加入左边?试图弄清

时间:2016-01-18 21:17:31

标签: mysql

我目前的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语句,这样如果照片表图像列中有一条记录,它将在库存表图像列中的任何内容之前使用。

2 个答案:

答案 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#。)