我有以下表定义和样本数据。在下表中,Customer Product&日期是关键字段
Table One
Customer Product Date SALE
X A 01/01/2010 YES
X A 02/01/2010 YES
X A 03/01/2010 NO
X A 04/01/2010 NO
X A 05/01/2010 YES
X A 06/01/2010 NO
X A 07/01/2010 NO
X A 08/01/2010 NO
X A 09/01/2010 YES
X A 10/01/2010 YES
X A 11/01/2010 NO
X A 12/01/2010 YES
在上表中,我需要找到N或>没有销售的N个连续记录,销售价值为'否' 例如,如果N为2,则结果集将返回以下
Customer Product Date SALE
X A 03/01/2010 NO
X A 04/01/2010 NO
X A 06/01/2010 NO
X A 07/01/2010 NO
X A 08/01/2010 NO
有人可以帮我处理SQL查询以获得所需的结果。我正在使用SQL Server 2005.我开始使用ROW_NUMBER()AND PARTITION子句但没有运气。 谢谢你的帮助
答案 0 :(得分:4)
您需要将表格与自身匹配,就好像有2个表格一样。所以你使用两个别名o1和o2来引用你的表:
SELECT DISTINCT o1.customer, o1.product, o1.datum, o1.sale
FROM one o1, one o2
WHERE (o1.datum = o2.datum-1 OR o1.datum = o2.datum +1)
AND o1.sale = 'NO'
AND o2.sale = 'NO';
customer | product | datum | sale
----------+---------+------------+------
X | A | 2010-01-03 | NO
X | A | 2010-01-04 | NO
X | A | 2010-01-06 | NO
X | A | 2010-01-07 | NO
X | A | 2010-01-08 | NO
请注意,我在postgresql数据库上执行了查询 - 也许ms-sql-server上的语法不同,也许在别名'FROM AS AS o1'上,也许你不能以这种方式添加/减少。
答案 1 :(得分:1)
一种不同的方法,受到最后一行的启发。
获取 - 给定日期的第一个日期晚于YES,最后一个日期早于YES。这些形成了我们的日期适合的边界。
SELECT (o1.datum),
MAX (o3.datum) - MIN (o2.datum) AS diff
FROM one o1, one o2, one o3
WHERE o1.sale = 'NO'
AND o3.datum <
(SELECT MIN (datum)
FROM one
WHERE datum >= o1.datum
AND SALE = 'YES')
AND o2.datum >
(SELECT MAX (datum)
FROM one
WHERE datum <= o1.datum
AND SALE = 'YES')
GROUP BY o1.datum
HAVING MAX (o3.datum) - MIN (o2.datum) >= 2
ORDER BY o1.datum;
也许它需要某种优化,因为第一表是查询中涉及的5倍。 :)
答案 2 :(得分:0)
好的,我们需要一个可变的答案。我们搜索一个日期,我们有N个以下日期,所有销售区域都是NO。
SELECT d1.datum
FROM one d1, one d2, i
WHERE d1.sale = 'NO' AND d2.sale = 'NO'
AND d1.datum = (d2.datum - i)
AND i > 0 AND i < 4
GROUP BY d1.datum
HAVING COUNT (*) = 3;
这将为我们提供日期,我们将其用于子查询。
注意:
我使用'datum'而不是date,因为date是postgresql上的保留关键字。
在Oracle中,您可以使用虚拟表格虚拟,其中包含您要求的任何内容,例如“(1,2,3)中的SELCT foo FROM dual WHERE foo”;如果我没记错的话会给你1,2,3。根据供应商的不同,可能还有其他技巧可以获得序列1到N.我创建了一个带有列i的表i,并用值1到100填充它,我希望N不超过100;由于有几个版本,postgresql包含一个函数'generate_series(from,to),它也可以解决问题,并且可能与特定数据库的解决方案有相似之处。但是我应该独立于供应商。
如果N == 17,则必须修改3到3的3个位置。
最终查询将是:
SELECT o4.*
FROM one o3, one o4
WHERE o3.datum = (
SELECT d1.datum
FROM one d1, one d2, i
WHERE d1.sale = 'NO' AND d2.sale = 'NO'
AND d1.datum = (d2.datum - i)
AND i > 0 AND i <= 3
GROUP BY d1.datum
HAVING COUNT (*) = 3)
AND o4.datum <= o3.datum + 3
AND o4.datum >= o3.datum;
customer | product | datum | sale
----------+---------+------------+------
X | A | 2010-02-06 | NO
X | A | 2010-02-07 | NO
X | A | 2010-02-08 | NO
X | A | 2010-02-09 | NO
答案 3 :(得分:0)
感谢大家发布您的解决方案。想了想,我也会和大家分享我的解决方案。就像一个FYI,我从另一个SQL Server Central论坛成员那里收到了这个解决方案。我绝对不会赞成这个解决方案。
DECLARE @CNT INT
SELECT @CNT = 3
SELECT * FROM
(
SELECT
[Customer], [Product], [Date], [Sale], groupID,
COUNT(*) OVER (PARTITION BY [Customer], [Product], [Sale], groupID) AS groupCnt
FROM
(
SELECT
[Customer], [Product], [Date], [Sale],
ROW_NUMBER() OVER (PARTITION BY [Customer], [Product] ORDER BY [Date])
- ROW_NUMBER() OVER (PARTITION BY [Customer], [Product], [Sale] ORDER BY [Date]) AS groupID
FROM
[TableSales]
) T1
) T2
WHERE
T2.[Sale] = 'NO' AND T2.[groupCnt] >= @CNT