Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 查找具有匹配行的组_Sql_Sql Server - Fatal编程技术网

Sql 查找具有匹配行的组

Sql 查找具有匹配行的组,sql,sql-server,Sql,Sql Server,我有一张关于人、车主和他们拥有的汽车类型的表格 +-------+-------+ | Name | Model | +-------+-------+ | Bob | Camry | | Bob | Civic | | Bob | Prius | | Kevin | Civic | | Kevin | Focus | | Mark | Civic | | Lisa | Focus | | Lisa | Civic | +-------+-------+ 如果给我一个名字,

我有一张关于人、车主和他们拥有的汽车类型的表格

+-------+-------+
| Name  | Model |
+-------+-------+
| Bob   | Camry |
| Bob   | Civic |
| Bob   | Prius |
| Kevin | Civic |
| Kevin | Focus |
| Mark  | Civic |
| Lisa  | Focus |
| Lisa  | Civic |
+-------+-------+
如果给我一个名字,我如何找到其他拥有完全相同汽车的人?例如,如果我以Mark为目标,没有其他人只有Civic,因此查询将不返回任何结果。如果我以Lisa为目标,查询将返回

+-------+-------+
| Name  | Model |
+-------+-------+
| Kevin | Civic |
| Kevin | Focus |
+-------+-------+
因为凯文和丽莎的车一模一样。如果我以Kevin为目标,查询将返回Lisa

我创建了一个包含我的目标人物汽车的cte,但我不确定如何实现确切的匹配要求。我所有的尝试都会返回子集匹配的结果

with LisaCars as (
    SELECT Model FROM CarOwners WHERE Name = 'Lisa'
)
SELECT Name, Model
FROM CarOwners
WHERE Model in (SELECT * FROM LisaCars) AND Name != 'Lisa'
这个查询将返回所有拥有Civic或Focus的人,这不是我想要的

+-------+-------+
| Name  | Model |
+-------+-------+
| Bob   | Civic |
| Kevin | Civic |
| Kevin | Focus |
| Mark  | Civic |
+-------+-------+

一种方法是比较每个名称的有序连接模型值

