2015-10-16 93 views
1

的最新值在表中選擇行我有這個表樣品SQL SELECT查詢 - 基於

enter image description here

我需要基於這樣就會產生這個最新的日期,只選擇最新的面積值一種輸出

enter image description here

+0

'SELECT TOP 4 * FROM yourTable ORDER BY [日期] DESC'? –

+0

它並不總是前4名,區域可能會相應改變,並可能與另一位房客再次有所不同。 – rickyProgrammer

+0

如果OP想按日期升序排序,可以類似於Felix的評論,但是像這樣'select * from(select * from(select * from table order by [date] desc)[date]' – zedfoxus

回答

1

菲利克斯修復解決方案。我認爲你在第一次CTE中不應該被area分區。你應該在第二個CTE中劃分area,而不是按它排序。

SQL Fiddle

WITH 
CTE1 
AS 
(
    SELECT *, 
     ROW_NUMBER() OVER(PARTITION BY tenant ORDER BY date desc) AS rn 
    FROM yourTable 
) 
,CTE2 
AS 
(
    SELECT 
    * 
    ,rn - ROW_NUMBER() OVER (PARTITION BY tenant, area ORDER BY rn) AS rnk 
    FROM CTE1 
) 
SELECT 
    tenant 
    ,area 
    ,date 
    ,sales 
FROM CTE2 
WHERE rnk = 0 
ORDER BY tenant, date desc 
+0

費利克斯的答案也會產生正確答案..你是怎麼說你的更正確的。如何影響第一次CTE的面積? @Vladimir – rickyProgrammer

+0

@rickyProgrammer,Felix的查詢肯定會返回與我的變體不同的結果。正如我在評論中所說的,當你的數據具有'10'而不是'20'時,試着運行Felix查詢。至於,你需要哪個結果,取決於你。如果您在樣本中添加更多數據並且涵蓋不同案例的預期結果,它將有助於包括您在內的所有人。 –

2

的使用差距及離島的解決方案:

SQL Fiddle

WITH CteIslands AS(
    SELECT *, 
     grp = DATEADD(DAY, -ROW_NUMBER() OVER(PARTITION BY tenant, area ORDER BY date), date) 
    FROM yourTable 
), 
Cte AS(
    SELECT *, 
     rnk = RANK() OVER(PARTITION BY tenant ORDER BY grp DESC, area) 
    FROM CteIslands 
) 
SELECT tenant, area, date, sales 
FROM Cte WHERE rnk = 1 
+0

嘗試將'area'的兩個值從'20'更改爲'10',您將看到查詢不會返回您所期望的內容。 –

+0

這是有道理的...我正在嘗試你的@Vladimir – rickyProgrammer

1

溶液使用Windowing Functionsthe APPLY operator可能會更簡單,更高效的執行,但有些人使用這些有困難的時候,我懷疑最好的結果會利用LAG/LEAD,這是的在Sql Server 2008中不可用。因此,我提供了一個純粹基於JOIN和GROUP BY的解決方案。

首先你需要知道最近的每個租戶的日期:

SELECT tenant, MAX(date) date 
FROM sample s1 
GROUP BY s1.tenant 

你可以用它來找到該行的area值:

SELECT tenant, area, date 
FROM sample s 
INNER JOIN (
    SELECT tenant, MAX(date) date 
    FROM sample s1 
    GROUP BY s1.tenant 
) t on t.tenant = s.tenant and t.date = s.date 

現在你可以用它來找到不具有相同區域的最近日期:

SELECT s3.tenant, MAX(date) date 
FROM sample s3 
INNER JOIN (
    SELECT tenant, area, date 
    FROM sample s2 
    INNER JOIN (
     SELECT tenant, MAX(date) date 
     FROM sample s1 
     GROUP BY s1.tenant 
    ) j1 on j1.tenant = s.tenant and j1.date = s.date 
) j2 on j2.tenant = s3.tenant and j2.area <> s3.area 
GROUP BY s3.tenant 

