我有两个表,House
和Person
。对于House中的任何行,Person
中可以有0,1或许多对应的行。但是,在这些人中,最多一个人的状态为“ACTIVE”,其他人的状态均为“CANCELLED”。
e.g。
SELECT * FROM House LEFT JOIN Person ON House.ID = Person.HouseID
House.ID | Person.ID | Person.Status
1 | 1 | CANCELLED
1 | 2 | CANCELLED
1 | 3 | ACTIVE
2 | 1 | ACTIVE
3 | NULL | NULL
4 | 4 | CANCELLED
我想过滤掉已取消的行,并得到类似的内容:
House.ID | Person.ID | Person.Status
1 | 3 | ACTIVE
2 | 1 | ACTIVE
3 | NULL | NULL
4 | NULL | NULL
我通过以下子选择实现了这个目标:
SELECT *
FROM House
LEFT JOIN
(
SELECT *
FROM Person
WHERE Person.Status != "CANCELLED"
) Person
ON House.ID = Person.HouseID
...哪个有效,但会破坏所有索引。有没有更好的解决方案呢?
我正在使用MySQL并且所有相关列都已编入索引。 EXPLAIN
possible_keys
中没有列出任何内容。
感谢。
答案 0 :(得分:4)
怎么样:
SELECT *
FROM House
LEFT JOIN Person
ON House.ID = Person.HouseID
AND Person.Status != "CANCELLED"
答案 1 :(得分:2)
您是否可以控制数据库结构?如果是这样,我认为您可以通过从Person表中删除列Status并将一个ActivePersonID列添加到House表中来更好地表示您的数据。这样,您可以从Person中删除所有冗余的CANCELED值,并消除应用程序或存储过程代码,以确保每个家庭只有一个人处于活动状态。
此外,您可以将查询表示为
SELECT * FROM House LEFT JOIN Person ON House.ActivePersonID = Person.ID
答案 2 :(得分:1)
使用:
SELECT *
FROM HOUSE h
LEFT JOIN PERSON p ON p.houseid = h.id
AND p.status = 'ACTIVE'
答案 3 :(得分:0)
这是在SQL Server中,但逻辑似乎有效,上面回应了Chris:
declare @house table
(
houseid int
)
declare @person table
(
personid int,
houseid int,
personstatus varchar(20)
)
insert into @house (houseid) VALUES (1)
insert into @house (houseid) VALUES (2)
insert into @house (houseid) VALUES (3)
insert into @house (houseid) VALUES (4)
insert into @person (personid, houseid, personstatus) VALUES (1, 1, 'CANCELLED')
insert into @person (personid, houseid, personstatus) VALUES (2, 1, 'CANCELLED')
insert into @person (personid, houseid, personstatus) VALUES (3, 1, 'ACTIVE')
insert into @person (personid, houseid, personstatus) VALUES (1, 2, 'ACTIVE')
insert into @person (personid, houseid, personstatus) VALUES (4, 4, 'CANCELLED')
select * from @house
select * from @person
select *
from @house h LEFT OUTER JOIN @person p ON h.houseid = p.houseid
AND p.personstatus <> 'CANCELLED'