3

我认为这应该很容易,但我无法弄清楚。

以下是一些背景信息:

我有两张表,分别称为 Leases 和 UtilityBills。它们通过 UtilityBills 表中称为 LeaseID 的外键连接,该外键引用 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,但无法让它工作。谢谢!

4

5 回答 5

1

如果您希望两个日期在同一行,您可以使用 ROW_NUMBER() 函数。您不需要将表连接到自身,只需像这样使用 group by:

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() 将产生意想不到的结果。

于 2012-12-21T14:35:36.413 回答
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
于 2012-12-21T13:13:49.180 回答
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)
于 2012-12-21T14:31:47.810 回答
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
于 2012-12-21T13:10:49.763 回答
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

这适用于先验。要返回更长的时间,您需要更复杂的解决方案。. . 但这不是你的问题。

于 2012-12-21T14:30:52.863 回答