回答
菲利克斯修复解决方案。我认为你在第一次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
费利克斯的答案也会产生正确答案..你是怎么说你的更正确的。如何影响第一次CTE的面积? @Vladimir – rickyProgrammer
@rickyProgrammer,Felix的查询肯定会返回与我的变体不同的结果。正如我在评论中所说的,当你的数据具有'10'而不是'20'时,试着运行Felix查询。至于,你需要哪个结果,取决于你。如果您在样本中添加更多数据并且涵盖不同案例的预期结果,它将有助于包括您在内的所有人。 –
的使用差距及离岛的解决方案:
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
尝试将'area'的两个值从'20'更改为'10',您将看到查询不会返回您所期望的内容。 –
这是有道理的...我正在尝试你的@Vladimir – rickyProgrammer
溶液使用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
而现在您可以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
(感谢这里的其他海报以节省我一些时间把架构放在一起。)
当你在查询中通过'date'加入时,你认为每个房客只有一行最大日期,是吗? –
这是正确的,但迄今为止的所有迹象都表明,情况会如此。如果需要,我可以将这些JOIN转换为APPLY,以避免这种情况,但JOIN速度更快。 –
可以试试这个
//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
- 1. SQL SELECT查询
- 2. SQL SELECT查询
- 3. SQL Select查询
- 4. 基本的多对多sql select查询
- 5. 基于select的多个插入查询?
- 6. mysql的select查询得到基于
- 7. SQL查询基于计数
- 8. SQL查询,基于条件
- 9. SQL查询基于条件
- 10. SQL查询基于序列
- 11. SQL Select子查询
- 12. SELECT WHERE sql查询
- 13. 从SQL SELECT查询
- 14. Sql select count查询
- 15. SQL SELECT查询中
- 16. 用于select的SQL中的子查询
- 17. SQL SELECT查询问题
- 18. DB2 SQL SELECT基于加权
- 19. 带有列的SQL查询或查看取决于SELECT查询
- 20. SQL查询用SELECT和IF
- 21. 将SQL查询转换为Access查询 - SELECT内的SELECT
- 22. 结合sql select查询
- 23. Sql select查询性能
- 24. SQL查询使与内SELECT
- 25. 的Oracle SQL SELECT查询
- 26. SQL SELECT查询帮助
- 27. 问题与SQL SELECT查询
- 28. 基于子查询
- 29. DB2中的SQL SELECT查询
- 30. SQL SELECT查询帮助
'SELECT TOP 4 * FROM yourTable ORDER BY [日期] DESC'? –
它并不总是前4名,区域可能会相应改变,并可能与另一位房客再次有所不同。 – rickyProgrammer
如果OP想按日期升序排序,可以类似于Felix的评论,但是像这样'select * from(select * from(select * from table order by [date] desc)[date]' – zedfoxus