2013-10-28 30 views
1

我有了后续数据结构的表格:MS SQL中的CrossTab查询/数据透视表?

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 

我试图获得的来自每个terminal.For例如负载时间间隔击穿,对于上面的表中,我试图创建一个击穿看起来像以下:

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   

有点谷歌搜索后,它看起来像我应该集中在枢轴()函数和交叉表查询。我读了关于这两个,但我还是不太能得到

+1

是你的最终格式?只有三个区间? –

+0

不,我会每隔1分钟到20分钟,然后每隔5分钟从20分钟到7小时。 –

回答

2

像这样的东西可能会有所帮助:

查询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 

结果

| 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 | 

小提琴here

注意,在你的榜样,你没有包括在[0-1]范围1但你在[0-3]范围内,这似乎也不对确实包括3

+1

谢谢!这正是我需要的。你说得对;我以我的例子滑倒了。 –

+0

@BadProgrammer:那么你的声明是“你将会每隔1分钟到20分钟,然后每隔5分钟从20分钟到7小时*”?你需要多少'CASE'行? –

0

您可以使用一点动态SQL将其扩展到完整的结果集。创建一个表名为间隔存储间隔:

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 

然后,您可以使用游标来建立完整的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; 

Example SQLFiddle

0
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