给出一个表
custid | date | action
1 | 2011-04-01 | activate
1 | 2011-04-10 | deactivate
1 | 2011-05-02 | activate
2 | 2011-04-01 | activate
3 | 2011-03-01 | activate
3 | 2011-04-01 | deactivate
数据库是PostgreSQL。
我想要一个SQL查询来显示在5月的任何阶段都处于活动状态的客户。
所以,在上面,那将是1和2.
我无法理解我的方法来解决这个问题。有什么指针吗?
更新
客户2在5月期间处于活动状态,因为他在5月之前被激活,并且自从他被激活后未被停用。就像在,我本月活着,但本月没出生,我没有死。
select distinct custid
from MyTable
where action = 'active' and date >= '20110501' and date < '20110601'
这种方法不起作用,因为它只显示在may期间的激活,而不是'actives'。
答案 0 :(得分:3)
注意:这将是一个起点,仅适用于2011年。
忽略任何遗留的错误,此代码(针对每个客户)查看1)客户在5月之前的最新状态更新和2)客户在5月期间是否变为活动状态?
SELECT
Distinct CustId
FROM
MyTable -- Start with the Main table
-- So, was this customer active at the start of may?
LEFT JOIN -- Find this customer's latest entry before May of This Year
(select
max(Date)
from
MyTable
where
Date < '2011-05-01') as CustMaxDate_PreMay on CustMaxDate_PreMay.CustID = MyTable.CustID
-- Return a record "1" here if the Customer was Active on this Date
LEFT JOIN
(select
1 as Bool,
date
from
MyTable
) as CustPreMay_Activated on CustPreMay_Activated.Date = CustMaxDate_PreMay.Date and CustPreMay_Activated.CustID = MyTable.CustID and CustPreMay_Activated = 'activated'
-- Fallback plan: If the user wasn't already active at the start of may, did they turn active during may? If so, return a record here "1"
LEFT JOIN
(select
1 as Bool
from
MyTable
where
Date <= '2011-05-01' and Date < '2011-06-01' and action = 'activated') as TurnedActiveInMay on TurnedActiveInMay .CustID = MyTable.CustID
-- The Magic: If CustPreMay_Activated is Null, then they were not active before May
-- If TurnedActiveInMay is also Null, they did not turn active in May either
WHERE
ISNULL(CustPreMay_Activated.Bool, ISNULL(TurnedActiveInMay.Bool, 0)) = 1
注意:强>
您可能需要将 我不清楚只看这个代码是否A)太慢或B)以某种方式引起欺骗或问题,因为启动FROM子句@ MYTable可能包含每个客户的许多记录。 DISTINCT子句可能会解决这个问题,但我想提到这个解决方法。 最后,我会让你在不同年份完成这项工作。 From (Select distinct CustID from MyTable) as Customers
答案 1 :(得分:2)
试试这个
select t2.custid from
(
-- select the most recent entry for each customer
select custid, date, action
from cust_table t1
where date = (select max(date)
from cust_table where custid = t1.custid)
) as t2
where t2.date < '2011-06-01'
-- where the most recent entry is in May or is an activate entry
-- assumes they have to have an activate entry before they get a deactivate entry
and (date > '2011-05-01' or [action] = 'activate')
答案 2 :(得分:0)
在PostgreSQL 8.4 +中:
WITH ActivateDates AS (
SELECT
custid,
date,
ROW_NUMBER() OVER (PARTITION BY custid ORDER BY date) AS rownum
FROM atable
WHERE action = 'activate'
),
DeactivateDates AS (
SELECT
custid,
date,
ROW_NUMBER() OVER (PARTITION BY custid ORDER BY date) AS rownum
FROM atable
WHERE action = 'deactivate'
),
ActiveRanges AS (
SELECT
a.custid,
a.date AS activated,
COALESCE(b.date, '21000101'::date) AS deactivated
FROM ActivateDates a
LEFT JOIN DeactivateDates d ON a.custid = d.custid AND a.rownum = d.rownum
)
SELECT DISTINCT custid
FROM ActiveRanges
WHERE deactivated > '20110501'
AND activated < '20110601'