所以,我现在有三张桌子。 reports
,berries
和melons
。我设置了这样的查询,它让我得到了我想要的东西。
SELECT
rpt.*,
ber.shipper, ber.po, ber.commodity, ber.label
FROM reports rpt
LEFT JOIN berries ber ON rpt.inspection_number = ber.report_key
LEFT JOIN melons mel ON rpt.inspection_number = mel.report_key
WHERE rpt.status='1' OR rpt.status='0'
ORDER BY rpt.inspection_number DESC
我得到了预期的回报
key | role | region | inspection_type | inspection_number | shipper | po | commodity | label
3 | NULL | Seattle | melons | 5555 | Shipper1 | PO2 | Commodity2 | Label2
2 | NULL | Seattle | berries | 1023 | Shipper1 | PO1 | Commodity1 | Label1
如果我从我的陈述中删除LEFT JOIN melons mel ON rpt.inspection_number = mel.report_key
,我会得到完全相同的东西......我从未提及melons
??
如果我修改并使用JOIN
代替浆果
SELECT
rpt.*,
ber.shipper, ber.po, ber.commodity, ber.label
FROM reports rpt
JOIN berries ber ON rpt.inspection_number = ber.report_key
WHERE rpt.status='1' OR rpt.status='0'
ORDER BY rpt.inspection_number DESC
它产生我预期的应该!
key | role | region | inspection_type | inspection_number | shipper | po | commodity | label
2 | NULL | Seattle | berries | 1023 | Shipper1 | PO1 | Commodity1 | Label1
但是试图修改我的SQL语句......
SELECT
rpt.*,
ber.shipper, ber.po, ber.commodity, ber.label
mel.shipper, mel.po, mel.commodity, mel.label
FROM reports rpt
JOIN berries ber ON rpt.inspection_number = ber.report_key
JOIN melons mel ON rpt.inspection_number = mel.report_key
WHERE rpt.status='1' OR rpt.status='0'
ORDER BY rpt.inspection_number DESC
Nets me ....
MySQL returned an empty result set (i.e. zero rows). ( Query took 0.0011 sec )
给了我大中指。我勒个去?有人可以解释我显然做错了什么,以及如何解决它?
答案 0 :(得分:5)
这不是那么复杂。你的第一个问题,你是加入反对梅尔但从未做过任何事情,所以你只得到贝尔的数据。你的最后一个查询更接近,但因为你内心加入浆果和甜瓜而且你没有任何两个的报告,你就得不到任何结果。但答案更接近你在第二个查询中所做的事情,我认为你想要的是:
SELECT
rpt.*,
COALESCE(ber.shipper, mel.shipper) AS shipper,
COALESCE(ber.po, mel.po) AS po,
COALESCE(ber.commodity, mel.commodity) AS commodity,
COALESCE(ber.label, mel.label) AS label
FROM reports rpt
LEFT JOIN berries ber ON rpt.inspection_number = ber.report_key
LEFT JOIN melons mel ON rpt.inspection_number = mel.report_key
WHERE rpt.status='1' OR rpt.status='0'
ORDER BY rpt.inspection_number DESC
这个查询说,给我一些有浆果或甜瓜连接的行,但是对于它们共有的列,给我任何一个存在的。我们没有特别的原因,我们先服用ber。
假设这两个表是互斥的,我认为这可以做你想要的。
编辑:根据@MarcusAdams在下面指出的内容,如果有一些令人讨厌的水果表,可以将其重写为使用UNION
:
SELECT report_key, shipper, po, commodity, label FROM berries
UNION
SELECT report_key, shipper, po, commodity, label FROM melons
UNION
SELECT report_key, shipper, po, commodity, label FROM ...
...
此查询将为您提供一些方便的功能,您可以在以后将其用作子查询(或视图)。您也可以硬编码原始名称,如下所示:
SELECT report_key, shipper, po, commodity, label, 'berries' AS type FROM berries
UNION
SELECT report_key, shipper, po, commodity, label, 'melons' FROM melons
UNION
SELECT report_key, shipper, po, commodity, label, '...' FROM ...
...
然后在原始查询中使用它,你可以这样嵌入它:
SELECT *
FROM reports rpt,
JOIN (SELECT report_key, shipper, po, commodity, label, 'berries' AS type FROM berries
UNION
SELECT report_key, shipper, po, commodity, label, 'melons' FROM melons
UNION
SELECT report_key, shipper, po, commodity, label, '...' FROM ...
...) fruits ON rpt.inspection_number = fruits.report_key
WHERE rpt.status='1' OR rpt.status='0'
ORDER BY rpt.inspection_number DESC
答案 1 :(得分:3)
Daniel Lyons提供的以下查询效果很好,但我想稍微讨论一下,并且严格用于学术目的,提供另一种解决方案,可能会更加优化。
这是丹尼尔的询问:
SELECT
rpt.*,
COALESCE(ber.shipper, mel.shipper) AS shipper,
COALESCE(ber.po, mel.po) AS po,
COALESCE(ber.commodity, mel.commodity) AS commodity,
COALESCE(ber.label, mel.label) AS label
FROM reports rpt
LEFT JOIN berries ber ON rpt.inspection_number = ber.report_key
LEFT JOIN melons mel ON rpt.inspection_number = mel.report_key
WHERE rpt.status='1' OR rpt.status='0'
ORDER BY rpt.inspection_number DESC
这个查询效果很好,只有两个水果,它相当优化。仍然因为报告是互斥的,所以查询正在尝试额外的连接而不是必要的。例如,如果报告记录已经加入浆果记录,我们知道它不会加入甜瓜记录,但MySQL不知道。相反,MySQL将进行另一次查找以尝试连接到瓜表,即使找不到相应的记录。
只有两个连接,一半的连接尝试都被浪费了。然而,有三个果实,三分之二的连接尝试被浪费,有四个果实,四分之三的连接尝试被浪费,等等。
为了避免额外的连接尝试,我们可以颠倒连接的顺序,如下所示:
(SELECT rpt.*, ber.shipper, ber.po, ber.commondity, ber.label
FROM berries ber
JOIN reports rpt
ON rpt.inspection_number = ber.report_key
WHERE rpt.status = '1' OR rpt.status = '0')
UNION ALL
(SELECT rpt.*, mel.shipper, mel.po, mel.commondity, mel.label
FROM melons mel
JOIN reports rpt
ON rpt.inspection_number = mel.report_key
WHERE rpt.status = '1' OR rpt.status = '0')
ORDER BY inspection_number DESC
在这里,我们从另一个方向(带有水果)开始,然后加入到报告中。这允许我们为每个报告只创建一个连接。
请注意,我们现在每个水果都使用INNER JOIN
而不是LEFT JOIN
,我们正在使用UNION ALL
将每个水果的结果加入到一个更大的结果集中。< / p>
为了进一步优化,有时MySQL不会将1
和0
这两个常量识别为范围,特别是如果它不是整数字段。范围查找比两个单独的查找更快,因此要向MySQL提示1
和0
的rpt.status是范围,请使用BETWEEN
而不是OR
,假设您的覆盖索引为(rpt.inspection_number, rpt.status)
。
答案 2 :(得分:0)
首先,你会注意到这个SELECT查询没有从瓜表中选择任何数据。因此,您不需要加入瓜表,因为您没有从中选择任何数据,并且它并不重要,因为您没有从中选择任何内容,因此无论它是什么或引用它。
SELECT
rpt.*,
ber.shipper, ber.po, ber.commodity, ber.label
接下来,我不太熟悉LEFT JOIN
,INNER JOIN
和JOIN
之间的差异,所以我无法回答这个问题。但是,根据我对MySQL的经验,尝试将最后一个查询更改为INNER JOIN而不是JOIN,看看是否有效。 MySQL网站上有documentation关于不同类型连接之间的差异。
如果您仍然遇到问题,请告诉我,我会尽力帮助您。希望我至少回答了一些问题。