仅基于不同的对应实体选择公共实体

时间:2016-09-22 23:09:59

标签: sql sql-server select join sql-server-2012

3表

客户 -

CID    Name
1      Ana
2      Bana
3      Cana

ClientProgram(桥接表) -

CID   PID
1      4
1      5
1      8
2      10

计划 -

PID   Program
4      X
5      Y
8      Z
10     G

期望输出:

Name    Program
Ana       X
Ana       Y

我想只提取我选择的不同Clients中常见/存在的Programs(在这种情况下说X和Y)

查询尝试:

  SELECT 
        C.Name
        ,P.Program
    FROM ClientProgram CP
    INNER JOIN Client C
        ON CP.CID=C.CID
    INNER JOIN Program P
        ON CP.PID=P.PID
    INNER JOIN ClientProgram CP1
        ON CP.CID=CP1.CID

    WHERE P.Program = 'X' OR P.Program = 'Y'
        AND CP.CID = CP1.CID

然而,这不会吸引所有客户端,而不仅仅是那些存在于多个程序中的客户端。

2 个答案:

答案 0 :(得分:1)

;WITH cte AS (
    SELECT
       c.Name
       ,p.Program
       ,COUNT(*) OVER (PARTITION BY c.CID) as ProgramCount
    FROM
       Program p
       INNER JOIN ClientProgram cp
       ON p.PID = cp.PID
       INNER JOIN Client c
       On cp.CID = c.CID
    WHERE
       p.Program IN ('X','Y')
)

SELECT Name, Program
FROM
    cte
WHERE
    ProgramCount > 1

如果PID在程序中不是唯一的,或者如果ClientProgram中的CID与PID的组合不唯一,则使用COUNT(*)将是一个问题。但是我会根据我所看到的情况假设唯一性。

如果没有,你可以选择这样的路线:

;WITH cte AS (
    SELECT
       cp.CID
    FROM
       Program p
       INNER JOIN ClientProgram cp
       ON p.PID = cp.PID
    WHERE
       p.Program IN ('X','Y')
    GROUP BY
       cp.CID
    HAVING
       COUNT(DISTINCT p.PID) > 1
)

SELECT
    c.Name
    ,p.Program
FROM
    cte t
    INNER JOIN Client c
    ON t.CID = c.CID
    INNER JOIN ClientProgram cp
    ON t.CID = cp.CID
    INNER JOIN Program p
    ON cp.PID = p.PID
    AND p.Program IN ('X','Y')

答案 1 :(得分:0)

这是一种关于这样做的方式。可能是一个更好的方法,但这将做到这一点。我通过脚本中的临时表,以防其他人想要改进。可以做一个临时表而不是CTE。

create table #client(cid int,name varchar(20))
create table #clientprogram (cid int, pid int)
create table #program( pid int, program varchar(20))

insert into #client
values(1,'Ana')
    ,(2,'Bana')
    ,(3,'Cana')

insert into #clientprogram
values (1,4)
        ,(1,5)
        ,(1,8)
        ,(2,10)
        ,(2,4)

insert into #program
values (4,'x')
    ,(5,'y')
    ,(8,'z')
    ,(10,'g')

WITH CHECKPLEASE AS(
Select c.Name,ISNULL(p.Program,p2.PRogram) Program
from #client c
inner join #clientprogram cp
    on c.CID = cp.CID
left join #program p
    on cp.PID = p.PID
    and p.PRogram = 'X'
left join #program p2
    on cp.PID = p2.PID
    and p2.Program = 'Y'
where ISNULL(p.Program,p2.PRogram) is not null
)

Select * 
From CHECKPLEASE
where Name in (
SELECT Name
From CHECKPLEASE
group by Name
having COUNT(*) > 1)