从列

时间:2016-05-03 09:43:47

标签: sql-server-2012 null pivot notnull

使用PIVOT

SELECT id, _TIMESTAMP, [Tag1], [Tag2], [Tag3], [Tag4], [Tag5], [Tag6]
FROM (SELECT id, _VALUE, _NAME, _TIMESTAMP
      FROM [dbo].[TableLogger]) AS SourceTable PIVOT (MAX(_VALUE) FOR _NAME IN ([Tag1], [Tag2], [Tag3], [Tag4], [Tag5], [Tag6])) AS PivotTable 

我的表看起来像这样:

id      _TIMESTAMP            Tag1  Tag2  Tag3  Tag4  Tag5  Tag6
1  2016-04-29 10:37:56.667    21    NULL  NULL  NULL  NULL  NULL
2  2016-04-29 10:37:56.667    NULL  0.2   NULL  NULL  NULL  NULL
3  2016-04-29 10:37:56.667    NULL  NULL  4     NULL  NULL  NULL  
4  2016-04-29 10:37:56.667    NULL  NULL  NULL  20    NULL  NULL  
5  2016-04-29 10:37:56.667    NULL  NULL  NULL  NULL  35    NULL  
6  2016-04-29 10:37:56.667    NULL  NULL  NULL  NULL  NULL  54
7  2016-04-29 10:37:58.667    32    NULL  NULL  NULL  NULL  NULL  

该表有30471行,可以获得更多。 SELECT语句的执行过多(如10s)。我尝试使用以下命令删除这些NULL值:

where  [Tag1] IS NOT NULL ;  

如果我想同时放置相同的条件,并且对于[Tag2]列,表格不再显示。我猜那些NULL值会影响SELECT执行的时间。有没有办法删除那些NULL值,以便我的SELECT语句执行得更快? 提前谢谢了!

修改

我希望看到我的表格:

id      _TIMESTAMP            Tag1  Tag2  Tag3  Tag4  Tag5  Tag6
1  2016-04-29 10:37:56.667    21    0.2    4     20    35    54
2  2016-04-29 10:37:58.667    32    25     65    32    30    13  

1 个答案:

答案 0 :(得分:0)

有时使用Case Expressions而不是Pivot可以获得更好的性能。要做一个真正的Pivot虽然你不能拥有不属于聚合的唯一字段(ID)或你得到那些空值

SELECT _TIMESTAMP,
       MAX(CASE WHEN _NAME = 'Tag1' THEN _VALUE END) AS Tag1,
       MAX(CASE WHEN _NAME = 'Tag2' THEN _VALUE END) AS Tag2,
       MAX(CASE WHEN _NAME = 'Tag3' THEN _VALUE END) AS Tag3,
       etc..
FROM   TableLogger
GROUP BY _TIMESTAMP

测试用例

DECLARE @TableLogger TABLE (id int, _TIMESTAMP datetime, _NAME varchar(MAX), _VALUE FLOAT)
INSERT INTO @TableLogger VALUES
(1, '2016-04-29 10:37:56.667', 'Tag1', 21),
(2, '2016-04-29 10:37:56.667', 'Tag2', 0.2),
(3, '2016-04-29 10:37:56.667', 'Tag3', 4),
(4, '2016-04-29 10:37:56.667', 'Tag4', 20),
(5, '2016-04-29 10:37:56.667', 'Tag5', 35),
(6, '2016-04-29 10:37:56.667', 'Tag6', 54),
(7, '2016-04-29 10:37:58.667', 'Tag1', 32),
(8, '2016-04-29 10:37:58.667', 'Tag2', 25),
(9, '2016-04-29 10:37:58.667', 'Tag3', 65),
(10, '2016-04-29 10:37:58.667', 'Tag4', 32),
(11, '2016-04-29 10:37:58.667', 'Tag5', 30),
(12, '2016-04-29 10:37:58.667', 'Tag6', 13)

