2012-12-21 92 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