【问题标题】:I need help regarding JOIN query in mysql我需要有关 mysql 中的 JOIN 查询的帮助
【发布时间】:2014-04-29 06:16:41
【问题描述】:

我已经开始学习 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

我不知道是否可以这样做。如果有人能帮助我,那就太好了。

我尝试使用左连接

选择 * 来自sales 左连接 purchase 开启 sales.date = purchase.date

输出:

s_id 日期 s_cost s_quantity p_id 日期 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

但我希望第二行的前 4 个值为 NULL

【问题讨论】:

  • 尝试一下,然后发布您尝试过的内容。
  • 看起来像一个简单的问题,但我不明白的事情......让它更具可读性。给出一些 SQL,给出预期的结果。
  • 你打算做任何报告吗?
  • 是的,我想举报
  • pid 和 sid 这些是主键吗?

标签: mysql join


【解决方案1】:

这是获得相同结果的另一种方法,但对此的解释是可怕的;大集合的表现会很糟糕。

这实质上是将两个查询联合在一起。第一个查询本质上是“purchase LEFT JOIN sales”,第二个查询本质上是“sales ANTI JOIN purchase”。

因为两个表之间没有外键关系,除了日期匹配的行,我们必须“发明”一个可以加入的键;我们使用用户变量为给定日期内的每一行分配升序整数值,因此我们可以将购买的第 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)

【讨论】:

    【解决方案2】:

    在一般意义上,您要查找的内容称为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 每个表格并使用其他工具(或手动)进行格式化。

    【讨论】:

    • 感谢您的帮助。
    • @farha 我很想知道您正在使用的表的大小,以及 Joachim 的查询需要多长时间才能完成。这是一个巧妙的技巧,但执行计划非常可怕。
    • @AirThomas 实际上我正计划为我的项目做这样的事情。但我确定我需要改变我的想法。
    【解决方案3】:

    由于没有可使用的公用表表达式或完整外连接,查询将有一些重复,而需要使用左连接与右连接联合;

    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.

    【讨论】:

    • 太棒了,是的,就是这个!
    猜你喜欢
    • 2011-06-30
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多