帮助MySQL加入

时间:2010-11-01 20:55:22

标签: sql mysql join

我有两个表,Sales(ISBN,Sale_Time,[Sale Data Fields])和Affiliate_Sales(ISBN,Affiliate_Sale-Time,[Affiliate Data Fields])。

我想查询给定的一组ISBN的所有未到期销售(< 24小时)和未到期的Affiliate_Sales(< 72小时)。即使有未过期的销售但没有未到期的Affiliate_Sales,我也希望返回一行给定的ISBN,反之亦然(但是当它们都没有时应该返回任何内容)。我相信这被称为全加入。

我认为UNION不会在这里工作,因为除了ISBN之外,所有字段的表都不同。

这个问题的答案是在两个表中进行正确连接并检查到期的查询。

更新:正如您在下面的评论中所看到的,我正在尝试获取所有销售数据和所有Affiliate_Sales数据,而不仅仅是ISBN和时间。

更新2:结果如下所示

ISBN    Sale_DateTime   [Sale Fields…]  Affiliate_Sale_DateTime [Affiliate Sale Fields…]
1   11/6/2010 11:28    All the sale Fields  11/6/2010 0:28     All the affiliate Sale fields
2   NULL               NULLs                11/6/2010 0:28     All the affiliate Sale fields
3   11/6/2010 11:28    All the sale Fields  NULL               NULLs

如果得到这个需要在SQL端进行更多处理,而不仅仅是像Bruno的长查询所做的那样做两个基本的SELECT查询,也许我应该做两个?

4 个答案:

答案 0 :(得分:0)

如果您使用“AS”来定义要返回的字段的名称以便它们匹配,UNION应该可以工作。例如:

SELECT ISBN, Sale_Time FROM Sales
UNION ALL
SELECT ISBN, Affiliate_Sale_Time AS Sale_Time FROM Affiliate_Sales

答案 1 :(得分:0)

如果您在Sales表中始终拥有ISBN,那么您可以完全加入并获得您正在寻找的结果。否则,你需要离开加入。

select *
from Sales s
FULL OUTER JOIN Affiliate_Sales asa on asa.ISBN = s.ISBN
where DATEDIFF(hh, s.Sale_Time, GETDATE()) < 24
OR DATEDIFF(hh, asa.Sale_Time, GETDATE()) < 72

编辑 - 尝试上述或以下内容:

SELECT ISBN, Sale_Time 
FROM Sales s 
where DATEDIFF(hh, s.Sale_Time, GETDATE()) < 24
UNION ALL
SELECT ISBN, Affiliate_Sale_Time AS Sale_Time 
FROM Affiliate_Sales asa 
where DATEDIFF(hh, asa.Sale_Time, GETDATE()) < 72

如果您想要更多字段,则必须具体命名它们,除非表格结构相同。 FULL JOIN将为您提供所有结果。我之前的回答包括INNER JOIN,这会限制你的结果。

编辑 - 选择不匹配字段的示例:

select itemid, null, path, null, name
from Catalog

union all

select itemid, dsid, null, username, null
from DataSource

答案 2 :(得分:0)

您确实遇到了FULL OUTER JOIN问题,但遗憾的是,目前MySQL尚不支持此问题。

幸运的是,我们可以在表A和B之间模仿FULL OUTER JOIN

  • 从表A到表B的LEFT OUTER JOIN以捕获A中不在B中的行以及A和B之间的行匹配
  • 从表B到表A的右排除连接以捕获B中不在A中的行

