我有一张这样的桌子......
Key Seq Val
A 1 123
A 4 129
A 9 123
A 10 105
B 3 100
B 6 101
B 12 102
我想找到案例(如A,4),其中值(在本例中为123)在之前(在本例中为A,1)和之后(在本例中为A,9)是相同的。 seq严格增加,但可能有差距。 有什么建议吗?
答案 0 :(得分:3)
虽然我只在sql server 2005中测试了这个(因为我没有2000个实例),在用真实表替换@t后,这应该仍然适用于该平台。
select k, seq, val
from (
select k, seq, val,
(select top 1 val from @t aux where aux.k = main.k and aux.seq < main.seq order by seq desc) as prev_val,
(select top 1 val from @t aux where aux.k = main.k and aux.seq > main.seq order by seq asc) as next_val
from @t main
) x
where prev_val = next_val
如果您在k, seq
上有索引,则性能不应该太坏,因为相关子查询是简单的索引扫描。
遗憾的是,我认为lag
和lead
函数的支持不在SQL Server路线图上。
[如果有人感兴趣,我的意思是在某些数据库中你可以写:
select key, seq, val
from (
select key, seq, val,
lag(val) over(partition by key order by seq) as prev_val,
lead(val) over(partition by key order by seq) as next_val
from t
) x
where prev_val = next_val;
如果您想要查看前两个或更多值,这肯定会自成一体,因为您可以编写lag(val, 2)
来查看2行等。查找前一个或下一个值是一个更简单的情况select top 1 ...
处理得非常好。 ]
答案 1 :(得分:2)
我不希望这会消耗数千行:
SELECT
* /* TODO - pick columns */
FROM
Table t1
inner join
Table t2
on
t1.Key = t2.Key and
t1.Seq < t2.Seq
inner join
Table t3
on
t1.Key = t3.Key and
t1.Seq > t3.Seq and
t2.Val = t3.Val
left join
Table t4
on
t1.Key = t4.Key and
t1.Seq < t4.Seq and
t4.Seq < t2.Seq
left join
Table t5
on
t1.Key = t5.Key and
t1.Seq > t5.Seq and
t5.Seq > t3.Seq
WHERE
t4.Key is null and t5.Key is null
基本上,根据你的定义,表的前3个实例将表连接到自身,以找到围绕“有趣”行的两行。后续连接(t4和t5)确保t2和t3搜索找到的行最接近t1行。
答案 2 :(得分:1)
编辑:我在你说SQL Server 2000之前写过这个。这在SQL Server 2005或更高版本中有效,所以它对你没有帮助,但我会留在这里为后人:)
我正在使用CTE向表中添加顺序(不间断)排序,然后连接两次以获取上一行和下一行。
declare @t table (k char(1), seq int, val int)
insert into @t values ('A', 1, 100)
insert into @t values ('A', 4, 101)
insert into @t values ('A', 9, 100)
insert into @t values ('A', 10, 105)
insert into @t values ('B', 3, 100)
insert into @t values ('B', 6, 101)
insert into @t values ('B', 12, 102)
; with q as (
select *, row_number() over (partition by k order by seq) [rownum] from @t
)
select *
from q
join q q1 on q1.rownum=q.rownum-1 and q.k=q1.k
join q q2 on q2.rownum=q.rownum+1 and q.k=q2.k
where q1.val=q2.val
答案 3 :(得分:1)
如果您不需要seq字段,则此方法有效:
;with cte as
(
select COUNT( 1 ) as cnt, val, [key] from tbl
group by val, [key]
)
select * from cte where cnt > 1
如果你这样做:
;with cte as
(
select COUNT( 1 ) as cnt, val, [key] from tbl
group by val, [key]
)
select tbl.* from tbl inner join cte on cte.cnt > 1 and cte.[Key] = tbl.[Key] and cte.Val = tbl.Val
编辑:一种tmptbl方法,它不会给你seq:
CREATE TABLE #tmptbl (
cnt int,
[key] nchar(10),
Val nchar(10)
)
insert into #tmptbl
select COUNT( 1 ) as cnt, [key], Val from tbl
group by tbl.Val, tbl.[key]
select * from #tmptbl where cnt > 1
drop table #tmptbl
根据您的字段类型,这可能很容易更改,以便为您提供seq。
答案 4 :(得分:1)
假设表的名称是“Table”,这里是普通的vanilla sql。
SELECT
Key,
Seq
from Table A
WHERE EXISTS
(SELECT 1 FROM Table B, Table C
WHERE B.Key = A.Key
AND C.Key = A.Key
AND B.Seq = (SELECT MAX(Seq) FROM Table D WHERE D.Key = A.Key AND D.Seq < A.Seq) --This ensures that B retrieves previous row
AND C.Seq = (SELECT MIN(Seq) FROM Table E WHERE E.Key = A.Key AND E.Seq > A.Seq) --This ensures that C retrieves next row
AND B.Val = C.Val
)