【问题标题】:How to limit a query's results to only duplicates?如何将查询的结果限制为仅重复项?
【发布时间】:2015-05-01 20:54:38
【问题描述】:

这可能是一个愚蠢的问题,但它让我难住了。我基本上使用 3 个表格来提取活动和团队详细信息(如下)。

SELECT      GOLD.CAMPAIGN_ID,
            TEAM.ID,
            TEAM.NAME
FROM        CAMPAIGN_ANALYTICS_GOLD GOLD
LEFT JOIN   ENTITY ENT
ON          ENT.CAMPAIGN_ID = GOLD.CAMPAIGN_ID
LEFT JOIN   TEAM TEAM
ON          TEAM.ID = ENT.TEAM_ID
GROUP BY    GOLD.CAMPAIGN_ID,
            GOLD.CAMPAIGN_NAME,
            TEAM.ID,
            TEAM.NAME;

我能够绘制出哪些营销活动与哪些团队保持一致,但我只想过滤那些映射到多个团队的营销活动的结果。例如,一些结果如下所示:

CAMPAIGN_ID    ID           NAME
830            65           Media Group APAC
917            40           iAdvertising
1133           9            Media Comp
1133           2            Ad Network 5
7163           931          Y Vector
8149           318          Hectic Media
8149           3827         Effective Media Net
15982          1919         ADCMP 10
27587          2675         MediaCorp NA
27587          48           North Shore Ad

为了确定映射到多个团队的广告系列 ID(在本例中为 1133、8149 和 27587),我需要在查询中添加什么内容,或者为了实现这些目标,最佳做法是什么结果?

