我需要有关mysql中JOIN查询的帮助

时间:2014-03-21 18:02:20

标签: mysql join

我已经开始学习MySQL了,我遇到了JOIN的问题。

我有两张表:purchasesales

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 salesdate = purchasedate

输出:

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

3 个答案:

答案 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

An SQLfiddle to test with

答案 1 :(得分:1)

从一般意义上讲,您正在寻找的是FULL OUTER JOIN,它在MySQL中无法直接使用。相反,您只能获得LEFT JOINRIGHT JOIN,您可以UNION一起获得基本相同的结果。有关此主题的非常详尽的讨论,请参阅Full Outer Join in MySQL

如果您需要帮助了解JOIN桌子的不同方式,我建议A Visual Explanation of SQL Joins

这与常规FULL OUTER JOIN的不同之处在于,您在JOIN结果中最多只包含一个表中的任何特定行。问题是,如果您在特定日期有一条purchase条记录和两条sales条记录,sales条记录是与purchase条相关联的记录?你试图在这两个表之间表达的关系是什么?

听起来并不像purchasesales记录之间存在任何特定关系,除了其中一些记录恰好发生在同一天。在这种情况下,您使用错误的工具进行工作。如果要做的就是并排显示这些表并按行排列日期,则根本不需要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)