【问题标题】:Remove NULL values from columns从列中删除 NULL 值
【发布时间】:2016-08-28 07:11:03
【问题描述】:

使用 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 空 空 空 空 空 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 空 空 空 空 空 空

该表有 30471 行,可以得到更多。 SELECT 语句的执行耗时过长(如 10 秒)。我尝试使用以下方法删除那些 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

【问题讨论】:

  • 如果您尝试按时间戳进行汇总,您需要从您正在旋转的子查询和主 Select 语句中删除 id

标签: sql-server-2012 null pivot notnull


【解决方案1】:

有时使用案例表达式而不是数据透视可以获得更好的性能。要进行真正的 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

【讨论】:

  • 它可以满足我的要求,但问题是并非所有值都被采用。我的意思是我只得到 5120 行,而不是 30471 行。知道为什么会这样吗? :)
  • 我能做些什么来解决这个问题吗?
  • @magn 可以更好地了解您在这里要完成的工作。您已经向我们展示了您从查询中获得的结果,但您没有向我们展示您期望的结果。
  • @magn 您的预期结果与此答案产生的结果有何不同?
  • 去掉 NULL 值。
猜你喜欢
  • 1970-01-01
  • 2014-12-19
  • 2013-08-09
  • 2016-01-05
  • 1970-01-01
  • 2017-10-12
  • 2011-08-08
  • 1970-01-01
相关资源
最近更新 更多