SQL:查询返回互补值

时间:2016-03-10 17:17:17

标签: mysql sql-server

这是我的问题的简化版本。我有一个包含名称的表和一个包含有限时隙列表的表(比如一周中的几天)链接器表链接这两个表。使用这三个表的简单内连接,我可以显示每个人的可用性:

| id   | day |
|******|*****|
| 1    | MO  |
| 1    | TU  |
| 1    | WE  | 
| 1    | TH  |
| 1    | FR  |
| 1    | SU  | 
| 2    | MO  |  
| 2    | TU  |
| 2    | WE  | 
| 2    | FR  |
| 2    | SA  |
| 2    | SU  | 

由于大多数用户大多数时间都可以使用,因此我想运行一个查询来显示他们的时间:

| id   | day |
|******|*****|
| 1    | SA  |
| 2    | TH  |

我知道如何使用外连接和WHERE找到集合的补集... IS NULL,但我看不出如何将这些互补值链接到个人。这可能是非常明显的事情,但我已经坚持了几个小时。请注意,我无法控制数据库设计。

编辑:我为我的问题不够清楚而道歉。

我会再试一次。

表个人具有以下列:id(PK),first_name,last_name,DOB等。 表时隙具有以下列:id(PK),时间段 链接器表个人时间段具有以下列:id(PK),idindividual(FK),idtimeslot(FK)

以下查询返回个人可用时的概述。

SELECT 
i.first_name, i.last_name, t.timeslot
FROM 
individuals as i 
inner join individualstimeslots as it on it.idindividual = i.id
inner join timeslots as t on t.id = it.idtimeslot

(结果类似于上面的第一个表,除了名字和姓氏而不是id)

如果我想知道id 1的个人何时不可用,我可以使用以下查询:

SELECT 
i.first_name, i.last_name, t.timeslot, t2.timeslot as all
FROM 
individuals as i 
inner join individualstimeslots as it on it.idindividual = i.id and i.id = 1
inner join timeslots as t on t.id = it.idtimeslot
right outer join timeslots as t2 on t.id = t2.id

具有以下结果:

| JOHN | DOE | MO | MO | 
| JOHN | DOE | TU | TU | 
| JOHN | DOE | WE | WE | 
| JOHN | DOE | TH | TH | 
| JOHN | DOE | FR | FR | 
|      |     |    | SA | 
| JOHN | DOE | MO | SU | 

如果我只想显示John Doe不可用的时间段,我可以在查询中添加以下条件:

WHERE t.timeslot IS NULL

结果:

|      |     |    | SA | 

然而,此结果并未明确指代id = 1的个人。 我所追求的是一个查询,只有当所有(选定)个人

时才会这样做并显示:

| JOHN | DOE | SA |
| JANE | DOE | TH |

希望我现在让自己更清楚了。

2 个答案:

答案 0 :(得分:0)

不幸的是,我不认为你可以通过一个简单的查询来解决这个问题(我想证明这是错误的)。 但是您可以轻松地创建一个循环遍历所有(相关)个体的游标,并且每个人都执行外部联接查询。然后,您可以将结果插入临时表中,并从最后选择。 你已经标记了mysql和sql-server,所以我不知道你使用哪种语言。但这两种情况都有可能:)

答案 1 :(得分:0)

此查询似乎可以执行您想要的操作。你甚至可以在没有CTE的情况下重写它,但我认为它更清楚。

INSERT INTO dbo.days (namedays) VALUES 
('Monday'),
('Tuesday'),
('Wednesday'),
('Thursday'),
('Friday'),
('Saturday'),
('Sunday')

INSERT INTO availability (ID,namedays) VALUES
(1,'Monday'),
(1,'Tuesday'),
(1,'Thursday'),
(2,'Monday'),
(2,'Saturday')

;WITH CTE AS (
SELECT DISTINCT a.ID AS ID ,d.namedays FROM availability a
CROSS JOIN dbo.days d)

SELECT CTE.ID, CTE.namedays FROM CTE
LEFT OUTER JOIN availability a
ON a.ID = CTE.ID AND a.namedays = CTE.namedays
WHERE a.ID IS NULL