我最近在大约15年不活动后开始重新学习SQL语法。我熟悉旧的ANSI-89 JOIN语法,新语法正在习惯。
无论如何,我要做的是计算两个查询中的元素数量,如果它们相等,则为行设置一个标志。
这是我的表结构:
PERSON
ID -- unique ID for the person
HOUSE
ID -- unique ID for the house
PersonID -- person who owns the house
BATHROOM
HouseID -- House that the room is in
Type -- The type of bathroom - ensuite, powder, etc.
Pieces -- The number of pieces in the bathroom.
行。所以我想在PERSON
表中添加一个新字段,用于跟踪所有房屋的所有浴室是否为3件套房。 (不要问为什么 - 这显然是制造场景,但它很好地映射到我试图解决的现实世界场景。)
所以,我从以下开始:
ALTER TABLE person ADD All_Three tinyint(1) NOT NULL DEFAULT 1 AFTER ID;
现在我有了这个字段,它默认为1
。
所以,我需要运行一个填充它的查询。这是我的尝试:
UPDATE IGNORE person,
(SELECT COUNT(*) AS count
FROM house, bathroom
WHERE house.PersonID=person.ID
AND bathroom.HouseID=house.ID
AND bathroom.Type='ensuite'
AND bathroom.Pieces=3) num_three,
(SELECT COUNT(*) AS count
FROM house, bathroom
WHERE house.PersonID=person.ID
AND bathroom.HouseID=house.ID) all_bathrooms
SET person.All_Three=2
WHERE num_three.count=all_bathrooms.count;
这对我来说似乎很合乎逻辑;
第一个子查询计算具有三个部分的套间数,第二个子查询计算浴室总数。如果他们是平等的(即该人拥有的所有浴室都是3件套房),那么我们可以设置All_Three
字段。
此操作失败并显示错误
ERROR 1054 (42S22): Unknown column 'person.ID' in 'where clause'
那么,如何在子查询中引用person
?我试过别名,但也失败了同样的错误。
编辑: 事实证明我的目标是错误的。我需要做的是设置all_three
字段,如果该人拥有的每个房屋仅包含3件套房,并且每个房屋至少有一个套房(显然必须是3件)
答案 0 :(得分:1)
为此,我们将生成符合条件PERSON.ID
的{{1}}的包含列表,BATHROOM.Type = 'ensuite' and BATHROOM.Pieces = 3
的排除列表不符合条件PERSON.ID
}),并使用BATHROOM.Type != 'ensuite' or BATHROOM.Pieces != 3
/ in
过滤更新:
not in
答案 1 :(得分:1)
您想要更新表格中的记录。单个表中更新的语法是:
UPDATE tablename SET ... WHERE ...
相反,您尝试使用两个所谓的派生表(select语句)加入表:
UPDATE tablename, (query 1), (query 2) SET ... WHERE ...
这将交叉加入这三个部分。这是旧的以逗号分隔的连接语法总是会发生的事情;您将所有记录相互组合。然后,您通常会在WHERE子句中命名您的连接条件,以从结果中删除记录。所以使用新的sytax,这将是:
UPDATE tablename CROSS JOIN (query 1) CROSS JOIN (query 2) SET ... WHERE ...
您为两个派生查询的连接提供了条件,但这会将其连接转换为内连接:
UPDATE tablename CROSS JOIN (query 1) INNER JOIN (query 2) ON ... SET ...
您还尝试将表人与派生表相关联。但是在两个派生表查询中,不知道外部的其他表或派生表。您无法在派生表查询中引用表人员。
不允许:
UPDATE tablename CROSS JOIN (select something from othertable where othertable.colx = tablename.coly) SET ...
相反:
UPDATE tablename INNER JOIN (select something, colx from othertable where ...) AS query1 ON query1.colx = tablename.coly) SET ...
但如上所述,您无论如何都不想更新多个表,因此无需加入。与派生表不同,普通子查询可以与外表不相关。您可以在WHERE子句中使用此类子查询:
UPDATE person
SET ...
WHERE
(select count(*) from ... where ... = person.id) =
(select count(*) from ... where ... = person.id)
关于你在编辑中澄清的问题:你想找到只有三件套浴室的房子的人。换句话说:所有拥有房屋的人(简单的EXISTS或IN条款),但没有其他浴室类型的房子或另一个浴室的批发房间(更多的'更多)复杂的NOT EXISTS条款)。
在你的NOT EXIST条款中,对于一个人不合适的房屋你再次有一个NOT EXISTS条款(如果这个房子没有房间,如果可能的话)和一个EXISTS条款(对于一个浴室的情况)那个房子里有错误的类型或件号。)
UPDATE person p
SET all_three = 2
WHERE id IN (select personid from house)
AND NOT EXISTS -- an unsuitable house
(
select *
from house h
where not exists -- a bathroom for that house
(
select *
from bathroom b
where b.houseid = h.id
)
or exists -- bad bathroom for that house
(
select *
from bathroom b
where b.houseid = h.id
and (b.type <> 'ensuite' or b.pieces <> 3)
)
where h.personid = p.id
);
顺便说一句,是否使用(NOT)EXISTS或(NOT)IN条款主要是个人品味问题。