SQL:使用 MySQL 4 获取非耦合项列表
我不太擅长 SQL,并且遇到了一个不知道如何解决的问题。我已经阅读并重新阅读了一本有关 SQL 的书(O'Reilly 的《学习 SQL》)的部分内容,我希望这本书包含我需要的信息,但我还没有找到。
我的问题如下。我将使用一个简化的示例来使其更容易讨论。
我有三个表:car、rim 以及两者的组合:carRim。
car
carId
description
rim
rimId
description
carRim
carRimId
carId
rimId
price
在表 carRim 中,我有一个额外的价格属性,因为每种类型的汽车的轮辋价格可能不同。我的一个限制是每种类型的轮辋只能与每种类型的汽车连接一次。因此,所有车圈组合都应该是独一无二的。
如果我想给汽车添加轮辋,我需要一份尚未与该汽车连接的轮辋列表。为此,我认为我需要分别使用 rim 表和 carRim 表来获取已与我想要添加轮辋的汽车耦合的轮辋总列表和 carRim 列表。
我编写了(简单)查询来生成与特定汽车耦合的轮辋列表,在以下示例中为 carId 9 的汽车。
SELECT
*
FROM
rims
INNER JOIN
carRims
ON
carRims.rimId = rim.rimId
WHERE
carRims.carId = 9
但现在我需要以下轮辋列表:尚未耦合到特定汽车。问题是,如果我执行 LEFT OUTER JOIN,我得到的列表会被轮辋与其他汽车的耦合“污染”,因此“WHERE carRims.carId IS NULL”的过滤条件不起作用。
SELECT
*
FROM
rims
LEFT OUTER JOIN
carRims
ON
carRims.rimId = rim.rimId
WHERE
carRims.carId IS NULL
另一个挑战是我无法使用 MySQL 5 中的任何新语法,例如子查询,因为我的客户端正在使用 MySQL 4,目前无法升级。
这个问题的查询可以在MySQL 4中编写吗,我怀疑可以。
谢谢!
I'm not that good in SQL and I've come across a problem I don't know how to solve. I've read and re-read parts of a book about SQL (O'Reilly's Learning SQL) which I hoped would contain the information I needed but I haven't found it.
My problem is the following. I'll use a simplified example to make it easier to discuss.
I've got three tables, car, rim and the combination of the two: carRim.
car
carId
description
rim
rimId
description
carRim
carRimId
carId
rimId
price
In the table carRim I have an extra attribute of price, because the price of a rim is potentially different for every type of car. A constraint I have is that every type of rim should only be coupled once to every type of car. So all combinations of car-rim should be unique.
If I want to add a rim to a car I need a list of rims that are not yet coupled to that car. For this I think I need the rim table and the carRim table respectively for the total list of rims and the list of carRims that are already coupled to the car I want to add a rim to.
I've written the (simple) query to make the list of rims that are coupled to a specific car, in the following example the car with carId 9.
SELECT
*
FROM
rims
INNER JOIN
carRims
ON
carRims.rimId = rim.rimId
WHERE
carRims.carId = 9
But now I need the list of rims that are not yet coupled to a specific car. The problem is that if I do a LEFT OUTER JOIN the list I get is "tainted" with couplings of rims to other cars, so the filter condition of "WHERE carRims.carId IS NULL" does not work.
SELECT
*
FROM
rims
LEFT OUTER JOIN
carRims
ON
carRims.rimId = rim.rimId
WHERE
carRims.carId IS NULL
Another challenge is that I can't use any syntax new to MySQL 5, like subqueries, because my client is using MySQL 4 and can't upgrade at this time.
Can a query for this problem be written in MySQL 4, I suspect it can.
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
更新:
要将
NOT EXISTS
重写为LEFT JOIN / IS NULL
,您需要将所有条件放入ON连接的
子句:Update:
To rewrite the
NOT EXISTS
into aLEFT JOIN / IS NULL
, you'll need to put all conditions into theON
clause of the join:您可以在左外连接
ON
表达式中添加额外的条件。您想要的是carRims
中与您的rims
行相匹配的行,并且属于 9 号车,对吗?如果其他汽车还有其他
carRim
,它们将被ON
子句中的额外条件过滤掉。关于在
JOIN
或WHERE
子句中放置条件的问题:对于外部连接,将条件放置在何处很重要比较。 JOIN 子句中的条件用于测试一个表中的行是否与另一表中的行匹配。测试匹配后,我们对各个表中的行所做的操作取决于连接的类型。
对于外连接,即使
carRims
中没有匹配的行,我们也需要来自rims
的行。如果我们将 carID=9 条件放在WHERE
子句中会怎样?发生的情况如下:外连接返回
rims
中的所有行,其中carRims
中与rimID
匹配的行并且包含 具有虚假carID
值的行。仅当没有汽车与给定轮辋匹配时,它才会对c.*
列使用NULL。但是,
WHERE
子句会消除连接产生的所有行,除非carID
的值为 9。这意味着它还会消除carID
所在的位置NULL,即它消除任何与任何汽车都不匹配的轮辋的行。因此,结果等同于INNER JOIN
的结果。因此,在将行连接到
rims
之前,我们需要从carRims
中排除具有错误 carID 的行。这是关于该单个表中的哪些行可以与另一个连接表中的行匹配的条件。
许多书籍说您可以在
ON
子句和WHERE
子句之间自由混合条件。但并非所有情况都是如此。它适用于 INNER JOIN,因为两种方式的最终结果都是相同的。它也适用于仅适用于左连接中左表的条件,例如:对于左外连接中右表的条件,它确实不管你把条件放在哪里。
对您所说的内容再发表一条评论:
那么您是否已在
carRims(carId,rimId)
上声明了UNIQUE
约束?You can put extra conditions in a left outer join
ON
expression. What you want is a row fromcarRims
that matches yourrims
row, and belongs to car number 9, right?If there are other
carRims
for other cars, they'll be filtered out by the extra condition in theON
clause.Re your questions about where to put a condition, in the
JOIN
or in theWHERE
clause:For outer joins, it matters where you put the comparison. The condition in a JOIN clause is for testing whether rows in one table match rows in the other table. What we do with the rows from the respective tables after we test the match depends on the type of join.
For an outer join, we want rows from
rims
even if there's no matching row incarRims
. What if we were to put the carID=9 condition in theWHERE
clause?Here's what happens: the outer join returns all rows from
rims
, with rows fromcarRims
that match therimID
and includes the rows with spuriouscarID
values. Only if none of the cars match a given rim does it use NULL for thec.*
columns.But then the
WHERE
clause eliminates all the rows resulting from the join, unlesscarID
is the value 9. That means it also eliminates wherecarID
is NULL, that is it eliminates rows for any rim matches none of the cars. Therefore the result becomes equivalent to the result of anINNER JOIN
.So we need to exclude rows from
carRims
with the wrong carID before the rows are joined torims
.It's a condition on what rows from that individual table can match rows in the other joined table.
Many books say you can freely mix conditions between the
ON
clause and theWHERE
clause. But this isn't true in all cases. It works forINNER JOIN
, because the end result is the same either way. It also works for a condition that applies only to the left table in a left join, for example:For a condition on the right table in a left outer join, it does matter where you put the condition.
One more comment on something you said:
So have you declared a
UNIQUE
constraint oncarRims(carId,rimId)
?(我需要更多的空间来详细说明,评论没有足够的字符)
@Bill Karwin
您提供的查询是我的问题的正确答案。谢谢!
我想要的是未连接到特定汽车的行(轮辋)列表。
在《学习 SQL》一书中,我读到查询中过滤器和连接条件的位置并不重要。他们给出了一个内部联接的示例,其中有 1 个联接条件(在 ON 子句之后)和 1 个过滤条件(在 WHERE 子句之后)。他们证明,无论将这两个条件放在 ON 子句之后还是 WHERE 子句之后,实际上并不重要。
考虑到这一点,我不明白你的解决方案的一部分。如果条件
和条件
都存在,那不是会导致结果集为空吗?因为没有字段可以同时为 9 和 NULL 对吗?
我的怀疑是:JOIN 子句中的条件是位置限制的,并且您不能只是将它们放在WHERE 子句中。
这是正确的吗?
(I needed some more room to elaborate, a comment did not have enough characters)
@Bill Karwin
The query you've provided is the correct answer to my problem. Thanks!
What I wanted was a list of rows (rims) that are not connected to a specific car.
In the "Learning SQL" book I read that the location of filter and join conditions in the query did not matter. They gave an example of an inner join where there was 1 join condition (after the ON clause) and 1 filter condition (after the WHERE clause). They demonstrated that whether you put those two conditions after the ON clause or after the WHERE clause effectively did not matter.
With that in mind I don't understand a part of your solution. If the condition
and the condition
are both present, doesn't that result in an empty resultset? Because no field can be 9 and NULL simultaneously right?
My suspicion then is: the conditions in the JOIN clause are location-bound, and you can't just put them in the WHERE clause.
Is this correct?