由于您的表格除了ISBN以外的所有字段都有所不同,我们需要分两步完成:

  1. 首先,我们需要提取符合到期时间标准的ISBN
  2. 然后我们可以从两个表中检索以前选择的ISBN
  3. 的信息

    以下是检查查询的示例脚本:

    CREATE TABLE sales ( 
       isbn INT NOT NULL
      ,sale_time TIMESTAMP NOT NULL
      ,sale_value VARCHAR(100)
      ,PRIMARY KEY (isbn)
    );
    CREATE TABLE affiliate_sales ( 
       isbn INT NOT NULL
      ,sale_time TIMESTAMP NOT NULL
      ,affiliate_sale_value VARCHAR(100)
      ,PRIMARY KEY (isbn)
    );
    
    INSERT INTO sales (isbn,sale_time,sale_value) VALUES (1,TIMESTAMPADD(HOUR,-30,NOW()),'expired_sale');
    INSERT INTO sales (isbn,sale_time,sale_value) VALUES (2,TIMESTAMPADD(HOUR,-34,NOW()),'expired_sale');
    INSERT INTO sales (isbn,sale_time,sale_value) VALUES (3,TIMESTAMPADD(HOUR,-23,NOW()),'unexpired_sale');
    INSERT INTO sales (isbn,sale_time,sale_value) VALUES (4,TIMESTAMPADD(HOUR,-12,NOW()),'unexpired_sale');
    INSERT INTO sales (isbn,sale_time,sale_value) VALUES (5,TIMESTAMPADD(HOUR,-12,NOW()),'unexpired_sale_only');
    
    INSERT INTO affiliate_sales (isbn,sale_time,affiliate_sale_value) VALUES (1,TIMESTAMPADD(HOUR,-74,NOW()),'expired_affiliate_sale');
    INSERT INTO affiliate_sales (isbn,sale_time,affiliate_sale_value) VALUES (2,TIMESTAMPADD(HOUR,-54,NOW()),'unexpired_affiliate_sale');
    INSERT INTO affiliate_sales (isbn,sale_time,affiliate_sale_value) VALUES (3,TIMESTAMPADD(HOUR,-80,NOW()),'expired_affiliate_sale');
    INSERT INTO affiliate_sales (isbn,sale_time,affiliate_sale_value) VALUES (4,TIMESTAMPADD(HOUR,-12,NOW()),'unexpired_affiliate_sale');
    INSERT INTO affiliate_sales (isbn,sale_time,affiliate_sale_value) VALUES (6,TIMESTAMPADD(HOUR,-44,NOW()),'unexpired_affiliate_sale_only');
    

    以下是提取所需数据的查询(抱歉格式错误,我无法找到如何在预阻塞内正确显示):

    SELECT unexpired_sal.isbn
    , sal.sale_time, sal.sale_value
    , afs.sale_time affiliate_sale_time, afs.affiliate_sale_value
    FROM (
    SELECT sal.isbn
    FROM (
    SELECT isbn FROM sales
    WHERE TIMESTAMPDIFF(HOUR,sale_time,NOW()) < 24
    ) sal
    LEFT JOIN (
    SELECT isbn FROM affiliate_sales
    WHERE TIMESTAMPDIFF(HOUR,sale_time,NOW()) < 72
    ) afs
    ON afs.isbn = sal.isbn
    UNION ALL
    SELECT afs.isbn
    FROM (
    SELECT isbn FROM sales
    WHERE TIMESTAMPDIFF(HOUR,sale_time,NOW()) < 24
    ) sal
    RIGHT JOIN (
    SELECT isbn FROM affiliate_sales
    WHERE TIMESTAMPDIFF(HOUR,sale_time,NOW()) < 72
    ) afs
    ON afs.isbn = sal.isbn
    WHERE sal.isbn IS NULL
    ) unexpired_sal
    LEFT JOIN (
    SELECT * FROM sales
    WHERE TIMESTAMPDIFF(HOUR,sale_time,NOW()) < 24
    ) sal
    ON sal.isbn = unexpired_sal.isbn
    LEFT JOIN (
    SELECT * FROM affiliate_sales
    WHERE TIMESTAMPDIFF(HOUR,sale_time,NOW()) < 72
    ) afs
    ON afs.isbn = unexpired_sal.isbn
    ;

    您将获得以下输出:

    +------+---------------------+---------------------+---------------------+-------------------------------+
    | isbn | sale_time           | sale_value          | affiliate_sale_time | affiliate_sale_value          |
    +------+---------------------+---------------------+---------------------+-------------------------------+
    |    3 | 2010-11-06 11:28:08 | unexpired_sale      |                NULL | NULL                          |
    |    4 | 2010-11-06 22:28:08 | unexpired_sale      | 2010-11-06 22:28:08 | unexpired_affiliate_sale      |
    |    5 | 2010-11-06 22:28:08 | unexpired_sale_only |                NULL | NULL                          |
    |    2 |                NULL | NULL                | 2010-11-05 04:28:08 | unexpired_affiliate_sale      |
    |    6 |                NULL | NULL                | 2010-11-05 14:28:08 | unexpired_affiliate_sale_only |
    +------+---------------------+---------------------+---------------------+-------------------------------+
    5 rows in set (0.00 sec)
    

