2015-10-16 99 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