而現在您可以n使用此日期從與其中的日期爲每個租戶選擇的所有記錄更大:

SELECT s4.* 
FROM sample s4 
INNER JOIN (
    SELECT s3.tenant, MAX(date) date 
    FROM sample s3 
    INNER JOIN (
     SELECT tenant, area 
     FROM sample s2 
     INNER JOIN (
      SELECT tenant, MAX(date) date 
      FROM sample s1 
      GROUP BY s1.tenant 
     ) j1 on j1.tenant = s.tenant and j1.date = s.date 
    ) j2 on j2.tenant = s3.tenant and j2.area <> s3.area 
    GROUP BY s3.tenant 
) j3 on j3.tenant = s4.tenant and s4.date > j4.date 

值得注意聽到我可以在嵌套的聯接重新使用表的別名,但我經常發現它如果我保持它們的獨特性,在編寫查詢時更容易跟蹤事物。您還可以通過移動嵌套查詢出來的CTE提高可讀性,這將有助於保持合理的流動,我提出:

-- Most recent date for each tenant 
WITH LatestDates AS 
(
    SELECT tenant, MAX(date) date 
    FROM sample 
    GROUP BY tenant 
), 
-- the area for each tenant on that date 
LatestAreas AS 
(
    SELECT tenant, area 
    FROM sample s 
    INNER JOIN LatestDates l on l.tenant = s.tenant and l.date = s.date 
), 
-- the most recent date for each tenant where the area is different 
LatestDateWithChangedArea AS 
(
    SELECT s.tenant, MAX(date) date 
    FROM sample s 
    INNER JOIN LatestAreas l on l.tenant = s.tenant and l.area <> s.area 
    GROUP BY s.tenant 
) 
-- all records for each tenant where the date is greater than that 
SELECT s.* 
FROM sample s 
INNER JOIN LatestDateWithChangedArea l ON s.tenant = l.tenat and s.date > l.date 

正如我前面提到的,我們可以使用APPLY運營商進一步簡化這一點:

WITH LatestDates AS 
(
    SELECT tenant, MAX(date) date 
    FROM sample 
    GROUP BY tenant 
) 
SELECT s3.* 
FROM LatestDates l 
INNER JOIN sample s ON s.tenant = l.tenant and s.date = l.date 
OUTER APPLY (
    SELECT TOP 1 tenant, date 
    FROM sample s2 
    WHERE s2.tenant = s.tenant and s2.area<>s.area 
    ORDER BY s2.tenant, s2.date desc 
) a 
INNER JOIN sample s3 ON s3.tenant = a.tenant and s3.date > a.date 

SQL Fiddle

(感謝這裏的其他海報以節省我一些時間把架構放在一起。)

+0

當你在查詢中通過'date'加入時,你認爲每個房客只有一行最大日期,是嗎? –

+0

這是正確的,但迄今爲止的所有跡象都表明,情況會如此。如果需要,我可以將這些JOIN轉換爲APPLY,以避免這種情況,但JOIN速度更快。 –

1

可以試試這個

 
//get latest date record for the tenant 
WITH LatestData AS 
    (SELECT tenant, area, date 
    FROM tenant_table as a 
    WHERE DATE = (SELECT MAX(date) FROM tenant_table as b 
        WHERE a.tenant = b.tenant) 
    ), 
//get latest date record for the tenant with area not the latest area 
    LatestDateWithAreaChanged AS 
    (SELECT tenant, max(date) 
    FROM tenant_table as c INNER JOIN LatestData as D 
          ON c.tenant = D.tenant and c.area d.area 
    GROUP BY tenant) 
//get all data where date is after the last area changed  
SELECT X.* FROM tenant_table as X 
INNER JOIN LatestDateWithAreaChanged as Y 
ON X.tenat = Y.tenant AND X.date > Y.date