2017-03-27 89 views
1

我想知道如何排除某个值的所有数据点。 (我在这个问题的底部提供了查询)SQL,如果其中一个标记值被忽略,则忽略所有值

例子。 这是我的当前表中的数据(该标志可以接受更多的大于2倍的值(N,P和A))

RevisionID   DateTime   Value Flag 
21026  2017-01-01 06:00:00.000 224.4 N 
21026  2017-01-01 07:00:00.000 476.8 P 
21026  2017-01-01 08:00:00.000 588.6 N 
21027  2017-01-01 07:00:00.000 138.4 N 
21027  2017-01-01 08:00:00.000 683.6 N 

上面的数据将被展平,通过最高版本对于给定的日期时间(我可以用提供的查询来做到这一点)。

结果会是这样

RevisionID   DateTime   Value Flag 
21026  2017-01-01 06:00:00.000 224.4 N 
21027  2017-01-01 07:00:00.000 138.4 N 
21027  2017-01-01 08:00:00.000 683.6 N 

,但我想做的事,如果其中任何一个有标志P的数据点,所有相关的日期时间应不显示

目前第2行包含标志P

21026  2017-01-01 07:00:00.000 476.8 P 

我想最后的结果看起来像这样

低于210
RevisionID   DateTime   Value Flag 
21026  2017-01-01 06:00:00.000 224.4 N 
21027  2017-01-01 08:00:00.000 683.6 N 

都提供了将扁平化数据查询,现在我要排除所有的数据点,即使其中一个被标记为P

CREATE TABLE #data (RevisionID INT, _datetime DATETIME, _value FLOAT, flag CHAR) 
    INSERT INTO #data VALUES 
    (21026,'2017-01-01 06:00:00.000',224.4,'N'), 
    (21026,'2017-01-01 07:00:00.000',476.8,'P'), 
    (21026,'2017-01-01 08:00:00.000',588.6,'N'), 
    (21027,'2017-01-01 07:00:00.000',138.4,'N'), 
    (21027,'2017-01-01 08:00:00.000',683.6,'N') 

    WITH RNData AS 
    (
     SELECT d.RevisionID, d._datetime, d._value, d.flag, ROW_NUMBER() 
     OVER (PARTITION BY d._datetime ORDER BY d._datetime, d.RevisionID DESC) AS rn 
        FROM #data d 
    )select * from RNData where rn = 1 

回答

3

您可以使用窗口函数对于这个问题,以及:

WITH d AS (
     SELECT d.RevisionID, d._datetime, d._value, d.flag, 
      ROW_NUMBER() OVER (PARTITION BY d._datetime ORDER BY d.RevisionID DESC) AS seqnum, 
      SUM(CASE WHEN d.flag = 'P' THEN 1 ELSE 0 END) OVER (PARTITION BY d._datetime) as cnt_P 
     FROM #data d 
    ) 
SELECT d.* 
FROM d 
WHERE seqnum = 1 AND cnt_P = 0; 

请注意,您不应该重复ORDER BY中的分区键。

如果标志只需要对'N''P'的值,那么你可以使用一个小捷径:

WITH d AS (
     SELECT d.RevisionID, d._datetime, d._value, d.flag, 
      ROW_NUMBER() OVER (PARTITION BY d._datetime ORDER BY d.RevisionID DESC) AS seqnum, 
      MAX(d.flag) OVER (PARTITION BY d._datetime) as max_flag 
     FROM #data d 
    ) 
SELECT d.* 
FROM d 
WHERE seqnum = 1 AND max_flag = 'P'; 
+0

嗨,感谢您的答复。是国旗可以采取超过2个值(我更新了我的问题)对不起有关丢失信息 –

+0

@Gordon Linoff你的查询都参考列rn。我认为你的意思是seqnum?另外,第二个查询不会是<>'P'而不是='P'? –

+0

@ChrisAlbert。 。 。谢谢。 –

0

使用CASE表达式(条件聚合):

WITH RNData AS 
(
    SELECT 
    d.RevisionID, d._datetime, d._value, d.flag, 
    ROW_NUMBER() OVER (PARTITION BY d._datetime ORDER BY d._datetime, d.RevisionID DESC) AS rn, 
    MAX(CASE WHEN flag = 'P' THEN 1 ELSE 0 END) OVER (PARTITION BY d._datetime) AS flagged_p 
    FROM #data d 
) 
select * 
from RNData 
where rn = 1 
and flagged_p = 0; 
+0

谢谢,这也适用,但解决方案是缺少一个,后.... DESC)AS rn –

+0

正确;感谢您发现这一点。我添加了缺失的逗号。 –

0

另一种方法

select * 
from 
(SELECT d.RevisionID, d._datetime, d._value, d.flag 
     , ROW_NUMBER() OVER (PARTITION BY d._datetime ORDER BY d.RevisionID DESC) AS rn 
     FROM #data d 
     WHERE NOT EXISTS (SELECT 1 FROM #data p WHERE d._datetime = p._datetime and p.flag = 'P') 
     AND d.flag <> 'P' 
) tt 
where tt.rn = 1 

AND d.flag <> 'P'不是必需的,而是可能使其更有效