2012-12-21 90 views
3

我认为这应该很容易,但我无法弄清楚。SQL Server:在单个查询中结合最大结果和第二大结果

下面是一些背景资料:

我有两个表,称为租赁和UtilityBills。他们通过名为LeaseID的外键连接在UtilityBills表中,该表引用了Leases表中的主键(也称为LeaseID)。

所以这非常简单 - 我为每个租赁记录每月的电表读数。

在UtilityBills表中,我有一个名为MeterReadingDate的字段,它用于存储每次读取仪表读数的日期。

这里是我的问题:

如何创建一个查询,这将给我,为每个租赁,双方最近一次抄表日期,和之前的抄表日期?

我能够获得最新的抄表每个租赁很轻松了,使用这个SQL语句:

SELECT LeaseID, MAX(MeterReadingDate) AS MostRecentMeterReadingDate 
FROM dbo.UtilityBills 
GROUP BY LeaseID 

我也能得到之前抄表对于任何给定的租赁,使用该SQL声明(例如,这给了我与LeaseID租赁之前抄表= 228):

SELECT TOP 1 MeterReadingDate, LeaseID 
FROM (SELECT TOP 2 MeterReadingDate, LeaseID 
       FROM dbo.UtilityBills 
       WHERE (LeaseID = 228) 
       ORDER BY MeterReadingDate DESC) DERIVEDTBL 
ORDER BY MeterReadingDate 

我想不通,是如何将这两个语句结合生成一个查询,列出第二 - 最近的和最近的抄表日期,所有租约。据我所知,我需要在这种情况下使用CROSS APPLY,但无法使其工作。谢谢!

回答

0

如果我理解正确,我认为您需要从每个LeaseID获取最近的2个读数。为此,

SELECT LeaseID, MeterReadingDate 
FROM (
    SELECT LeaseID, MeterReadingDate, 
      Rank() Over (Partition by LeaseID Order by MeterReadingDate desc) rk 
    FROM dbo.UtilityBills 
) A 
WHERE rk <3 
ORDER BY MeterReadingDate desc 
+0

这将返回两个单独的行而不是一行 –

+0

@rs:他说他需要他们在两列? – Kaf

+0

从他的问题,我认为他希望在一行OP表示 - “如何结合这两个语句产生一个查询,列出所有租约第二最近和最近的抄表日期。”# –

0

试试这个

;WITh CTE AS 
(
    SELECT LEASEID, MeterReadingDate, ROW_NUMBER() OVER 
         (PARTITION BY LEASEID 
         ORDER BY MeterReadingDate DESC) RN 
    FROM dbo.UtilityBills 
) 
SELECT x1.LEASEID, x1.MeterReadingDate CurrentDate, 
x2.MeterReadingDate PreviousDate 
FROM CTE x1 
LEFT OUTER JOIN CTE X2 ON x1.leaseid = x2.leaseid AND x1.rn + 1 = x2.rn 
WHERE X1.rn = 1 
0

为您的特定问题,可以通过包括group by组合查询。这里是一个例子:

SELECT LeaseID, MIN(MeterReadingDate) as PriorReading, MAX(MeterReadingDate) as LatestReading 
FROM (SELECT TOP 2 MeterReadingDate, LeaseID 
     FROM dbo.UtilityBills 
     WHERE (LeaseID = 228) 
     ORDER BY MeterReadingDate DESC 
     ) DERIVEDTBL 
group by leaseid 
ORDER BY MeterReadingDate 

这适用于以前。为了延长使用时间,您需要更复杂的解决方案。 。 。但那不是你的问题。

0

试试这个:

SELECT  
    ls.Id as 'leaseId', 
    ub.MeterReadingDate as 'MeterDate' 
FROM Leases ls 
    left outer join UtilityBills ub on ls.Id = ub.LeaseID 
    left outer join UtilityBills ub2 on ub2.LeaseID=ls.Id 
            and ub2.MeterReadingDate > ub.MeterReadingDate 
    left outer join UtilityBills ub3 on ub3.LeaseID=ls.Id 
            and ub3.MeterReadingDate > ub.MeterReadingDate 
            and ub3.MeterReadingDate < ub2.MeterReadingDate 
    left outer join UtilityBills ub4 on ub4.LeaseID=ls.Id 
            and ub3.Id is null 
            and ub4.MeterReadingDate > ub2.MeterReadingDate 
WHERE ub2.Id is null 
    or (ub3.Id is null and ub4.Id is null) 
1

如果你想在同一行中的两个日期,你可以使用ROW_NUMBER()函数。你不需要加入表本身,只是像这样使用一组:

IF OBJECT_ID('dbo.UtilityBills') IS NOT NULL DROP TABLE dbo.UtilityBills; 

CREATE TABLE dbo.UtilityBills(
Id INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, 
LeaseId INT, 
MeterReadingDate DATE 
); 

INSERT INTO dbo.UtilityBills(LeaseId,MeterReadingDate)VALUES 
    (1,'2012-01-01'), 
    (1,'2012-02-01'), 
    (1,'2012-03-01'), 
    (1,'2012-04-01'), 
    (2,'2012-01-02'), 
    (2,'2012-03-02'), 
    (2,'2012-05-02'), 
    (3,'2012-08-03'), 
    (3,'2012-10-03'), 
    (4,'2012-05-04'); 

SELECT LeaseId, 
MAX(CASE WHEN rn = 1 THEN MeterReadingDate END) MostRecentReadingDate, 
MAX(CASE WHEN rn = 2 THEN MeterReadingDate END) PreviousReadingDate 
FROM(
SELECT LeaseID, 
     MeterReadingDate, 
     ROW_NUMBER() OVER (PARTITION BY LeaseId ORDER BY MeterReadingDate DESC) rn 
FROM dbo.UtilityBills 
)AS U 
WHERE rn <=2 
GROUP BY LeaseId; 

这里有一些其他的答案提示)的RANK()函数而不是ROW_NUMBER(。但是,如果最后两次读数在同一天发生,RANK()会产生意想不到的结果。

+0

user1349242似乎已经沉默,但这是最好的解决方案。 – DeanGC

+0

你在哪个版本的SQL Server上?什么SP? (运行“SELECT @@ VERSION;”并发布结果。) –

+0

感谢您的详细回复!事实证明,我正在使用SQLServer 2000,我认为它不支持ROW_NUMBER()。是否有任何你知道的解决方法?或者也许这只是升级的时间......具体来说,Microsoft SQL Server 2000 - 8.00.2305(Build 3790:Service Pack 2) – korby