SQL:如何删除由 CASE WHEN 语句创建的重复行

Posted

技术标签:

【中文标题】SQL:如何删除由 CASE WHEN 语句创建的重复行【英文标题】:SQL: How to remove duplicate rows created by CASE WHEN statement 【发布时间】: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 要求数据集中有哪些行。 【参考方案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 中的任何数据。

【讨论】:

以上是关于SQL:如何删除由 CASE WHEN 语句创建的重复行的主要内容,如果未能解决你的问题,请参考以下文章

SQL Select CASE-WHEN - 如何从电话号码中删除格式

SQL语句中case,when,then的用法

将 SQL CASE WHEN 语句转换为 C#

SQL查询语句SELECT中带有case when嵌套子查询判断的问题

sql语句借助case when实现自动拼装where条件

如何从 case when 中删除 NULL 然后输出 Oracle SQL Developer