SQL,如果标记了其中一个值,则忽略所有值

时间:2017-03-27 11:47:51

标签: sql tsql

我想知道如果它们中的任何一个具有某个标志值,如何排除某个值的所有数据点。 (我在这个问题的底部提供了查询)

例子。 这是我表中的当前数据(该标志可以采用超过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 

我希望最终结果看起来像这样

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 个答案:

答案 0 :(得分: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';

答案 1 :(得分: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;

答案 2 :(得分: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'不是必需的,但可能会提高效率