棘手的SQL问题
我有一张这样的桌子棘手的SQL问题,sql,exists,Sql,Exists,我有一张这样的桌子 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严格增加,但可能存在缺口。 有什么建议吗?我没想到这会在数千行中引起轰动: SELECT * /* TODO
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严格增加,但可能存在缺口。
有什么建议吗?我没想到这会在数千行中引起轰动:
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行最接近。编辑:在您提到SQL Server 2000之前,我写了这个。这在SQL Server 2005或更高版本中有效,因此对您没有帮助,但我将把它留给后代: 我使用a向表中添加连续的不间断顺序,然后连接两次以获得上一行和下一行
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
如果您不需要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方法,不提供以下信息:
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。尽管我只是在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
如果你想查看前两个或更多的值,这肯定会有它自己的作用,因为你可以写lagval,2来向后看2行等等。查找前一个或下一个值是一个简单的情况,选择前1。。。处理得很好。] 假设表名为table,这里是普通的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
)
如果两边的值相同,您能重新表述一下吗?我不明白你想做什么val是一个回文数字,或者只是第一个和最后一个数字相同?SQL的味道是什么?值必须是哪一边的?好的,我把问题改写得更清楚一点你使用的是哪种数据库产品?按k顺序按seq分区不是更好/更清晰,因为每个k值都是分开的吗?是的,这更符合逻辑。已编辑。不幸的是,SQL Server 2000中没有CTE和ROW_编号:-@marc wow,我知道CTE是新的,但我没有意识到ROW_编号不在2000年..所有这些排名函数ROW_编号、排名、密集排名等都是SQL Server 2005的新功能。。。此外:SQLServer2000已经很老了——这个星球上的任何人都不应该再被迫使用它了。。。我也是我自己——不幸的是!不幸的是,OP要求使用SQL Server 2000-目前还没有任何CTE:-啊,我开始时没有指定。尽管如此,对于其他有同样问题的人来说可能还是有用的,但是对于现代数据库来说。OP可以用tmp表做类似的事情吗?很好的解决方案。我只是稍微喜欢阿拉克尼德的简单回答。
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
)