【问题标题】:SQL: How to remove duplicate rows created by CASE WHEN statementSQL:如何删除由 CASE WHEN 语句创建的重复行
【发布时间】:2021-10-11 06:25:30
【问题描述】:

我有两张桌子:(A) 健身房的顾客和 (B) 餐厅的顾客。我想在表 (A) 中创建一个指标来指示同一天去过健身房和餐厅的顾客。为此,我使用了以下 SQL 脚本,但它创建了重复的行:

SELECT *,
CASE WHEN a.GymDate = b.RestaurantDate THEN 'Meal + Gym on the same day'
ELSE 'Gym Only' END AS 'Meal+Gym'
FROM Table_A a
LEFT JOIN Table_B b
ON a.customerid = b.customerid;

我可以知道如何只保留 Table_A,但添加了“膳食+健身房”指示器吗?谢谢!

【问题讨论】:

  • 请显示样本数据和所需结果。您有单独的客户表吗?此外,您的描述和查询返回不同的结果。如果某天一个客户同时去,而某天一个客户只去一个怎么办?
  • 它创建了重复的行 - 它更可能是创建重复行的连接,而不是 CASE WHEN。如果 a 中有 2 行 ID 为 1,B 中有 2 行 ID 为 1,则您将获得 4 行。如果通过“创建重复”你的意思是 CASE WHEN 将一些值隐藏到它的 ELSE 中导致行看起来像重复,那是你真正需要用 WHERE 控制的东西
  • A CASE 不会创建行,它只是一个标量表达式。就像如果你有一个像YourColumn + OtherColumn 这样的表达式不会创建新行。如果您的 FROMWHERE 要求数据集中有哪些行。

标签: sql sql-server join duplicates case


【解决方案1】:

case 表达式不会生成行,它是您的联接生成了重复的行。您可以将日期谓词添加到连接条件,并仅检查是否存在记录,例如

SELECT *,
        CASE WHEN b.customerid IS NOT NULL THEN 'Meal + Gym on the same day'
            ELSE 'Gym Only' 
        END AS [Meal+Gym]
FROM Table_A a
      LEFT JOIN Table_B b
          ON a.customerid = b.customerid
          AND a.GymDate = b.RestaurantDate;

如果每个客户/日期的 table_B 不是唯一的,那么您可能需要执行以下操作来防止重复:

SELECT *,
       CASE WHEN r.RestaurantVisit IS NOT NULL THEN 'Meal + Gym on the same day'
            ELSE 'Gym Only' 
       END AS [Meal+Gym]
FROM Table_A a
    OUTER APPLY 
    (    SELECT TOP 1 1
         FROM   Table_B b
         WHERE  a.customerid = b.customerid
         AND    a.GymDate = b.RestaurantDate
    ) AS r (RestaurantVisit);

注意虽然使用单引号适用于列别名,但这根本不是一个好习惯,因为它使您的列别名与字符串文字(而不是上下文)无法区分。即使这对您来说很清楚,但对其他人来说可能不是,并且由于阅读:编写代码的比例约为 10:1,因此编写易于阅读的代码很重要。因此,我使用方括号代替您的列名

【讨论】:

    【解决方案2】:

    我会从一张顾客表开始,这样您就可以得到既没有去过健身房也没有去过餐厅的顾客的指标。

    然后:

    select c.*,
           (case when exists (select 1
                              from table_a a join
                                   table_b b
                                   on a.customerid = b.customerid and
                                      a.GymDate = b.RestaurantDate
                              where a.customerid = c.customerid
                             )
                 then 1 else 0
             end) as same_day_gym_restaurant_flag
    from customers c;
    

    【讨论】:

      【解决方案3】:

      您可以使用CASE WHEN EXISTS 代替LEFT JOIN

      SELECT *,
      CASE WHEN EXISTS (
         SELECT 1 FROM Table_B b
         WHERE a.customerid = b.customerid
         AND a.GymDate = b.RestaurantDate)
         THEN 'Meal + Gym on the same day'
         ELSE 'Gym Only'
         END AS 'Meal+Gym'
      FROM Table_A a
      

      这假设您在结果中不需要 Table_B 中的任何数据。

      【讨论】:

        猜你喜欢
        • 2016-07-08
        • 1970-01-01
        • 2021-12-23
        • 2011-08-27
        • 1970-01-01
        • 2012-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多