答案 0 :(得分:2)
使用Gaps and Islands解决方案:
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
答案 1 :(得分:1)
使用Windowing Functions或the 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
现在,您可以使用此日期从每个租户中选择日期更大的所有记录:
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 强>
(感谢其他海报,为我节省了一些时间将模式放在一起。)
答案 2 :(得分:1)
通过Felix修复解决方案。我认为你不应该在第一个CTE中按area
进行分区。您应该在第二个CTE中按area
进行分区,而不是按它排序。
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
答案 3 :(得分: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