我目前的sql语句正如我所希望的那样完全正常工作。我的问题是我在LEFT JOIN上需要某种子查询,或者我如何从invUpdate表中检索不存在于库存表中的任何记录。现在我得到了所有的库存记录(我想要的),如果在invUpdate中存在匹配的记录(基于vin),那么表invUpdate中的记录信息将覆盖库存中的记录信息(在显示的网页上)。我还需要能够包含来自invUpdate的任何其他记录。
SELECT IF(u.vin IS NULL,i.vin,u.vin) AS vin, IF(u.vin IS NULL,i.miles,u.miles) AS miles
, IF(u.vin IS NULL,i.year,u.year) AS year, IF(u.vin IS NULL,i.make,u.make) AS make
, IF(u.vin IS NULL,i.model,u.model) AS model, IF(u.vin IS NULL,i.trim,u.trim) AS trim
, IF(u.vin IS NULL,i.category,u.category) AS category, IF(u.vin IS NULL,i.price,u.price) AS price
, IF(u.vin IS NULL,i.msrp,u.msrp) AS msrp, IF(u.vin IS NULL,i.color,u.color) AS color
, IF(u.vin IS NULL,i.engine,u.engine) AS engine, IF(u.vin IS NULL,i.transmission,u.transmission) AS transmission
, i.images, i.stock, p.imgURL
FROM inventory i
LEFT JOIN invUpdate u ON i.vin=u.vin
LEFT JOIN photos p ON i.vin=p.vin AND position=0
WHERE i.vin != ''
我最初的想法是添加某种NOT EXISTS语句,例如
WHERE NOT EXISTS (SELECT *
FROM invUpdate u
WHERE u.vin = i.vin)
我的想法是,这应该以某种方式成为第一个LEFT JOIN ON声明的一部分
FROM inventory i LEFT JOIN invUpdate u ON i.vin=u.vin
但是我在这个子查询上遇到了麻烦。任何想法,指示或帮助将不胜感激。
更新: 在沉睡于此并阅读每个人的笔记以及其他一些堆栈溢出示例后,我想出了一些简单的方法来从库存和invUpdate表中选择数据。
(SELECT ...
i.stock,
IF(p.images IS NULL,i.images,p.images)
...
FROM inventory i
LEFT JOIN invUpdate u ON i.vin=u.vin)
UNION
(SELECT ...
i.stock,
IF(p.images IS NULL,i.images,p.images)
...
FROM inventory i
RIGHT JOIN invUpdate u ON i.vin=u.vin)
我现在唯一的问题就是有一张名为照片的第3张桌子。如果照片中有匹配的记录,我需要使用该记录。它们将基于vin匹配。我试图将它联合起来,但因为它有不同数量的字段我无法使其工作。有任何想法吗?注意我在联合查询中使用IF语句,这样如果照片表图像列中有一条记录,它将在库存表图像列中的任何内容之前使用。
答案 0 :(得分:0)
你能完全加入吗?然后,无论是否匹配,您都可以从两个表中获取记录。
我不知道我的SQL,但这就是我在SQL Server中所做的事情。
答案 1 :(得分:0)
“我如何从invUpdate表中检索库存表中不存在的任何记录。”
总结一下,对于您拥有的表:
INV (inventory)
UPD (invupdate)
考虑任何给定的“vin”可能存在于......
中1) just INV
2) both INV & UPD
3) just UPD
您发布的查询几乎涵盖1& 2。
修改的 @Macrunning写道:
> hello jgreve.
> Yes I understand it covers 1 & 2.
> Yes I need 3 included on this.
> After the initial WHERE i.vin!='' statement,
> there is more based on user selection.
> These additional are concatenated using php.
> For example:
> if(isset($_GET['year'])){ $query_Recordset1.=" AND i.year='$myYear' "; }
>
> Therefor placing the union all after would impede on this.
> I thought there would be a cleaner solution by placing a
> subquery in the first LEFT JOIN statement.
嗯......这变得越来越复杂了。 : - )
R.E。在原始问题的第一个LEFT JOIN中添加子查询:
这似乎会导致WHERE子句中复杂逻辑的大鼠巢。
考虑一下(u2& u3是我试图回到3种情况):
select i.vin as i_vin
, u2.vin as u2_vin
, u3.vin as u3_vin
from INVENTORY i
left join INVUPDATE u2 on u2.vin = i.vin
left join INVUPDATE u3 on u3.vin = i.vin
Source tables : Result set
+-----------+-----------+ : +-------+--------+--------+
| INVENTORY | INVUPDATE | : | i_vin | u2_vin | u3_vin |
+-----------+-----------+ : +-------+--------+--------+
| 100 | 200 | : | 100 | null | null |
| 200 | 300 | : | 200 | 200 | 200 |
+-----------+-----------+ : +-------+--------+--------+
请注意,#300永远不会有机会出现。 我认为你不能通过组合LEFT JOIN来做到这一点。
您可能能够修改您的“LEFT JOIN”以从子选择中读取 而不是直接指定表格,例如:
select i.vin as i_vin
, u2.vin as u2_vin
from INVENTORY i
left join (select usub.vin .... from INVUPDATE something somthing) u
但是没有进行一些实验,我很难预测 结果集会产生什么(编写子选择很难 对我来说,没有逐步建立它与实际 数据库)。
我想你们所有的PHP过滤器都必须限制#3。 这是我怀疑会变得丑陋的。
如果MySQL支持“完全外部联接”,我建议可能会这样做:(请参阅“{3}}上的”没有完全加入MySQL“
-- hypothetical example, doesn't actually run in MySQL
select i.vin as i_vin
, u.vin as u_vin
from INVENTORY i
full outer join INVUPDATE u on u.vin = i.vin
Source tables : Result set
+-----------+-----------+ : +-------+-------+
| INVENTORY | INVUPDATE | : | i_vin | u_vin |
+-----------+-----------+ : +-------+-------+
| 100 | 200 | : | 100 | null |
| 200 | 300 | : | 200 | 200 |
+-----------+-----------+ : | null | 300 |
: +-------+-------+
但是你仍然需要按YEAR,MODEL以及PHP前端支持的其他任何内容进行过滤。
当你从各种表限定符中涉及列时(例如i.year与u.year), WHERE子句的逻辑似乎很复杂(例如让我头痛)。
那么......以下方法呢?
UNION 方法看起来起初更复杂。
但我怀疑它会简化你的过滤逻辑。
因为MySQL独立地评估了union的每个部分, 我们不应该担心表限定符。
这意味着您应该能够编写“通用”过滤器...... 假设我们有以下PHP变量用于过滤器:
$filter_YEAR = "\nAND year = '1995'"
$filter_YEAR = "\nAND model = 'XYZ'"
目标是生成这样的SQL(从这里开始测试):
select '1) just INV' as record_source
, vin
, miles
...etc...
from FROM inventory i
where not exists( select 1 from invupdate u where u.vin=i.vin )
AND year = '1995'
AND model = 'XYZ'
-- In this part the "where NOT EXISTS" makes this "1) just INV"
-- ===============================================================
-- I'm avoiding @Uueerdo's neat trick with left-join on INVUPDATE
-- and filtering nulls in this part's WHERE clause because I don't
-- want to generate a $filter_YEAR_INV = "AND i.year = '1995'"
-- and another one for $filter_YEAR_UPD = "AND u.year = '1995'"
-- (note the different qualifiers).
-- ===============================================================
union all
select '2) both INV and UPD' as record_source
, vin
, miles
...etc...
from FROM invupdate u
-- the "where EXISTS" makes this "2) both INV and UPD"
where exists( select 1 from inventory i where u.vin=i.vin )
AND year = '1995'
AND model = 'XYZ'
union all
select '3) just UPD' as record_source
, vin
, miles
from FROM invupdate u
-- the "where NOT EXISTS" makes this "3) just UPD".
where not exists( select 1 from inventory i where u.vin=i.vin )
AND year = '1995'
AND model = 'XYZ'
order by record_source, vin
由于我在PHP中没有太多(任何)飞行时间,我不知道是否有以下内容 实际上会编译,但我希望你能得到这个想法。
// obligatory: see "little bobby tables" https://xkcd.com/327/
// Sanitizing the input filters is beyond the scope of this answer.
$filter_YEAR = "";
if(isset($_GET['year'])){ $filter_YEAR ="\n AND year='$myYear' "; }
$filter_YMODEL = "";
if(isset($_GET['model'])){ $filter_MODEL ="\n AND year='$myModel' "; }
$filter_COLOR = "";
// At this point your $filter_WHATEVER variables either have an AND-clause
// that will work for all of the following.
// Or they are empty, in which case they wont change your resultant SQL.
$query_Recordset1 = "select '1) just INV' as record_source"
.= "\n , vin"
.= "\n , miles"
...etc...
.= "\nfrom FROM inventory i"
.= "\nwhere not exists( select 1 from invupdate u where u.vin=i.vin )"
.= $filter_YEAR$ . filter_YMODEL . $filter_COLOR;
// add SQL to get 2) both INV and UPD
$query_Recordset1 .= "union all"
.= "select '2) both INV and UPD' as record_source
.= "\n , vin
.= "\n , miles"
...etc...
.= "\nfrom FROM invupdate u
.= "\nwhere exists( select 1 from inventory i where u.vin=i.vin )"
.= $filter_YEAR$ . filter_YMODEL . $filter_COLOR;
// add SQL to get 3) just UPD
$query_Recordset1 .= .= "union all"
.= "select '3) just UPD' as record_source
.= "\n , vin
.= "\n , miles"
...etc...
.= "\nfrom FROM invupdate u
.= "\nwhere not exists( select 1 from inventory i where u.vin=i.vin )"
.= $filter_YEAR$ . filter_YMODEL . $filter_COLOR
.= "order by record_source, vin"
(编辑修复SQL中的问题;为了完整性而保留在这里,但根据基于PHP前端的额外“动态过滤”要求,这些要求并不那么有用。)
(问题:我刚想到这个,你会有一个给定VIN的2+ UPD记录吗?解决方案有点不同,你可能只想使用最近的更新记录)
对于#3,你可以包含一个FULL OUTER JOIN,但这将非常混乱......你的IF()表达式将是代码和维护的头痛。
@UUeerdo在他们的评论中建议我这么干净。
此示例添加了一个“sourceTables”列,以帮助您追踪给定记录来自哪个表。
SELECT IF(u.vin IS NULL
, '1) Just INV'
, '2) Both INV & UPD' ) AS sourceTables
, IF(u.vin IS NULL, i.miles, u.miles) AS miles
, ...etc...
FROM inventory i
LEFT JOIN invUpdate u ON i.vin=u.vin
LEFT JOIN photos p ON i.vin=p.vin AND position=0
WHERE i.vin != ''
union all
SELECT '3) Just UPD' AS sourceTables
, u.miles AS miles
, ...etc...
from invUpdate u
-- edit: fixed "where" before LEFT JOIN error.
-- Also modified as per @Uueerdo's insightful comment.
LEFT JOIN inventory AS i ON u.vin = i.vin
LEFT JOIN photos p ON u.vin=p.vin AND position=0
WHERE u.vin != ''
AND i.vin IS NULL – Uueerdo 3 hours ago
琐事点:注意在上一次LEFT JOIN我们加入了u.vin上的“照片”,而不是上面的i.vin。同样的WHERE u.vin!=''(我假设你有充分的理由阻止空的vin#。)