SQL -- Using IN over tables joined on multiple-row key
Alright. I've got a small set of sample tables set up. I'll just give the example because it's the best way I can communicate the issue.
Certs Table:
WorkerId Name Version
----------- -------------------------------- -----------
1 Construction 1
1 Construction 2
1 Demolition 1
1 Fusion 1
5 Fusion 1
4 Demolition 1
4 Demolition 2
CertDesc Table (Version, Name form Primary Key):
Name Version Description
-------------------------------- ----------- -----------------------------------------------------------------------------------------
Construction 1 Basic Construction -- Required for all construction workers.
Construction 2 Full Construction -- Required for all construction managers.
Demolition 开发者_开发知识库 1 Demolition -- Explosives -- Required for demolition managers.
Fusion 1 Fusion System Control -- Includes catastrophic super-criticality recovery.
Demolition 2 Large Scale Demolition -- Basic fission knowledge with full chemical cert.
Now. I want to get a list of all CertDesc rows such that WorkerId 1 does NOT have that cert. For X = 1, I should only get Demolition 2.
Here's the almost-there query that looks the best to me:
Select Distinct d.Name, d.Version, d.Description
From CertDesc d join Certs c on d.Name = c.Name and d.Version = c.Version
Where d.Name NOT IN (Select c2.Name
From Certs c2
Where c2.WorkerId = 1)
This query returns zero rows. The problem is that Demolition rows get excluded regardless of the version number. What I would like is to use IN with tuples:
Select Distinct d.Name, d.Version, d.Description
From CertDesc d join Certs c on d.Name = c.Name and d.Version = c.Version
Where (d.Name, d.Version) NOT IN (Select c2.Name, c2.Version)
From Certs c2
Where c2.WorkerId = 1)
Unfortunately, this is invalid in SQL Server. Does anybody know a good way to get at this?
SELECT *
FROM CertDesc cd
WHERE NOT EXISTS
(
SELECT NULL
FROM Certs c
WHERE c.WorkerId = 1
AND c.name = cd.name
AND c.version = cd.version
)
, or, if name
and version
are enough, just this:
SELECT name, version
FROM CertDesc
EXCEPT
SELECT name, version
FROM Certs
WHERE WorkerId = 1
Edit: This latter query only works with SQL-Server 2005.
Would something like this work:
select c.WorkerId, c.Name as workername, cd.version,
cd.name as certificatename
from certs as c
cross join certdesc as cd
where cd.version <> c.version
and cd.name <> c.name
order by c.workerid
To compare:
select c.WorkerId, c.Name as workername, cd.version,
cd.name as certificatename
from certs as c
cross join certdesc as cd
where cd.version = c.version
and cd.name = c.name
order by c.workerid
精彩评论