with cte as (
select name,model,
     STUFF((
          SELECT ',' + t2.model
          FROM t t2
          WHERE t1.name=t2.name
          ORDER BY model
          FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') concat_value
from t t1 
) 
select distinct x2.name,x2.model
from cte x1
join cte x2 on x1.concat_value=x2.concat_value and x1.name<>x2.name
where x1.name='Kevin'

这将使用带有count的cte统计每个名称的行数

然后matches cte使用自联接,其中名称不匹配,模型匹配,每个名称匹配的模型数,其中一个名称是“Lisa”。having子句确保匹配行计数count*与name拥有的模型数匹配

匹配本身只返回每个人的姓名,因此我们返回源表t以获得每个匹配的完整模型列表

;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.name <> x2.name
      and 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
我们也可以在没有ctes的情况下编写,但这样做会让我们更难理解:

select t.*
from t 
  inner join (
    select x2.Name
    from (
      select *, cnt = count(*) over (partition by name) 
      from t 
      where name='Lisa'
      ) as x
      inner join (
      select *, cnt = count(*) over (partition by name) 
      from t
      ) as x2
        on x.name <> x2.name
       and x.model = x2.model
       and x.cnt   = x2.cnt 
    group by x2.name, x.cnt
    having count(*) = x.cnt
  ) as m 
    on t.name = m.name
试试这个

if object_id('tempdb.dbo.#temp') is not null
drop table #temp

create table #temp (name varchar(100),model varchar(100))

insert into #temp values('Bob','Camry')
insert into #temp values('Bob','Civic')
insert into #temp values('Bob','Prius')
insert into #temp values('Kevin','Focus')
insert into #temp values('Kevin','Civic')
insert into #temp values('Mark','Civic')
insert into #temp values('Lisa','Focus')
insert into #temp values('Lisa','Civic')

select * from (
select row_number() over(partition by name order by (select null)) as n,
row_number() over(partition by model order by (select null)) as m,*
from #temp) as a
where  n = m
order by name

由于您希望您的匹配准确无误,我们应该将每个人拥有的汽车数量添加为一个附加字段。假设您的表名为“owner”,则执行以下查询

select  *
        , (select COUNT(*)
            from #owners o2
            where o2.name = o1.name) as num
    from #owners o1
; with
    OwnedCount as (
        select  *
                , (select COUNT(*)
                    from #owners o2
                    where o2.name = o1.name) as num
            from #owners o1
    )
select *
    from OwnedCount o1
    inner join OwnedCount o2
        on o1.model = o2.model 
        and o1.num = o2.num
给我们桌子

+-------+-------+-----+
| Name  | Model | num |
+-------+-------+-----+
| Bob   | Camry | 3   |
| Bob   | Civic | 3   |
| Bob   | Prius | 3   | 
| Kevin | Civic | 2   |
| Kevin | Focus | 2   |
| Mark  | Civic | 1   |
| Lisa  | Focus | 2   |
| Lisa  | Civic | 2   |
+-------+-------+-----+
然后我们要将这个表连接到匹配模型和计数的表本身。我们使用CTE以便它读起来更好。下面的查询

select  *
        , (select COUNT(*)
            from #owners o2
            where o2.name = o1.name) as num
    from #owners o1
; with
    OwnedCount as (
        select  *
                , (select COUNT(*)
                    from #owners o2
                    where o2.name = o1.name) as num
            from #owners o1
    )
select *
    from OwnedCount o1
    inner join OwnedCount o2
        on o1.model = o2.model 
        and o1.num = o2.num
给我们这张桌子

+-------+-------+-----+-------+-------+-----+
| Name  | Model | num | Name  | Model | num |
+-------+-------+-----+-------+-------+-----+
| Bob   | Camry | 3   | Bob   | Camry | 3   |
| Bob   | Civic | 3   | Bob   | Civic | 3   |
| Bob   | Prius | 3   | Bob   | Prius | 3   |
| Kevin | Civic | 2   | Kevin | Civic | 2   |
| Kevin | Civic | 2   | Lisa  | Civic | 2   |
| Kevin | Focus | 2   | Kevin | Focus | 2   |
| Kevin | Focus | 2   | Lisa  | Focus | 2   |
| Mark  | Civic | 1   | Mark  | Civic | 1   |
| Lisa  | Civic | 2   | Kevin | Civic | 2   |
| Lisa  | Civic | 2   | Lisa  | Civic | 2   |
| Lisa  | Focus | 2   | Kevin | Focus | 2   |
| Lisa  | Focus | 2   | Lisa  | Focus | 2   |
+-------+-------+-----+-------+-------+-----+
最后,按所需名称筛选结果

declare @given_name varchar(32) = 'Lisa'
; with
    OwnedCount as (
        select  *
                , (select COUNT(*)
                    from #owners o2
                    where o2.name = o1.name) as num
            from #owners o1
    )
select o2.name, o2.model
    from OwnedCount o1
    inner join OwnedCount o2
        on o1.model = o2.model 
        and o1.num = o2.num
    where o1.name = @given_name
        and o2.name <> @given_name

试试这个,我认为只需一个分区函数,代码就简单多了

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

    declare @input varchar(50)='Lisa'

    ;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)
)

所以你想要完全匹配,而不是部分匹配?i、 e.只有当一个人拥有与被询问人完全相同的汽车时才可以?耶。我的示例查询已经提供了部分匹配。@很乐意提供帮助!是否仍然需要将x.name='Lisa'更改为名称列表,然后接收按完全相同的汽车所有权划分的结果集?现在,我用Java中的循环调用这个查询,传递每个名称。感觉效率太低了。嗨,Zim,我在这里发布了一个新问题和我想要的结果,希望你能继续拯救我的一天。我也会查看你的链接。