sql选择并比较最近和第n个最近的值,但是当值重复超过三个月时排除

时间:2013-08-09 16:05:47

标签: sql sql-server

我使用以下查询从按MeterNumber分组的表中选择最近和最近的第3个值。用户提供一个月和日,确定返回的最高值。

查询的目的是查看仪表的水读数,并查看它们在3个月内是否相同。如果是这样,就不会发生消耗,仪表可能会损坏。

我的问题是,我还想排除任何对第4,第5,第6,......最近阅读日期有相同读数的仪表,因为这些仪表很可能未被使用。

任何帮助将不胜感激!我对此非常陌生,所以也许有更有效/更好的方法来实现这一目标。

我正在使用MS SQL 2012。

SELECT 
MeterNumber, 
MAX(WaterRead) AS CurrentRead, 
MAX(ReadDate) AS CurrentReadDate, 
MIN(WaterRead) AS nthLastRead, 
MIN(ReadDate) AS nthLastReadDate
From
(SELECT MeterNumber, ReadDate, WaterRead
    FROM (
        SELECT MeterNumber, ReadDate, WaterRead, Rank() over (Partition BY MeterNumber ORDER BY ReadDate DESC ) AS myRank
    FROM WaterReads
) WaterReads WHERE myRank <= 3 ) a
Group By MeterNumber
Having MAX(WaterRead) - MIN(WaterRead) = 0 AND MAX(WaterRead) != 0 AND MIN(WaterRead) != 0     AND MIN(ReadDate) <> MAX(ReadDate)
AND MONTH(MAX(ReadDate)) = 6 AND DAY(MAX(ReadDate)) = 25
ORDER BY MeterNumber, CurrentReadDate

返回:

MeterNumber CurrentRead CurrentReadDate nthLastRead nthLastReadDate
80021139    12103       2013-06-25      12103   2013-04-24
80029512    5347        2013-06-25      5347    2013-04-24
80038245    304304      2013-06-25      304304  2013-04-24
80044119    46250       2013-06-25      46250   2013-04-24
80048357    6707        2013-06-25      6707    2013-04-24

1 个答案:

答案 0 :(得分:0)

你走在正确的轨道上。您可以使用max(大于......的情况)来抽取特定的前一个时段进行比较。像这样:

SELECT
    meternumber,
    MAX(CASE WHEN myrank = 1 THEN readdate ELSE NULL END) curr_date,
    MAX(CASE WHEN myrank = 1 THEN waterread ELSE NULL END) curr_read,
    MAX(CASE WHEN myrank = 4 THEN readdate ELSE NULL END) ago3_date,
    MAX(CASE WHEN myrank = 4 THEN waterread ELSE NULL END) ago3_read,
    MAX(CASE WHEN myrank = 7 THEN readdate ELSE NULL END) ago6_date,
    MAX(CASE WHEN myrank = 7 THEN waterread ELSE NULL END) ago6_read
FROM
(        
    SELECT  MeterNumber, 
            ReadDate, 
            WaterRead, 
            Rank() over (Partition BY MeterNumber ORDER BY ReadDate DESC ) AS myRank
      FROM  WaterReads
            WHERE   readdate <= '20130625'
) AS a
GROUP BY
    meternumber
HAVING
    MAX(CASE WHEN myrank = 1 THEN waterread ELSE NULL END) = MAX(CASE WHEN myrank = 4 THEN waterread ELSE NULL END) 
    AND MAX(CASE WHEN myrank = 1 THEN waterread ELSE NULL END) > MAX(CASE WHEN myrank = 7 THEN waterread ELSE NULL END) 
    AND MAX(CASE WHEN myrank = 4 THEN waterread ELSE NULL END) > 0

SQLFiddle here

或者,更容易阅读,但有一个额外的子查询:

SELECT
    meternumber,
    curr_date,
    curr_read,
    ago3_date,
    ago3_read,
    ago6_date,
    ago6_read
FROM    
(
    SELECT
        meternumber,
        MAX(CASE WHEN myrank = 1 THEN readdate ELSE NULL END) curr_date,
        MAX(CASE WHEN myrank = 1 THEN waterread ELSE NULL END) curr_read,
        MAX(CASE WHEN myrank = 4 THEN readdate ELSE NULL END) ago3_date,
        MAX(CASE WHEN myrank = 4 THEN waterread ELSE NULL END) ago3_read,
        MAX(CASE WHEN myrank = 7 THEN readdate ELSE NULL END) ago6_date,
        MAX(CASE WHEN myrank = 7 THEN waterread ELSE NULL END) ago6_read
    FROM
    (        
        SELECT  MeterNumber, 
                ReadDate, 
                WaterRead, 
                Rank() over (Partition BY MeterNumber ORDER BY ReadDate DESC ) AS myRank
          FROM  WaterReads
                WHERE   readdate <= '20130625'
    ) AS a
    GROUP BY
        meternumber
) AS b
WHERE
    curr_read = ago3_read
    AND curr_read > ago6_read
    AND ago3_read > 0