我正在尝试建立一个SQL查询,该查询将为我提供价格相同的日期的日期范围。如果价格出现突破,我希望能在新的一行看到它。即使一个月中的某个时间有相同的价格,但如果价格介于两者之间的某个时间有变化,我希望将其视为具有特定日期范围的两行。
样本数据:
Date Price
1-Jan 3.2
2-Jan 3.2
3-Jan 3.2
4-Jan 3.2
5-Jan 3.2
6-Jan 3.2
7-Jan 3.2
8-Jan 3.2
9-Jan 3.5
10-Jan 3.5
11-Jan 3.5
12-Jan 3.5
13-Jan 3.5
14-Jan 4.2
15-Jan 4.2
16-Jan 4.2
17-Jan 3.2
18-Jan 3.2
19-Jan 3.2
20-Jan 3.2
21-Jan 3.2
22-Jan 3
23-Jan 3
24-Jan 3
25-Jan 3
26-Jan 3
27-Jan 3
28-Jan 3
29-Jan 3.5
30-Jan 3.5
31-Jan 3.5
所需结果:
Price Date Range
3.2 1-8
3.5 9-13
4.2 14-16
3.2 17-22
3 22-28
3.5 29-31
最佳答案
非关系解决方案
我认为其他答案都不正确。GROUP BY
不起作用
使用ROW_NUMBER()
会强制将数据放入物理的“记录归档系统”结构中,然后将其作为物理记录进行处理。以巨大的性能代价。当然,为了编写这样的代码,它迫使您以RFS的方式来思考,而不是以关系的方式来思考。
使用CTE是相同的。遍历数据,尤其是不变的数据。费用略有不同。
出于不同的原因,游标肯定是错误的事情。 (a)游标需要代码,并且您已请求一个视图(b)游标放弃了集处理引擎,并恢复为逐行处理。同样,不是必需的。如果我的任何团队中的开发人员都在关系数据库(即非记录归档系统)上使用了游标或临时表,那么我会射击它们。
关系解决方案
您的数据是关系型的,逻辑的,两个给定的数据列就足够了。
当然,我们必须形成一个View(派生关系)以获得所需的报告,但是它由纯SELECT组成,这与处理(将其转换为物理文件然后处理该文件)完全不同。临时表;或工作表;或CTE;或ROW_Number();等)。
与有一个议程的“理论家”的哀叹相反,SQL可以很好地处理关系数据。而您的数据就是关系型的。
因此,请保持“关系”心态,数据的“关系”视图和集合处理心态。可以使用单个SELECT来满足关系数据库上的每个报告要求。无需退回1970年以前的ISAM文件处理方法。
我将假设主键(提供关系行唯一性的列集)为Date,
,根据给出的示例数据,数据类型为DATE.
试试这个:
CREATE VIEW MyTable_Base_V -- Foundation View
AS
SELECT Date,
Date_Next,
Price
FROM (
-- Derived Table: project rows with what we need
SELECT Date,
[Date_Next] = DATEADD( DD, 1, O.Date ),
Price,
[Price_Next] = (
SELECT Price -- NULL if not exists
FROM MyTable
WHERE Date = DATEADD( DD, 1, O.Date )
)
FROM MyTable MT
) AS X
WHERE Price != Price_Next -- exclude unchanging rows
GO
CREATE VIEW MyTable_V -- Requested View
AS
SELECT [Date_From] = (
-- Date of the previous row
SELECT MAX( Date_Next ) -- previous row
FROM MyTable_V
WHERE Date_Next < MT.Date
),
[Date_To] = Date, -- this row
Price
FROM MyTable_Base_V MT
GO
SELECT *
FROM MyTable_V
GO
通用方法
当然,这是一种方法,因此它是通用的,它可用于根据任何数据更改(此处为更改)来确定任何数据范围(此处为
From_
范围)的To_
和Date
在Price
中)。在这里,您的
Dates
是连续的,因此Date_Next
的确定很简单:将Date
增加1天。如果PK在增加但不连续(例如DateTime
或TimeStamp
或其他某个键),请将派生表X
更改为: -- Derived Table: project rows with what we need
SELECT DateTime,
[DateTime_Next] = (
-- first row > this row
SELECT TOP 1
DateTime -- NULL if not exists
FROM MyTable
WHERE DateTime > MT.DateTime
),
Price,
[Price_Next] = (
-- first row > this row
SELECT TOP 1
Price -- NULL if not exists
FROM MyTable
WHERE DateTime > MT.DateTime
)
FROM MyTable MT
请享用。
请随时发表评论,提出问题等。
关于sql - 同一数据集的日期范围,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30455227/