我有一个包含交易、人员、交易日期、物品等的数据库。 每次有人购买商品时,交易都会存储在表中,如下所示:
personNumber, TransactionNumber, TransactionDate, ItemNumber
我想要做的是找到从 2012 年 1 月 1 日(交易日期)到 2012 年 3 月 1 日在 14 天内(可配置)或更短时间内多次购买相同 ItemNumber 的人(personNumber)。然后我需要在报告中列出所有这些交易。
样本数据:
personNumber, TransactionNumber, TransactionDate, ItemNumber
1 | 100| 2001-01-31| 200
2 | 101| 2001-02-01| 206
2 | 102| 2001-02-11| 300
1 | 103| 2001-02-09| 200
3 | 104| 2001-01-01| 001
1 | 105| 2001-02-10| 200
3 | 106| 2001-01-03| 001
1 | 107| 2001-02-28| 200
结果:
personNumber, TransactionNumber, TransactionDate, ItemNumber
1 | 100| 2001-01-31| 200
1 | 103| 2001-02-09| 200
1 | 105| 2001-02-10| 200
3 | 104| 2001-01-01| 001
3 | 106| 2001-01-03| 001
你会怎样做呢?
我尝试过这样做:
select *
from (
select personNumber, transactionNumber, transactionDate, itemNumber,
count(*) over (
partition by personNumber, itemNumber) as boughtSame)
from transactions
where transactionDate between '2001-01-01' and '2001-03-01')t
where boughtSame > 1
这让我明白了:
personNumber, TransactionNumber, TransactionDate, ItemNumber
1 | 100| 2001-01-31| 200
1 | 103| 2001-02-09| 200
1 | 105| 2001-02-10| 200
1 | 107| 2001-02-28| 200
3 | 104| 2001-01-01| 001
3 | 106| 2001-01-03| 001
问题是我不想要 TransactionNumber 107,因为它不在 14 天内。我不知道 14 天的限制应该放在哪里。我可以做一个约会,但是在哪里,通过什么?
唉,SQL Server 2005 中的窗口函数还不够强大。我将使用相关子查询来解决这个问题。
相关子查询计算一个人在每次购买后 14 天内购买该商品的次数(不包括第一次购买)。
select t.*
from (select t.*,
(select count(*)
from t t2
where t2.personnumber = t.personnumber and
t2.itemnumber = t.itemnumber and
t2.transactionnumber <> t.transactionnumber and
t2.transactiondate >= t.transactiondate and
t2.transactiondate < DATEADD(day, 14, t.transactiondate
) NumWithin14Days
from transactions t
where transactionDate between '2001-01-01' and '2001-03-01'
) t
where NumWithin14Days > 0
您可能还想在子查询中设置时间限制。
transactions(personnumber, itemnumber, transactionnumber, itemdate)
上的索引可能会帮助运行得更快。
如果您的问题表明您只想查找具有指定条件的人员(personNumbers),您可以进行自加入和分组:
create table #tx (personNumber int, transactionNumber int, transactionDate dateTime, itemNumber int)
insert into #tx
values
(1, 100, '2001-01-31', 200),
(2, 101, '2001-02-01', 206),
(2, 102, '2001-02-11', 300),
(1, 103, '2001-02-09', 200),
(3, 104, '2001-01-01', 001),
(1, 105, '2001-02-10', 200),
(3, 106, '2001-01-03', 001),
(1, 107, '2001-02-28', 200)
declare @days int = 14
select t1.personNumber from #tx t1 inner join #tx t2 on
t1.personNumber = t2.personNumber
and t1.itemNumber = t2.itemNumber
and t1.transactionNumber < t2.transactionNumber
and datediff(day, t1.transactionDate, t2.transactionDate) between 0 and @days
group by t1.personNumber
-- if more than zero joined rows there is more than one transaction in period
having count(t1.personNumber) > 0
drop table #tx
还需要考虑同一个人和物品的交易时间差。它可以按如下方式完成:
SELECT personNumber, TransactionNumber, TransactionDate, ItemNumber
FROM (
SELECT
personNumber,
transactionNumber,
transactionDate,
itemNumber,
COUNT(*) OVER (
PARTITION BY personNumber, itemNumber
ORDER BY transactionDate
RANGE BETWEEN INTERVAL 14 DAY PRECEDING AND CURRENT ROW
) AS boughtSame
FROM transactions
WHERE transactionDate BETWEEN '2001-01-01' AND '2001-03-01'
) t
WHERE boughtSame > 1;