这是上一个问题的延续:Find groups with matching rows
我有一张桌子,其中包含人和他们拥有的汽车
+-------+-------+
| Name | Model |
+-------+-------+
| Bob | Camry |
| Bob | Civic |
| Bob | Prius |
| John | Camry |
| John | Civic |
| John | Prius |
| Kevin | Civic |
| Kevin | Focus |
| Mark | Civic |
| Lisa | Focus |
| Lisa | Civic |
+-------+-------+
这个查询给了我所有拥有与Lisa
完全相同的汽车的人,以及丽莎本人,这很好。
;with cte as (
select *
, cnt = count(*) over (partition by name)
from t
)
, matches as (
select x2.name
from cte as x
inner join cte as x2
on x.model = x2.model
and x.cnt = x2.cnt
and x.name = 'Lisa'
group by x2.name, x.cnt
having count(*) = x.cnt
)
select t.*
from t
inner join matches m
on t.name = m.name
结果:
+-------+-------+
| name | model |
+-------+-------+
| Lisa | Civic |
| Lisa | Focus |
| Kevin | Civic |
| Kevin | Focus |
+-------+-------+
如果我想找到拥有与Bob
相同车辆的所有人,我会重新运行查询,结果应该会给我John
。
现在,我有一个Java名称列表,每个名称都运行此查询。这真的很慢。反正有没有找到拥有相同汽车的所有人,并在单个数据库调用中将结果分组?
例如,使用第一个表。我可以运行一个将名称分组的查询。注意Mark
是如何消失的,因为他不拥有与其他人完全相同的汽车,只有一部分。
+-------+-------+-------+
| Name | Model | Group |
+-------+-------+-------+
| Bob | Camry | 1 |
| Bob | Civic | 1 |
| Bob | Prius | 1 |
| John | Camry | 1 |
| John | Civic | 1 |
| John | Prius | 1 |
| Kevin | Civic | 2 |
| Kevin | Focus | 2 |
| Lisa | Focus | 2 |
| Lisa | Civic | 2 |
+-------+-------+-------+
这个结果集也很好,我只需要知道谁属于哪个组,我可以稍后取车。
+-------+-------+
| Name | Group |
+-------+-------+
| Bob | 1 |
| John | 1 |
| Kevin | 2 |
| Lisa | 2 |
+-------+-------+
我需要以某种方式遍历一个名单列表,找到拥有相同汽车的所有人,然后将它们全部合并到一个结果集中。
答案 0 :(得分:2)
你可以这两种方式。一种方法是进行复杂的连接。另一种方式是捷径。只需将汽车聚合成一个字符串并比较字符串。
with nc as (
select n.name,
stuff( (select ',' + t.model
from t
where t.name = n.name
order by t.model
for xml path ('')
), 1, 1, '') as cars
from (select distinct name from t) n
)
select nc.name, nc.cars, dense_rank() over (order by nc.cars)
from nc
order by nc.cars;
这将创建一个列表,其中包含汽车的名称和列表作为逗号分隔列表。如果您愿意,可以加入原始表格以获取原始行。
答案 1 :(得分:1)
如果我们添加dense_rank()
,那么使用像上一个问题的vkp回答这样的连接方法也可以在这里工作:
with cte as (
select
name
, models = stuff((
select
',' + i.model
from t i
where i.name=t.name
order by 1
for xml path(''), type).value('.','varchar(max)')
,1,1,'')
from t
group by name
)
select
name
, models
, dr = dense_rank() over (order by models)
from cte
rextester:http://rextester.com/GTT11495
结果:
+-------+-------------------+----+
| name | models | dr |
+-------+-------------------+----+
| Bob | Camry,Civic,Prius | 1 |
| Mark | Civic | 2 |
| Kevin | Civic,Focus | 3 |
| Lisa | Civic,Focus | 3 |
+-------+-------------------+----+
答案 2 :(得分:0)
尝试使用othar样本数据。 它适用于所有情况。
declare @t table(Name varchar(50),Model varchar(50))
insert into @t values
('Bob','Camry')
,('Bob','Civic')
,('Bob','Prius')
,('Kevin','Civic')
,('Kevin','Focus')
,('Mark','Civic')
,('Lisa','Focus')
,('Lisa','Civic')
,('John','Camry')
,('John','Civic')
,('John','Prius')
declare @input varchar(50)='Bob'
;with
CTE1 AS
(
select name,model,ROW_NUMBER()over( order by name) rn
from @t
where name=@input
)
,cte2 as
(
select t.name,t.Model
,ROW_NUMBER()over(partition by t.name order by t.name) rn3
from @t t
inner JOIN
cte1 c on t.Model=c.model
where t.Name !=@input
)
select * from cte2 c
where exists(select rn3 from cte2 c1
where c1.name=c.name and c1.rn3=(select max(rn) from cte1)
)
答案 3 :(得分:-1)
Select *, row_number() Over(partition by Model order by name) as Group
from t
where model in(Select Model from t
Where name in('Bob', 'Lisa'))