SQL 查询以了解商品销售的后续天数
Posted
技术标签:
【中文标题】SQL 查询以了解商品销售的后续天数【英文标题】:SQL Query to know followed days of item sales 【发布时间】:2014-01-19 10:53:01 【问题描述】:我有一张桌子,上面放着所有售出的物品。这些记录适用于已签发文件的所有行。有些商品每天都有销售,而其他商品则没有。还有一些没有每日销售的人,有一定的销售期。
我需要一个查询来向我显示每件商品的最大销售期(以天数计)。这可能吗?
在 Excel 中可以这样做,使用按项目/天/数量分组的表并应用以下公式:“如果天数 = 0,则返回 0,否则,如果前一天的金额 = 0,则返回 1,否则返回前一天的金额 + 1"。最后它只是检查该列的最大值。
在 SQL 中执行此操作有什么帮助吗?谢谢!
这是一个小样本(1 月 1 日至 10 日期间):
原表:
SalesDate Doc ItemID Qty
01-jan 156 123456 10
01-jan 156 654321 5
01-jan 157 123456 3
02-jan 158 654321 4
02-jan 158 123456 7
03-jan 159 123456 8
04-jan 160 654321 3
04-jan 161 654321 8
05-jan 162 654321 3
06-jan 163 123456 7
06-jan 163 654321 2
06-jan 164 123456 9
07-jan 165 654321 4
08-jan 166 123456 5
09-jan 167 123456 6
10-jan 168 123456 3
10-jan 168 654321 5
10-jan 169 654321 1
中间表:
CalendarDate ItemID SumQty FollowedSalesDays
01-jan 123456 13 1
02-jan 123456 7 2
03-jan 123456 8 3
04-jan 123456 0 0
05-jan 123456 0 0
06-jan 123456 16 1
07-jan 123456 0 0
08-jan 123456 5 1
09-jan 123456 6 2
10-jan 123456 3 3
01-jan 654321 5 1
02-jan 654321 4 2
03-jan 654321 0 0
04-jan 654321 11 1
05-jan 654321 3 2
06-jan 654321 2 3
07-jan 654321 4 4
08-jan 654321 0 0
09-jan 654321 0 0
10-jan 654321 6 1
最终结果:
ItemID MaxFollowedSalesDays
123456 3
654321 4
【问题讨论】:
您使用的是哪个 DBMS?后格雷斯?甲骨文? 对不起:MS SQL Server。 你能展示一些示例数据和所需的输出吗?? @M.Ali:问题已编辑 - 添加了小样本 【参考方案1】:这是一种基于cursor 的方法。它应该以线性时间运行,比简单的实现要快得多。
DECLARE @ItemID varchar(10) = NULL
DECLARE @SalesDate date
DECLARE @NextItemID varchar(10)
DECLARE @NextSalesDate date
DECLARE @StartDate date
DECLARE @Contiguity int
DECLARE @MaxContiguity int = 1
DECLARE @MaxSalesDateContiguityPerItem TABLE (
ItemID varchar(10) NOT NULL,
MaxSalesDateContiguity int NOT NULL
)
DECLARE SalesCursor CURSOR FOR
SELECT DISTINCT ItemID, SalesDate FROM ItemsSold ORDER BY ItemID, SalesDate
OPEN SalesCursor
DECLARE @more int = 3
WHILE @more > 0
BEGIN
FETCH NEXT FROM SalesCursor INTO @NextItemID, @NextSalesDate
SET @more = CASE
WHEN @@FETCH_STATUS <> 0 THEN 0 -- reached end of result set
WHEN @ItemID IS NULL OR @ItemID <> @NextItemID THEN 1 -- next item
WHEN DATEDIFF(day, @SalesDate, @NextSalesDate) > 1 THEN 2 -- date hole
ELSE 3
END
-- Calculate the length of the contiguity we just passed.
-- Compare with earlier contiguities; keep whatever is longest.
IF @more <= 2 AND @ItemID IS NOT NULL
BEGIN
SET @Contiguity = DATEDIFF(day, @StartDate, @SalesDate) + 1
IF @Contiguity > @MaxContiguity SET @MaxContiguity = @Contiguity
SET @StartDate = @NextSalesDate -- begin another contiguity
END
-- Flush the item we just passed to the temporary table.
IF @more <= 1 AND @ItemID IS NOT NULL
BEGIN
INSERT INTO @MaxSalesDateContiguityPerItem VALUES (@ItemID, @MaxContiguity)
SET @MaxContiguity = 1 -- start over with another item
END
SET @ItemID = @NextItemID
SET @SalesDate = @NextSalesDate
END
CLOSE SalesCursor
DEALLOCATE SalesCursor
SELECT * FROM @MaxSalesDateContiguityPerItem ORDER BY ItemID
注意:请将所有出现的varchar(10)
替换为您的ItemID
列的任何类型。
编辑:进一步的性能考虑... 如果您正在处理甚至使这种线性时间解决方案变得太慢的记录集,那么请注意还有其他选择。在您的问题中,您已经提出了一个“中间表”;您可以将其设为永久表,通过预定作业定期更新,或通过销售交易表上的trigger 立即更新。后者保证了实时信息,但它会使交易变慢。
【讨论】:
感谢@Ruud 的努力。这是一项伟大的工作!我尝试了一些样品,结果总是完美的。然而应用于生产数据库有一些奇怪的东西 - 游标的查询返回超过 42000 条记录,(有超过 42000 种不同的销售项目),但最终结果只出现 18612 ......知道它可能是什么吗? 对不起@Ruud - 我忘记了你的笔记。当我将 varchar(10) 更改为 nvarchar(25)(我的 ItemID)时,每条记录都会产生结果!再次感谢! @PJLG:很高兴它成功了!我对建议进行了编辑,以防这种线性时间解决方案变得太慢。 感谢您的关心@Ruud。毕竟我对这个查询的性能感到惊讶——在几秒钟内返回完整的结果。无论如何,您创建表格并使用 Job 更新表格的建议很有趣。另一方面,对我来说,使用触发器是最后的解决方案,因为我不想影响事务性能。再次感谢您!【参考方案2】:这是一个幼稚的实现。它的性能很糟糕(二次时间复杂度),但它可能在测试更好的实现时派上用场。
SELECT ItemID, MAX(Filled)
FROM (
SELECT i1.ItemID,
DATEDIFF(day, i1.SalesDate, i2.SalesDate) AS Distance,
(
SELECT COUNT(DISTINCT i3.SalesDate)
FROM ItemsSold i3
WHERE i3.ItemID = i1.ItemID
AND i3.SalesDate BETWEEN i1.SalesDate AND i2.SalesDate
) AS Filled
FROM ItemsSold i1
INNER JOIN ItemsSold i2 ON i2.ItemID = i1.ItemID AND i2.SalesDate >= i1.SalesDate
) AS CartesianProduct
WHERE Distance + 1 = Filled
GROUP BY ItemID
要实现线性时间复杂度,您可以使用cursor。或者,将逻辑移至您的应用程序服务器。
【讨论】:
谢谢@Ruud。它真的很慢(它必须分析数百万行中的 50,000 多个项目),但这不是最大的问题。问题是查询不返回真实结果。我试了一个有 180 天销售天数的项目,这个查询只返回 21。 连续销售 180 天?这让我很怀疑;你从来没有提到我们应该“跳过”公共假期。无论如何,我愿意接受挑战;你能告诉我一个我的查询不足的示例记录集(如果可能的话,是一个小记录集)?以上是关于SQL 查询以了解商品销售的后续天数的主要内容,如果未能解决你的问题,请参考以下文章