[英]CrossTab Query / Pivot Table in MS SQL?
I have a table that has the follow data structure: 我有一个具有以下数据结构的表:
terminal | load_time_mns | vehicle
_________________________________________
Terminal 1 | 3 | AA
Terminal 2 | 10 | AF
Terminal 1 | 1 | BF
Terminal 6 | 3 | QRS
Terminal 6 | 1.4 | AA
Terminal 3 | 2.5 | OP
I am trying to get an interval breakdown of load time from each terminal.For example, for the above table, I am trying to create a breakdown that looks like the following: 我正在尝试从每个终端获取负载时间的间隔细分,例如,对于上表,我试图创建一个类似于以下内容的细分:
terminal | [0-1 mns] | [1-2 mns] | [2-3 mns] |
_______________________________________________________________
Terminal 1 | 0 | 1 | 1
_______________________________________________________________
Terminal 2 | 0 | 0 | 0
_______________________________________________________________
Terminal 3 | 0 | 0 | 1
_______________________________________________________________
Terminal 6 | 0 | 1 | 1
After a bit of Googling, it looks like I should be focusing on the pivot() function and crosstab queries. 经过一番谷歌搜索之后,看来我应该专注于pivot()函数和交叉表查询。 I am reading up on those two, but am still not quite able to get 我正在阅读这两个内容,但仍然不太能理解
Something like this might help: 这样的事情可能会有所帮助:
Query 1 : 查询1 :
SELECT
terminal,
count(CASE WHEN load_time_mns >= 0 AND load_time_mns < 1 THEN 1 END) [0-1 mns],
count(CASE WHEN load_time_mns >= 1 AND load_time_mns < 2 THEN 1 END) [1-2 mns],
count(CASE WHEN load_time_mns >= 2 AND load_time_mns < 3 THEN 1 END) [2-3 mns]
FROM t
GROUP BY terminal
Results : 结果 :
| TERMINAL | 0-1 MNS | 1-2 MNS | 2-3 MNS |
|------------|---------|---------|---------|
| Terminal 1 | 0 | 1 | 0 |
| Terminal 2 | 0 | 0 | 0 |
| Terminal 3 | 0 | 0 | 1 |
| Terminal 6 | 0 | 1 | 0 |
Note that in your example you did not include 1
in the [0-1]
range but you did include 3
in the [0-3]
range, which seems not right. 请注意,在您的示例中,您没有在[0-1]
范围内包含1
,但在[0-3]
范围内包含3
,这似乎不正确。
You can use a bit of dynamic SQL to extend this to the complete result set. 您可以使用一些动态SQL将其扩展到完整的结果集。 Create a table called intervals to store the intervals: 创建一个名为interval的表来存储间隔:
Create Table ex (
terminal varchar(10),
load_time_mns decimal(10, 2),
vehicle varchar(3)
);
Insert Into ex values
('Terminal 1', 3, 'AA'),
('Terminal 2', 10, 'AF'),
('Terminal 1', 1, 'BF'),
('Terminal 6', 3, 'QRS'),
('Terminal 6', 1.4, 'AA'),
('Terminal 3', 2.5, 'OP');
Create Table intervals (
min_mns decimal(10, 2),
max_mns decimal(10, 2),
column_name sysname
);
declare @i int = 0
while @i <= 20
begin
insert into intervals values (
@i, @i + 1, convert(varchar, @i) + '-' + convert(varchar, @i + 1)
);
set @i += 1;
end
while @i <= 420
begin
insert into intervals values (
@i, @i + 5, convert(varchar, @i) + '-' + convert(varchar, @i + 5)
);
set @i += 5;
end
You can then use a cursor to build up the complete SQL 然后,您可以使用游标建立完整的SQL
declare
@sql nvarchar(max) = N'select terminal',
@lo int, @hi int, @col sysname;
declare pivot_cursor cursor local fast_forward for
select
min_mns, max_mns, column_name
from
intervals
order by
min_mns;
open pivot_cursor;
fetch next from pivot_cursor into @lo, @hi, @col;
while @@fetch_status = 0
begin
set @sql += ', sum(case when load_time_mns >= ' + convert(varchar, @lo)
+ ' and load_time_mns < ' + convert(varchar, @hi)
+ ' then 1 else 0 end) as [' + @col + ']';
fetch next from pivot_cursor into @lo, @hi, @col;
end
close pivot_cursor;
deallocate pivot_cursor;
Set @sql += ' from ex group by Terminal order by terminal';
exec sp_executesql @sql;
DECLARE @t TABLE ( terminal VARCHAR(10), load_time_mns DECIMAL(5,2), vehicle VARCHAR(3))
INSERT INTO @t ( terminal, load_time_mns, vehicle )
VALUES
('Terminal 1' , 3 , 'AA'),
('Terminal 2' , 10 , 'AF'),
('Terminal 2' , 20 , 'AF'),
('Terminal 1' , 1 , 'BF'),
('Terminal 1' , 25 , 'BF'),
('Terminal 6' , 3 , 'QRS'),
('Terminal 6' , 1.4 , 'AA'),
('Terminal 3' , 2.5 , 'OP')
;WITH intervals AS
(
SELECT m = 0, n = 1
UNION ALL
SELECT CASE WHEN m < 20 THEN m+1 ELSE m+5 END, CASE WHEN n < 20 THEN n+1 ELSE n+5 END
FROM intervals
WHERE n<420
)
SELECT terminal, load_time_mns, vehicle,
interval = CAST(m AS VARCHAR(10)) + '-' + CAST(n AS VARCHAR(10)), m
INTO ##tmp
FROM intervals i
LEFT JOIN @t t
ON t.load_time_mns >= i.m
AND t.load_time_mns < i.n
OPTION (MAXRECURSION 0)
DECLARE @cols VARCHAR(MAX) =
STUFF(CAST((SELECT ',' + QUOTENAME(interval)
FROM (
SELECT DISTINCT interval, m
FROM ##tmp
) t
ORDER BY m
FOR XML PATH(''), TYPE
) AS VARCHAR(MAX)),1,1,'')
DECLARE @sql VARCHAR(MAX) = '
SELECT terminal, ' + @cols + '
FROM (
SELECT terminal, vehicle, interval
FROM ##tmp
) t
PIVOT (
COUNT(vehicle)
FOR interval IN (' + @cols + ')
) p
'
EXEC(@sql)
DROP TABLE ##tmp
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.