如何为每一行执行语句并返回整个结果

时间:2017-03-15 21:58:43

标签: sql sql-server tsql

这是上一个问题的延续: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 |
+-------+-------+

我需要以某种方式遍历一个名单列表,找到拥有相同汽车的所有人,然后将它们全部合并到一个结果集中。

4 个答案:

答案 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'))