我已经开始学习MySQL了,我遇到了JOIN
的问题。
我有两张表:purchase
和sales
purchase
--------------
p_id date p_cost p_quantity
---------------------------------------
1 2014-03-21 100 5
2 2014-03-21 20 2
sales
--------------
s_id date s_cost s_quantity
---------------------------------------
1 2014-03-21 90 9
2 2014-03-22 20 2
我希望将这两个表连接到purchase.date=sales.date
,以获得以下结果之一:
选项1:
p_id date p_cost p_quantity s_id date s_cost s_quantity
------------------------------------------------------------------------------
1 2014-03-21 100 5 1 2014-03-21 90 9
2 2014-03-21 20 2 NULL NULL NULL NULL
NULL NULL NULL NULL 2 2014-03-22 20 2
选项2:
p_id date p_cost p_quantity s_id date s_cost s_quantity
------------------------------------------------------------------------------
1 2014-03-21 100 5 NULL NULL NULL NULL
2 2014-03-21 20 2 1 2014-03-21 90 9
NULL NULL NULL NULL 2 2014-03-22 20 2
主要问题在于第一个结果的第二行。我不想要价值
第2行再次2014-03-21, 90, 9
...我想改为NULL
。
我不知道是否可以这样做。如果有人帮助我,那就太好了。
我尝试过使用左连接
SELECT *
来自sales
LEFT JOIN purchase
sales
。date
= purchase
。date
输出:
s_id date s_cost s_quantity p_id date p_cost p_quantity 1 2014-03-21 90 9 1 2014-03-21 100 5 1 2014-03-21 90 9 2 2014-03-21 20 2 2 2014-03-22 20 2 NULL NULL NULL NULL
但我希望第2行的第4个值为NULL
答案 0 :(得分:2)
由于没有常用的表表达式或完整的外连接可供使用,查询将有一些重复,而是需要使用与右连接联合的左连接;
SELECT p_id, p.date p_date, p_cost, p_quantity,
s_id, s.date s_date, s_cost, s_quantity
FROM (
SELECT *,(SELECT COUNT(*) FROM purchase p1
WHERE p1.date=p.date AND p1.p_id<p.p_id) rn FROM purchase p
) p LEFT JOIN (
SELECT *,(SELECT COUNT(*) FROM sales s1
WHERE s1.date=s.date AND s1.s_id<s.s_id) rn FROM sales s
) s
ON s.date=p.date AND s.rn=p.rn
UNION
SELECT p_id, p.date p_date, p_cost, p_quantity,
s_id, s.date s_date, s_cost, s_quantity
FROM (
SELECT *,(SELECT COUNT(*) FROM purchase p1
WHERE p1.date=p.date AND p1.p_id<p.p_id) rn FROM purchase p
) p RIGHT JOIN (
SELECT *,(SELECT COUNT(*) FROM sales s1
WHERE s1.date=s.date AND s1.s_id<s.s_id) rn FROM sales s
) s
ON s.date=p.date AND s.rn=p.rn
答案 1 :(得分:1)
从一般意义上讲,您正在寻找的是FULL OUTER JOIN
,它在MySQL中无法直接使用。相反,您只能获得LEFT JOIN
和RIGHT JOIN
,您可以UNION
一起获得基本相同的结果。有关此主题的非常详尽的讨论,请参阅Full Outer Join in MySQL。
如果您需要帮助了解JOIN
桌子的不同方式,我建议A Visual Explanation of SQL Joins。
这与常规FULL OUTER JOIN
的不同之处在于,您在JOIN
结果中最多只包含一个表中的任何特定行。问题是,如果您在特定日期有一条purchase
条记录和两条sales
条记录,sales
条记录是与purchase
条相关联的记录?你试图在这两个表之间表达的关系是什么?
听起来并不像purchase
和sales
记录之间存在任何特定关系,除了其中一些记录恰好发生在同一天。在这种情况下,您使用错误的工具进行工作。如果要做的就是并排显示这些表并按行排列日期,则根本不需要JOIN
。相反,您应该分别SELECT
每个表,并使用其他工具(或手动)进行格式化。
答案 2 :(得分:1)
这是获得相同结果的另一种方法,但是对此的解释是可怕的;和大集合的表现将是残酷的。
这实际上是UNIONed的两个查询。第一个查询基本上是“购买LEFT JOIN销售”,第二个查询基本上是“销售ANTI JOIN购买”。
因为两个表之间没有外键关系,除了在日期匹配的行之外,我们必须“发明”我们可以加入的键;我们使用用户变量为给定日期内的每一行分配升序整数值,因此我们可以将第1行从买入到第1行与销售等匹配。
我通常不会使用SQL生成此类型的结果;从传统上连接表的方式来看,它不是典型的JOIN操作。
但是,如果我必须使用MySQL生成指定的结果集,我会这样做:
SELECT p.p_id
, p.p_date
, p.p_cost
, p.p_quantity
, s.s_id
, s.s_date
, s.s_cost
, s.s_quantity
FROM ( SELECT @pl_i := IF(pl.date = @pl_prev_date,@pl_i+1,1) AS i
, @pl_prev_date := pl.date AS p_date
, pl.p_id
, pl.p_cost
, pl.p_quantity
FROM purchase pl
JOIN ( SELECT @pl_i := 0, @pl_prev_date := NULL ) pld
ORDER BY pl.date, pl.p_id
) p
LEFT
JOIN ( SELECT @sr_i := IF(sr.date = @sr_prev_date,@sr_i+1,1) AS i
, @sr_prev_date := sr.date AS s_date
, sr.s_id
, sr.s_cost
, sr.s_quantity
FROM sales sr
JOIN ( SELECT @sr_i := 0, @sr_prev_date := NULL ) srd
ORDER BY sr.date, sr.s_id
) s
ON s.s_date = p.p_date
AND s.i = p.i
UNION ALL
SELECT p.p_id
, p.p_date
, p.p_cost
, p.p_quantity
, s.s_id
, s.s_date
, s.s_cost
, s.s_quantity
FROM ( SELECT @sl_i := IF(sl.date = @sl_prev_date,@sl_i+1,1) AS i
, @sl_prev_date := sl.date AS s_date
, sl.s_id
, sl.s_cost
, sl.s_quantity
FROM sales sl
JOIN ( SELECT @sl_i := 0, @sl_prev_date := NULL ) sld
ORDER BY sl.date, sl.s_id
) s
LEFT
JOIN ( SELECT @pr_i := IF(pr.date = @pr_prev_date,@pr_i+1,1) AS i
, @pr_prev_date := pr.date AS p_date
, pr.p_id
, pr.p_cost
, pr.p_quantity
FROM purchase pr
JOIN ( SELECT @pr_i := 0, @pr_prev_date := NULL ) prd
ORDER BY pr.date, pr.p_id
) p
ON p.p_date = s.s_date
AND p.i = s.i
WHERE p.p_date IS NULL
ORDER BY COALESCE(p_date,s_date),COALESCE(p_id,s_id)