-- CORRECT WAY TO PIVOT
SELECT  _TIMESTAMP,
        MAX(CASE WHEN _NAME = 'Tag1' THEN _VALUE END) AS Tag1,
        MAX(CASE WHEN _NAME = 'Tag2' THEN _VALUE END) AS Tag2,
        MAX(CASE WHEN _NAME = 'Tag3' THEN _VALUE END) AS Tag3,
        MAX(CASE WHEN _NAME = 'Tag4' THEN _VALUE END) AS Tag4,
        MAX(CASE WHEN _NAME = 'Tag5' THEN _VALUE END) AS Tag5,
        MAX(CASE WHEN _NAME = 'Tag6' THEN _VALUE END) AS Tag6
FROM    @TableLogger
GROUP BY _TIMESTAMP

-- INCORRECT WAY TO PIVOT
-- Including ID will cause each row to only have one value
SELECT  ID
        _TIMESTAMP,
        MAX(CASE WHEN _NAME = 'Tag1' THEN _VALUE END) AS Tag1,
        MAX(CASE WHEN _NAME = 'Tag2' THEN _VALUE END) AS Tag2,
        MAX(CASE WHEN _NAME = 'Tag3' THEN _VALUE END) AS Tag3,
        MAX(CASE WHEN _NAME = 'Tag4' THEN _VALUE END) AS Tag4,
        MAX(CASE WHEN _NAME = 'Tag5' THEN _VALUE END) AS Tag5,
        MAX(CASE WHEN _NAME = 'Tag6' THEN _VALUE END) AS Tag6
FROM    @TableLogger
GROUP BY ID, _TIMESTAMP

-- WAYS TO INCLUDE ROW NUMBER OR ID IN PIVOT
SELECT  ROW_NUMBER() OVER (ORDER BY _TIMESTAMP) AS [RowNumber],
        MIN(ID) [MinID],
        _TIMESTAMP,
        MAX(CASE WHEN _NAME = 'Tag1' THEN _VALUE END) AS Tag1,
        MAX(CASE WHEN _NAME = 'Tag2' THEN _VALUE END) AS Tag2,
        MAX(CASE WHEN _NAME = 'Tag3' THEN _VALUE END) AS Tag3,
        MAX(CASE WHEN _NAME = 'Tag4' THEN _VALUE END) AS Tag4,
        MAX(CASE WHEN _NAME = 'Tag5' THEN _VALUE END) AS Tag5,
        MAX(CASE WHEN _NAME = 'Tag6' THEN _VALUE END) AS Tag6
FROM    @TableLogger
GROUP BY _TIMESTAMP

-- A CORRECT PIVOT QUERY
SELECT * FROM
(
    SELECT  _TIMESTAMP, _NAME, _VALUE
    FROM    @TableLogger tl
) t
PIVOT
(
    MAX(_VALUE)
    FOR _NAME IN ([Tag1],[Tag2],[Tag3],[Tag4],[Tag5],[Tag6])
) pt

-- AN INCORRECT PIVOT QUERY
SELECT * FROM
(
    SELECT  ID, -- OOPS, included ID
            _TIMESTAMP, _NAME, _VALUE
    FROM    @TableLogger tl
) t
PIVOT
(
    MAX(_VALUE)
    FOR _NAME IN ([Tag1],[Tag2],[Tag3],[Tag4],[Tag5],[Tag6])
) pt

-- GIMME THOSE DARN ID's IN MA PIVOT
SELECT  ROW_NUMBER() OVER (ORDER BY _TIMESTAMP) AS [RowNumber], 
        *
FROM
(
    SELECT  MIN(ID) OVER (PARTITION BY _TIMESTAMP) [MinID], 
            _TIMESTAMP, _NAME, _VALUE
    FROM    @TableLogger tl
) t
PIVOT
(
    MAX(_VALUE)
    FOR _NAME IN ([Tag1],[Tag2],[Tag3],[Tag4],[Tag5],[Tag6])
) pt