答案 3 :(得分:0)

定义要求

您在问题和评论中指定了一些矛盾和定义不足的要求,但我想这是您提出要求的原因之一。

让我为你列出

  1. 您要列出两张表中两个特定子集中任意一个子元素的ISBN(未到期的销售额和未到期的联盟销售额)
  2. 您希望显示两个表中的其他列,而不仅仅是ISBN
  3. 你不想要NULL
  4. (我正在使用术语子集,因为在概念层面上指定未过期子集的条件并不重要)

    以下是一些含义

    • 如果要列出两个表中的ISBN +字段以查找仅在其中一个子集中的条目,则必须为另一方提供NULL;这与#3

    • 相矛盾
    • 两个表中的ISBN都是唯一的吗?如果是,则忽略这一点:如果ISBN不是唯一的,那么您需要指定如何连接两个表的子集,否则从每个表中获取每行的每一行

    如果ISBN是唯一的

    现在,如果您的ISBN在两个表中都是唯一的,那么Bruno的答案似乎指向了正确的方向(尽管它没有完全通过他的SQL,但它看起来确实有点过于复杂)。

    在mysql中实现OUTER JOINS的方法是

    • LEFT JOIN和RIGHT JOIN的UNION(不是UNION ALL,而是UNION,它将采用不同的行;它也与正式定义相匹配)
    • UNION ALL LEFT JOIN和RIGHT EXCLUSION JOIN(UNION ALL可能明显更快,尤其是在大型结果集上);此选项具有直接对称等效(UNION ALL of RIGHT JOIN和LEFT EXCLUSION JOIN)
    • UNION ALL INNER JOIN和左排除连接和右排除连接(如果选择性高,则内部连接可能明显快于LEFT JOIN 如果排除连接可以使用索引)

    如果此处使用的某些术语不明确,请参阅Common MySQL Queries上的示例。

    如果ISBN不是唯一的

    您需要定义如何加入,仅加入ISBN将返回子集的笛卡尔积(在其他任何情况下,其他字段肯定不是您所需要的。)

    修改 澄清后,您可以尝试此解决方案

    SELECT * FROM Sales a LEFT JOIN Affiliate_Sales b ON a.ISBN=b.ISBN
    WHERE TIMESTAMPDIFF(HOUR, Sale_DateTime, Now()) < 24 
          AND (TIMESTAMPDIFF(HOUR, Affiliate_Sale_DateTime, Now()) < 72 
          OR Affiliate_Sale_DateTime IS NULL)
    UNION ALL
    SELECT * FROM Sales a RIGHT JOIN Affiliate_Sales b ON a.ISBN=b.ISBN
    WHERE TIMESTAMPDIFF(HOUR, Affiliate_Sale_DateTime, Now()) < 72 
          AND Sale_DateTime IS NULL; 
    

    如果你想缩短它,你需要创建视图。另外,请看一下提供的链接,这是非常好的。