我有一张包含以下数据的表格,按姓名和日期排序
Row Name Pos Date
--- ---- ---- ----
1 Anne A 11/01/2014
2 Anne A 11/02/2014
3 Anne C 11/04/2014
4 Anne B 11/06/2014
5 Anne C 11/08/2014
6 Jane A 11/01/2014
7 Jane A 11/02/2014
8 Jane C 11/03/2014
9 Mark B 11/01/2014
10 Mark A 11/04/2014
11 Mark A 11/06/2014
12 Mark B 11/07/2014
13 Mark C 11/08/2014
规则是用户不应该在C
之前至少他/她已经A
两次。一旦用户进入C
,他/她在A
之前必须再次C
两次或更多次。您如何找到遵循此规则的用户?
对于此示例,答案应为Jane
和Mark
。 Anne
违反了第5行的规则。
答案 0 :(得分:3)
假设您的表名为Records
,以下是利用SQL Server 2012的LAG window function进行操作的方法:
首先,让我们找到违反规则的用户:
;with ACRecords as (
select Row, Name, Date, Pos
from Records
where Pos in ('A', 'C')
),
AC3ConsecutiveRecords as (
select
Name,
Pos,
lag(Pos, 1) over (partition by Name order by Date) as LastPos,
lag(Pos, 2) over (partition by Name order by Date) as SecondToLastPos
from ACRecords
)
select
Name
from AC3ConsecutiveRecords
where Pos = 'C' and (LastPos <> 'A' or SecondToLastPos <> 'A')
此查询执行以下操作:
Pos
值的记录。Pos
,LastPos
和SecondToLastPos
,我们使用LAG
(使用适当的{{ {1}}和PARTITION
条款。)ORDER BY
等于C且前两个Pos
值不同于A的行(至少其中一个)。为每个记录选择名称。这些人违反了规则。为了让那些遵守规则的人,只需将最后一步包裹在另一个CTE中,然后选择除违反规则的人以外的所有人:
Pos
SQLFiddle的SQL 2012实例目前已关闭,但幸运的是查询在Postgres中正常运行,因此这里有一个实时版本:http://sqlfiddle.com/#!15/bed67/1
答案 1 :(得分:0)
让我们设置场景:
declare @table table(row int,name varchar(9),pos char(1),date smalldatetime)
insert @table values(1,'Anne','A','20141101')
insert @table values(2,'Anne','A','20141102')
insert @table values(3,'Anne','C','20141104')
insert @table values(4,'Anne','B','20141106')
insert @table values(5,'Anne','C','20141108')
insert @table values(6,'Jane','A','20141101')
insert @table values(7,'Jane','A','20141102')
insert @table values(8,'Jane','C','20141103')
insert @table values(9,'Mark','B','20141101')
insert @table values(10,'Mark','A','20141104')
insert @table values(11,'Mark','A','20141106')
insert @table values(12,'Mark','B','20141107')
insert @table values(13,'Mark','C','20141108')
下面的查询给出了预期的结果:
select distinct a.name
from @table a
where a.pos = 'C'
-- 1. ensure that there are no C's which is followed by less than 2 A's
and not exists (
select * from @table b where a.name = b.name and b.pos = 'C' and b.date < a.date
and (select count(*) from @table c where a.name = c.name and c.pos = 'A' and c.date < a.date and c.date > b.date) < 2)
-- 2. ensure that there are no C pairs which have less than 2 A's between them
and not exists (
select * from @table d join @table e on d.name = e.name
where d.pos = 'C' and e.pos = 'C' and d.name = a.name and d.date < e.date
and (select count(*) from @table f where f.name = a.name and f.pos = 'A' and f.date < e.date and f.date > d.date) < 2)
答案 2 :(得分:-1)
我认为唯一的解决方案是创建一个触发器而不是insert来检查这个
(从插入中选择count(pos),其中pos = C)&lt; =(从插入中选择2 * count(pos),其中pos = A)
并根据结果回滚或提交