我正在构建一个包含顾问档案的系统。在该系统中,每位顾问都可以选择他或她拥有的认证。现在,当顾问拥有一定数量的认证时,我正在扩展系统以包含标题。有趣的表是:
Person(stores ID, Firstname etc. of a person)
Certification(stores ID, Name of a certification)
PersonCertification(stores PersonID and CertificationID as a linking table (name?) )
Title(stores the title: ID, Shortname and Fullname)
TitleCertifications(stores which certifications is needed for a title)
举个例子,假设我们有一个名为MCSA的ID为1的标题。此标题所需的认证是ID为1和2的认证.TitleCertifications-table可能如下所示:
TitleID | CertificationID
1 | 1
1 | 2
如果顾问同时拥有身份证1和身份证2的证明,他或她将被授予身份证1的MCSA头衔。如果顾问没有任何证明,则他不会获得此头衔。
我遇到的问题是我不知道如何检查用户是否具有TitleCertifications表中定义的所有必需认证。我已经开始这样做了,但是如果这个人拥有所需的所有证明,它就没有任何检查。
SELECT t.Fullname
FROM Title t
JOIN TitleCertifications tc ON t.ID = tc.TitleID
JOIN PersonCertification pc ON tc.CertificationID = pc.CertificationID
上面的查询结果将为每一行产生一个与认证匹配的titlename,例如,如果用户拥有获得标题的三个必需认证中的两个,它将产生两行。
是否有人知道如何编写符合所需认证的查询,并且只有在用户拥有所有标题所需的认证时才给出答案?
我使用的是使用T-SQL的SQL Server 2012(如果重要的话,在Azure中)。
很抱歉写了一些模糊的,我不确定所有的英文术语。
答案 0 :(得分:2)
尝试这种方法:
;with pc as (
select p.personid, tc.titleid, count(*) as cnt_pc
from person p
inner join personcertification pc on p.personid = pc.personid
inner join titlecertifications tc on pc.certificationid = tc.certificationid
group by p.personid, tc.titleid
),
tc as (
select t.titleid, count(*) as cnt_tc
from title t
inner join titlecertifications tc on t.titleid = tc.titleid
group by t.titleid
)
select p.firstname, t.shortname
from pc
inner join tc on pc.titleid = tc.titleid
inner join person p on pc.personid = p.personid
inner join title t on pc.titleid = t.titleid
where cnt_pc = cnt_tc
一般的想法是选择需要特定标题的证书数量,以及该标题所拥有的证书数量 - 如果匹配的话,我们认为其中也有一个标题。计数可以通过多种方式完成。
答案 1 :(得分:1)
有很多方法可以做到这一点。这是一个:
select p.ID, p.Name, tcount.ID
from Person p
inner join
(
-- Get the count of certs for each title for each person
select pc.PersonID, t.ID TitleId, count(*) CertCount
from PersonCertification pc
inner join Certification c on c.ID = pc.CertificationID
inner join TitleCertification tc on tc.CertificationId = c.ID
inner join Title t on t.ID = tc.TitleID
group by pc.PersonID, t.ID
) cntByTitle on cntByTitle.PerdonID = p.ID
left outer join
(
select t.TitleID, count(*) CertCount
from Title t
inner join TitleCertification tc on tc.TitleId = t.ID
group by t.ID
) tcount on tcount.TitleID = cntByTitle.TitleID and tcount.PersonID = p.ID
and tcount.CertCount = cntByTitle.CertCount
注意:cntByTitle子查询可能需要是左外部而不是内部联接:如果一个人必须使用Certs,那么我认为除非你将它设置为左外部,否则它们不会被返回。我还假设所有索引都已到位。如果Person没有标题,则查询将返回Person.ID并返回null。
您可以将其包装为View,然后在更直接的查询中使用View。
答案 2 :(得分:0)
如果您使用的是SQL Server 2012
,则可以使用IIF
功能。
SELECT IIF(TitleID = '1' AND CertificationID= '1', 1, 0) AS fullName, *
FROM Title t
...?我想:/
编辑:新的CASE选项
SELECT' name' 案件 当TitleId =' 1' AND CertificateId =' 1'那么MCSA = 1 ELSE MCSA = 0 结束 FROM' table'
答案 3 :(得分:0)
COUNT(columnName)不会计算空值。
以下查询使用左连接来获取此人没有的证书的空值
SELECT MAX(Title.FullName)
FROM Title
INNER JOIN TitleCertifications
ON TitleCertifications.TitleID = TitleCertifications.TitleId
LEFT JOIN PersonCertifications
ON PersonCertifications.CertificationId = TitleCertifications.CertificationId
WHERE PersonCertifications.PersonId = @Person
AND TitleCertifications.TitleId = @Title
HAVING COUNT(TitleCertifications.CertificationId) = COUNT(PersonCertifications.CertificationId)
答案 4 :(得分:0)
这应该给你一些方向sql fiddle link
DECLARE @Person TABLE
(
Id INT,
FirstName VARCHAR (20)
)
DECLARE @Certification TABLE
(
Id INT,
CertificateName VARCHAR (20)
)
DECLARE @Title TABLE
(
TitleId INT,
Name VARCHAR (20)
)
DECLARE @TitleCertifications TABLE
(
TitleId INT,
CertificateId INT
)
DECLARE @PersonCertification TABLE
(
PersonId INT,
CertificateId INT
)
INSERT INTO @person VALUES (1, 'tyy'),(2,'Jon'), (3, 'James')
INSERT INTO @Certification VALUES (1, 'MSCA PreReq 1'),(2,'MSCA PreReq 2'),(3,'MSCC PreReq 1')
INSERT INTO @Title VALUES (1, 'MSCA'),(2,'MSCC')
INSERT INTO @TitleCertifications VALUES (1, 1),(1,2), (2,3)
INSERT INTO @PersonCertification VALUES (1, 1),(1,2), (2,1), (3,3)
SELECT * INTO #FlattenedTitleCerts
FROM
(SELECT g.TitleId, g.Name, STUFF( (SELECT ',' + CAST(CertificateId AS VARCHAR(10))
FROM @TitleCertifications v
WHERE v.TitleId = g.TitleId
ORDER BY CertificateId
FOR XML PATH('')),1, 1, '') Combination
FROM @Title g
) t
SELECT * INTO #FlattenedPersonCerts
FROM
(
SELECT g.Id, g.FirstName, STUFF( (SELECT ',' + CAST(CertificateId AS varchar(10))
FROM @PersonCertification v
WHERE v.PersonId = g.id
ORDER BY CertificateId
FOR XML PATH('')),1, 1, '') Combination
FROM @Person g
) t
--SELECT * FROM #FlattenedTitleCerts
--SELECT * FROM #FlattenedPersonCerts
--to get title
SELECT fpc.FirstName Name,
ftc.Name Title
FROM #FlattenedPersonCerts fpc
LEFT JOIN #FlattenedTitleCerts ftc ON ftc.Combination = fpc.Combination
DROP TABLE #FlattenedTitleCerts
DROP TABLE #FlattenedPersonCerts