【问题讨论】:

    标签: sql group-by duplicates mysql-workbench having


    【解决方案1】:

    您可以使用内部连接来解决此问题,以便过滤您想要获取的行。

    编辑: 此查询假定ENTITY 表中只有一行具有相同的CAMPAIGN_IDTEAM_ID 对。如果您可以有重复的行,那么我认为您应该查看 John Bollinger 提供的解决方案。

    SELECT      GOLD.CAMPAIGN_ID,
                TEAM.ID,
                TEAM.NAME
    FROM        CAMPAIGN_ANALYTICS_GOLD GOLD
    LEFT JOIN   ENTITY ENT
    ON          ENT.CAMPAIGN_ID = GOLD.CAMPAIGN_ID
    LEFT JOIN   TEAM TEAM
    ON          TEAM.ID = ENT.TEAM_ID
    INNER JOIN 
    (
    
    SELECT      CAMPAIGN_ID
    FROM        ENTITY
    GROUP BY    CAMPAIGN_ID
    HAVING COUNT(*) > 1
    
    ) x on x.G_ID= GOLD.CAMPAIGN_ID
    GROUP BY    GOLD.CAMPAIGN_ID,
                GOLD.CAMPAIGN_NAME,
                TEAM.ID,
                TEAM.NAME;
    

    【讨论】:

    • 这将识别具有多个 entitys 的广告系列,但如果将多个 entitys 分配给同一个广告系列和团队,它可能会产生不需要的额外结果。是否需要考虑这取决于数据。
    • @John Bollinger:你的权利。我已经更新了我的答案。
    【解决方案2】:

    如果您使用的是 MySQL,那么您将无法访问分析函数,否则会提供一个非常方便的解决方案(根据 @JohnOdom)。在这种情况下,您也无法访问公用表表达式,这很方便。

    如果可以安全地假设与同一个团队关联的两个不同实体永远不会与同一个活动相关联,那么问题可以简化为识别与多个关联实体相关联的活动,@user707727 提供了解决方案.

    更通用的解决方案稍微复杂一些,但您至少可以做出一些假设。特别是,一个活动只能通过与现有实体及其现有团队的关联来与多个团队关联,因此您可以执行内部联接而不是外部联接。此外,请注意所有有关哪些团队与哪些活动相关联的信息仅由表 entity 承载,因此探测该关系的查询只需要考虑该表。

    以下解决方案首先通过仅分析表ENTITY 来识别所需的(campaign_idteam_id)对,然后加入表TEAM 以获取团队名称。如果需要有关活动的其他信息(例如其名称),也可以将表 campaign 加入外部查询中。假设campaign_idteam_id是各自表的PK,则不需要在顶层进行分组。

    SELECT
      CAMP_TEAM.CAMPAIGN_ID,
      TEAM.ID,
      TEAM.NAME
    FROM
      (
        (
          SELECT CAMPAIGN_ID
          FROM ENTITY
          GROUP BY CAMPAIGN_ID
          HAVING COUNT(DISTINCT TEAM_ID) > 1
        ) CAMP
        JOIN ENTITY ENT
          ON ENT.CAMPAIGN_ID = CAMP.CAMPAIGN_ID
        GROUP BY ENT.CAMPAIGN_ID, ENT.TEAM_ID
      ) CAMP_TEAM
      JOIN TEAM TEAM
        ON TEAM.ID = CAMP_TEAM.TEAM_ID
    ;
    

    【讨论】:

      【解决方案3】:

      [更新] 我想我是 MYSQL 的菜鸟,认为它就像 MSSQL Lol :P。但是我现在已经更新了我的答案以符合 MYSQL。你可以查看我的 SQL Fiddle here

      您可以使用COUNT(CAMPAIGN_ID)GROUP BY CAMPAIGN_ID 来获取按CAMPAIGN_ID 分组的总行数(意味着具有相同CAMPAIGN_ID 的行,因此重复),然后过滤大于1 的计数。有不同的方式来做到这一点,但这是我最喜欢的方式:

      SELECT tt.CAMPAIGN_ID, tt.ID, tt.NAME
      FROM
      (
          SELECT GOLD.CAMPAIGN_ID,
                 TEAM.ID,
                 TEAM.NAME,
                 COUNT(GOLD.CAMPAIGN_ID) as [Count]
           FROM  CAMPAIGN_ANALYTICS_GOLD GOLD
           LEFT JOIN ENTITY ENT ON ENT.CAMPAIGN_ID = GOLD.CAMPAIGN_ID
           LEFT JOIN TEAM TEAM ON TEAM.ID = ENT.TEAM_ID
           GROUP BY GOLD.CAMPAIGN_ID
      ) t
      INNER JOIN CAMPAIGN_ANALYTICS_GOLD GOLD ON GOLD.CAMPAIGN_ID = t.CAMPAIGN_ID
      WHERE t.Count > 1
      

      我不知道您的表的布局,所以我制作了一个测试表,其结果与您发布的结果相同,然后创建了查询以仅在我的 SQL Fiddle 链接上返回重复项。

      这是我的 MSSQL 版本的未来观众答案:

      SELECT *
      FROM
      (
          SELECT GOLD.CAMPAIGN_ID,
                 TEAM.ID,
                 TEAM.NAME,
                 COUNT(GOLD.CAMPAIGN_ID) OVER (PARTITION BY GOLD.CAMPAIGN_ID) as [Count]
          FROM  CAMPAIGN_ANALYTICS_GOLD GOLD
          LEFT JOIN ENTITY ENT ON ENT.CAMPAIGN_ID = GOLD.CAMPAIGN_ID
          LEFT JOIN TEAM TEAM ON TEAM.ID = ENT.TEAM_ID
          GROUP BY GOLD.CAMPAIGN_ID, GOLD.CAMPAIGN_NAME, TEAM.ID, TEAM.NAME
      ) t
      WHERE t.Count > 1
      

      还有 MSSQL SQL Fiddle 链接here

      如果在存在重复行(活动、ID 和名称)的情况下仍希望结果是唯一的,则可以将 DISTINCT 子句添加到任一查询的外部选择语句中。

      【讨论】:

      • 他标记了 mysql-workbench,所以假设他正在使用 mysql 似乎是合理的。不幸的是,mysql 在主要的 DBMS 中因支持分析功能而引人注目。
      • @JohnBollinger 我更新了我的答案以使用 MYSQL。
      • 新查询与@user707727 存在相同的问题(这可能根本不是问题,具体取决于数据):如果活动与同一个团队通过两个不同的实体。
      • @JohnBollinger 我不明白你所说的false positives in the event that a campaign is associated with the same team via two distinct entities. 是什么意思你能给出你在说什么的示例数据吗?
      • 问题是过滤与多个团队相关的活动。目前尚不清楚是否可以有两个不同的实体行具有相同的campaign_id 和相同的team_id,但假设确实有两个具有campaign_id 2 和team_id 1,并且没有其他实体有 campaign_id 2。在分组之前,您的联接将包含这两个实体中的 每个 的一行,因此该组的 COUNT() 将为 2,它将通过过滤器.但是,它不在预期结果之列,因为它仅与团队 1 相关。
      【解决方案4】:

      group by 消除了左边,所以只需加入一个

      SELECT      GOLD.CAMPAIGN_ID,
                  TEAM.ID,
                  TEAM.NAME
      FROM        CAMPAIGN_ANALYTICS_GOLD GOLD 
      JOIN        ENT
        ON        ENT.CAMPAIGN_ID = GOLD.CAMPAIGN_ID
      JOIN        TEAM 
        ON        TEAM.ID = ENT.TEAM_ID 
      
      JOIN        CAMPAIGN_ANALYTICS_GOLD GOLDdup 
        ON        GOLD.CAMPAIGN_ID = GOLDdup.CAMPAIGN_ID  
      JOIN        ENT as ENTdup
        ON        ENTdup.CAMPAIGN_ID = GOLDdup.CAMPAIGN_ID
       and        ENTdup.TempID <> ENT.TEAM_ID  -- this finds the dups
      
      GROUP BY    GOLD.CAMPAIGN_ID,
                  GOLD.CAMPAIGN_NAME,
                  TEAM.ID,
                  TEAM.NAME;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-11-12
        • 1970-01-01
        • 2011-03-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多