如何在 SQL 服务器中 select 顺序复制
How to select sequential duplicates in SQL Server
我想 select 从 SQL 服务器 table、 复制条目,但前提是 ID 是连续的。
我一直在努力 this answer 满足我的需要,但我无法让它发挥作用。
上面的答案是针对Oracle的,但是我看到SQL服务器也有lead
和lag
功能。
此外,我认为上面的答案在重复项旁边放置了 *
,但我只想 select 重复项。
select
id, companyName,
case
when companyName in (prev, next)
then '*'
end match,
prev,
next
from
(select
id,
companyName,
lag(companyName, 1) over (order by id) prev,
lead(companyName, 1) over (order by id) next
from
companies)
order by
id;
示例:
所以从这个数据集中:
id companyName
-------------------
1 dogs ltd
2 cats ltd
3 pigs ltd
4 pigs ltd
5 cats ltd
6 cats ltd
7 dogs ltd
8 pigs ltd
我想select:
id companyName
-------------------
3 pigs ltd
4 pigs ltd
5 cats ltd
6 cats ltd
更新
时不时地,我对在 SO 上获得的答案的数量和质量感到吃惊。这是那些时代之一。我没有足够的专业知识来判断一个答案比另一个更好,所以我选择了 SqlZim,因为这是我看到的第一个有效答案。但很高兴看到不同的方法。尤其是一个小时前我还在想 "is this even possible?"。
您可以使用 Row_Number() 并根据子句
的分区获取重复项
;with cte as (
SELECT id, companyName,
RowN = Row_Number() over (partition by id order by companynae) from #yourTable
)
Select * from cte where RowN > 1
您能否提供您的输入和预期输出来验证此查询
这是一个间隙和孤岛式的问题,但我们在最里面的子查询中使用了 id
和 row_number()
,而不是使用两个 row_numbers()
。接下来是 count() over()
以获取每个 grp
的计数,最后是 return 具有 cnt > 1
.
的计数
select id, companyname
from (
select
id
, companyName
, grp
, cnt = count(*) over (partition by companyname, grp)
from (
select *
, grp = id - row_number() over (partition by companyname order by id)
from
companies
) islands
) d
where cnt > 1
order by id
rextester 演示:http://rextester.com/ACP73683
returns:
+----+-------------+
| id | companyname |
+----+-------------+
| 3 | pigs ltd |
| 4 | pigs ltd |
| 5 | cats ltd |
| 6 | cats ltd |
+----+-------------+
在WHERE子句中你只需要限制companyName与prev或next相同的那些
select id, companyName
from (
select id, companyName,
lag(companyName, 1) over (order by id) as prev,
lead(companyName, 1) over (order by id) as next
from companies
) q
where companyName in (prev, next)
order by id;
为了确保 id 真的没有间隙,你可以这样做:
select id, companyName
from (
select id, companyName,
lag(concat(id+1,companyName), 1) over (order by id) as prev,
lead(concat(id-1,companyName), 1) over (order by id) as next
from companies
) q
where concat(id,companyName) in (prev, next)
order by id;
你非常接近你想要的:
select id, companyName
from (select c.*,
lag(companyName, 1) over (order by id) prev,
lead(companyName, 1) over (order by id) next
from companies c
) a
where CompanyName in (prev, next)
order by id;
另一种形式,使用 LEAD() 和 LAG()(SQL 2012 年及以上)
SELECT id, CompanyName
FROM (
SELECT *,
LEAD(CompanyName, 1) OVER(ORDER BY id) as nc,
LAG(CompanyName, 1) OVER(ORDER BY id) AS pc
FROM #t t
) x
WHERE nc = companyName
OR pc = companyName
这里是测试数据,大家可以自行查看
CREATE TABLE #T (id int not null PRIMARY KEY, companyName varchar(16) not null)
INSERT INTO #t Values
(1, 'dogs ltd'),
(2, 'cats ltd'),
(3, 'pigs ltd'),
(4, 'pigs ltd'),
(5, 'cats ltd'),
(6, 'cats ltd'),
(7, 'dogs ltd'),
(8, 'pigs ltd')
我想 select 从 SQL 服务器 table、 复制条目,但前提是 ID 是连续的。
我一直在努力 this answer 满足我的需要,但我无法让它发挥作用。
上面的答案是针对Oracle的,但是我看到SQL服务器也有lead
和lag
功能。
此外,我认为上面的答案在重复项旁边放置了 *
,但我只想 select 重复项。
select
id, companyName,
case
when companyName in (prev, next)
then '*'
end match,
prev,
next
from
(select
id,
companyName,
lag(companyName, 1) over (order by id) prev,
lead(companyName, 1) over (order by id) next
from
companies)
order by
id;
示例:
所以从这个数据集中:
id companyName
-------------------
1 dogs ltd
2 cats ltd
3 pigs ltd
4 pigs ltd
5 cats ltd
6 cats ltd
7 dogs ltd
8 pigs ltd
我想select:
id companyName
-------------------
3 pigs ltd
4 pigs ltd
5 cats ltd
6 cats ltd
更新
时不时地,我对在 SO 上获得的答案的数量和质量感到吃惊。这是那些时代之一。我没有足够的专业知识来判断一个答案比另一个更好,所以我选择了 SqlZim,因为这是我看到的第一个有效答案。但很高兴看到不同的方法。尤其是一个小时前我还在想 "is this even possible?"。
您可以使用 Row_Number() 并根据子句
的分区获取重复项;with cte as (
SELECT id, companyName,
RowN = Row_Number() over (partition by id order by companynae) from #yourTable
)
Select * from cte where RowN > 1
您能否提供您的输入和预期输出来验证此查询
这是一个间隙和孤岛式的问题,但我们在最里面的子查询中使用了 id
和 row_number()
,而不是使用两个 row_numbers()
。接下来是 count() over()
以获取每个 grp
的计数,最后是 return 具有 cnt > 1
.
select id, companyname
from (
select
id
, companyName
, grp
, cnt = count(*) over (partition by companyname, grp)
from (
select *
, grp = id - row_number() over (partition by companyname order by id)
from
companies
) islands
) d
where cnt > 1
order by id
rextester 演示:http://rextester.com/ACP73683
returns:
+----+-------------+
| id | companyname |
+----+-------------+
| 3 | pigs ltd |
| 4 | pigs ltd |
| 5 | cats ltd |
| 6 | cats ltd |
+----+-------------+
在WHERE子句中你只需要限制companyName与prev或next相同的那些
select id, companyName
from (
select id, companyName,
lag(companyName, 1) over (order by id) as prev,
lead(companyName, 1) over (order by id) as next
from companies
) q
where companyName in (prev, next)
order by id;
为了确保 id 真的没有间隙,你可以这样做:
select id, companyName
from (
select id, companyName,
lag(concat(id+1,companyName), 1) over (order by id) as prev,
lead(concat(id-1,companyName), 1) over (order by id) as next
from companies
) q
where concat(id,companyName) in (prev, next)
order by id;
你非常接近你想要的:
select id, companyName
from (select c.*,
lag(companyName, 1) over (order by id) prev,
lead(companyName, 1) over (order by id) next
from companies c
) a
where CompanyName in (prev, next)
order by id;
另一种形式,使用 LEAD() 和 LAG()(SQL 2012 年及以上)
SELECT id, CompanyName
FROM (
SELECT *,
LEAD(CompanyName, 1) OVER(ORDER BY id) as nc,
LAG(CompanyName, 1) OVER(ORDER BY id) AS pc
FROM #t t
) x
WHERE nc = companyName
OR pc = companyName
这里是测试数据,大家可以自行查看
CREATE TABLE #T (id int not null PRIMARY KEY, companyName varchar(16) not null)
INSERT INTO #t Values
(1, 'dogs ltd'),
(2, 'cats ltd'),
(3, 'pigs ltd'),
(4, 'pigs ltd'),
(5, 'cats ltd'),
(6, 'cats ltd'),
(7, 'dogs ltd'),
(8, 'pigs ltd')