jus*_*tus 5 sql t-sql sql-server-2012
我真的希望你们中的一些人喜欢挑战.我有一个产品ID,价格和日期范围的表格,当这些价格活跃时.
+----+-------+---------------------+---------------------+
| Id | Price | StartDate | EndDate |
+----+-------+---------------------+---------------------+
| 1 | 19 | 2016-12-01 00:00:00 | 2017-12-01 23:59:59 |
| 1 | 18 | 2017-01-01 00:00:00 | 2018-01-12 23:59:59 |
| 1 | 17 | 2017-02-03 00:00:00 | 2017-03-03 23:59:59 |
| 1 | 16 | 2018-01-01 00:00:00 | 2018-03-02 23:59:59 |
| 2 | 15 | 2017-01-01 00:00:00 | 2017-03-05 23:59:59 |
| 2 | 15 | 2017-03-06 00:00:00 | 2017-03-31 23:59:59 |
| 2 | 30 | 2017-04-01 00:00:00 | 2017-05-03 23:59:59 |
| 3 | 12 | 2017-01-01 00:00:00 | 2017-01-31 23:59:59 |
| 3 | 12 | 2017-02-01 00:00:00 | 2017-02-28 23:59:59 |
| 4 | 14 | 2017-01-01 00:00:00 | 2017-04-05 23:59:59 |
| 4 | 14 | 2017-04-01 00:00:00 | 2017-04-30 23:59:59 |
| 4 | 12 | 2017-04-15 00:00:00 | 2017-05-30 23:59:59 |
| 5 | 20 | 2017-01-01 00:00:00 | 2017-01-31 23:59:59 |
| 5 | 20 | 2017-03-01 00:00:00 | 2017-03-31 23:59:59 |
| 6 | 15 | 2017-01-01 00:00:00 | 2017-01-31 23:59:59 |
| 6 | 15 | 2017-02-01 00:00:00 | 2017-02-28 23:59:59 |
| 6 | 15 | 2017-04-01 00:00:00 | 2017-04-30 23:59:59 |
+----+-------+---------------------+---------------------+
Run Code Online (Sandbox Code Playgroud)
SQLFiddle:http://sqlfiddle.com/#!6/39288/1
我需要以下列格式获取它:
日期与"触摸"(即Id#3)合并为一个期间的ID和价格相同.
重叠的日期(即Id#4)合并为一个期间.
显示每种产品的最低价格以及在什么范围内.
具有间隙和相同价格的日期范围不合并并且是单独的行(即Id#5).
结果应该是:
+----+-------+---------------------+---------------------+
| Id | Price | StartDate | EndDate |
+----+-------+---------------------+---------------------+
| 1 | 19 | 2016-12-01 00:00:00 | 2016-12-31 23:59:59 |
| 1 | 18 | 2017-01-01 00:00:00 | 2017-02-02 23:59:59 |
| 1 | 17 | 2017-02-03 00:00:00 | 2017-03-03 23:59:59 |
| 1 | 19 | 2017-03-04 00:00:00 | 2017-12-01 23:59:59 |
| 1 | 18 | 2017-12-02 00:00:00 | 2017-12-31 23:59:59 |
| 1 | 16 | 2018-01-01 00:00:00 | 2018-03-02 23:59:59 |
| 2 | 15 | 2017-01-01 00:00:00 | 2017-03-31 23:59:59 |
| 2 | 30 | 2017-04-01 00:00:00 | 2017-05-03 23:59:59 |
| 3 | 12 | 2017-01-01 00:00:00 | 2017-02-28 23:59:59 |
| 4 | 14 | 2017-01-01 00:00:00 | 2017-04-14 23:59:59 |
| 4 | 12 | 2017-04-15 00:00:00 | 2017-05-30 23:59:59 |
| 5 | 20 | 2017-01-01 00:00:00 | 2017-01-31 23:59:59 |
| 5 | 20 | 2017-03-01 00:00:00 | 2017-03-31 23:59:59 |
| 6 | 15 | 2017-01-01 00:00:00 | 2017-02-28 23:59:59 |
| 6 | 15 | 2017-04-01 00:00:00 | 2017-04-30 23:59:59 |
+----+-------+---------------------+---------------------+
Run Code Online (Sandbox Code Playgroud)
总的来说,它基本上决定了两个日期之间的最佳价格.
我过去曾使用过这个表,并且能够用C#解决它,但这次我需要一个纯粹的TSQL方法.
我已经放下了一些深度嵌套的CTE并且失去了理智,因为得到的结果远不及它们应该是什么.提前感谢能够提供帮助的任何人.
编辑:我甚至搞砸了想要的结果,因为这太令人困惑了.固定(我认为).
编辑2:示例:
+------+-------+-------------------------+-------------------------+
| Id | Price | StartDate | EndDate |
+------+-------+-------------------------+-------------------------+
| 8611 | 31.98 | 2017-06-06 00:00:00.000 | 2017-09-24 23:59:59.000 |
| 8611 | 31.98 | 2017-09-25 00:00:00.000 | 2017-12-31 23:59:59.000 |
| 8611 | 28.78 | 2017-07-31 00:00:00.000 | 2017-09-30 23:59:59.000 |
| 8611 | 28.78 | 2017-10-30 00:00:00.000 | 2017-12-31 23:59:59.000 |
+------+-------+-------------------------+-------------------------+
Run Code Online (Sandbox Code Playgroud)
@ GordonLinoff的结果是:
+------+-------+-------------------------+-------------------------+
| Id | Price | StartDate | EndDate |
+------+-------+-------------------------+-------------------------+
| 8611 | 28.78 | 2017-06-06 00:00:00.000 | 2017-12-31 23:59:59.000 |
+------+-------+-------------------------+-------------------------+
Run Code Online (Sandbox Code Playgroud)
结果应该是:
+------+-------+-------------------------+-------------------------+
| Id | Price | StartDate | EndDate |
+------+-------+-------------------------+-------------------------+
| 8611 | 31.98 | 2017-06-06 00:00:00.000 | 2017-07-30 23:59:59.000 |
| 8611 | 28.78 | 2017-07-31 00:00:00.000 | 2017-09-30 23:59:59.000 |
| 8611 | 31.98 | 2017-10-01 00:00:00.000 | 2017-10-29 23:59:59.000 |
| 8611 | 28.78 | 2017-10-30 00:00:00.000 | 2017-12-31 23:59:59.000 |
+------+-------+-------------------------+-------------------------+
Run Code Online (Sandbox Code Playgroud)
您有可用的日历/日期表吗?如果是这样,那么您可以使用日期表来帮助您获取表中期间内每个日期的每种产品的最低价格。
之后,您可以通过查看具有相同产品 ID 的下一条和上一条记录来获取每个周期的开始日期和结束日期。您可以使用 LAG 和 LEAD 函数来执行此操作。这为您提供了每个所需组的外部边界。
从那里开始,只需进行一些摆弄即可获得最终结果。我在下面提供了一个示例,它应该可以为您提供所需的结果。
--Get the best price per date for each product
WITH BestPricePerDate AS (
SELECT
Id,
MIN(Price) Price,
c.[Date]
FROM [YourTable] yt
INNER JOIN dbo.Calendar c
ON c.[Date] BETWEEN yt.StartDate AND yt.EndDate
GROUP BY Id, [Date]
),
--Check whether the date is the start or the end of a period
PeriodsMarkedPerId AS(
SELECT
Id,
Price,
[Date],
CASE WHEN
ISNULL(LAG(Price,1) OVER (PARTITION BY Id ORDER BY [Date]),-1) <> Price
OR ISNULL(LAG([Date],1) OVER (PARTITION BY Id ORDER BY [Date]),'1999-01-01') <> DATEADD(DAY,-1,[Date]) THEN 1 ELSE 0 END IsStartDate,
CASE WHEN
ISNULL(LEAD(Price,1) OVER (PARTITION BY Id ORDER BY [Date]),-1) <> Price
OR ISNULL(LEAD([Date],1) OVER (PARTITION BY Id ORDER BY [Date]),'1999-01-01') <> DATEADD(DAY,1,[Date]) THEN 1 ELSE 0 END IsEndDate
FROM BestPricePerDate
),
--Keep only the start and end date records
PeriodStartAndEndDates AS(
SELECT
Id,
Price,
[Date],
IsStartDate,
IsEndDate
FROM PeriodsMarkedPerId
WHERE IsStartDate = 1 OR IsEndDate = 1
),
--Move StartDate and EndDate to one record
StartAndEndDatesOnSameRow AS(
SELECT
Id,
Price,
[Date] AS StartDate,
LEAD([Date],1) OVER (ORDER BY Id, [Date]) AS EndDate,
IsStartDate
FROM PeriodStartAndEndDates
)
--Get the resulting periods
SELECT Id, Price, StartDate, EndDate
FROM StartAndEndDatesOnSameRow
WHERE IsStartDate = 1
ORDER BY Id, StartDate
Run Code Online (Sandbox Code Playgroud)
如果您没有日期表,那么您可以轻松创建一个。网络上有大量这样的例子。
我希望这有帮助!