1

我有一个具有以下数据结构的表:

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

经过一番谷歌搜索,看起来我应该专注于 pivot() 函数和交叉表查询。我正在阅读这两个,但仍然不太能得到

4

3 回答 3

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 |

在这里拉小提琴。

请注意,在您的示例中,您没有包含1在该[0-1]范围内,但您确实包含3在了该[0-3]范围内,这似乎不正确。

于 2013-10-28T23:41:28.740 回答
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

于 2013-10-29T00:08:29.097 回答
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
于 2013-10-29T00:09:43.913 回答