【问题标题】:CASE Statement instead of inner joinCASE 语句而不是内部连接
【发布时间】:2015-07-09 18:08:14
【问题描述】:

这是我的表结构:

CUST_ID  ORDER_MONTH
---------------------
 1       1
 1       5
 2       3
 2       4

我的目标是将这些客户标记为新客户或回头客。

当我过滤查询时,假设第 1 个月的客户 1 应该有标签“新”,但是当我在第 5 个月过滤它时,客户 1 应该显示为“退货”,因为他已经在第 1 个月进行了购买.

同样的方式客户 ID 2 应该在第 3 个月显示为 New,并在第 4 个月返回。

我想使用 CASE 语句而不是内部联接来执行此操作。

谢谢

【问题讨论】:

  • 为什么你更喜欢大小写而不是连接?
  • 谢谢大家!!一个快速更新我很好奇如果我们想要实现一个复杂的逻辑,比如说客户是否进行了第一次购买,他们是新的,如果他们在第一次购买后的 2 个月内进行第二次购买,他们将返回,或者如果他们在第一次购买后 6 个月进行第二次购买,他们被“重新激活”

标签: mysql sql logic


【解决方案1】:

如果您坚持使用 case 语句,则逻辑类似于“如果这是该用户的第一个月,则写新的,否则写返回。”查询如下:

SELECT CASE 
   WHEN m.month = (SELECT MIN(month) FROM myTable WHERE customer = m.customer) THEN 'New' 
   ELSE 'Returning' END AS customerType
FROM myTable m;

但是,我认为这在JOIN 中会更好,更易读。您可以编写一个聚合查询来获取每个用户的最早月份,然后使用COALESCE() 将空值替换为“返回”。聚合:

SELECT customer, MIN(month) AS minMonth, 'New' AS customerType
FROM myTable
GROUP BY customer ;

剩下的:

SELECT m.customer, m.month, COALESCE(t.customerType, 'Returning') AS customerType
FROM myTable m
LEFT JOIN(
   SELECT customer, MIN(month) AS minMonth, 'New' AS customerType
   FROM myTable
   GROUP BY customer) t ON t.customer = m.customer AND t.minMonth = m.month;

这是一个SQL Fiddle 示例,显示了这两个示例。

【讨论】:

  • 当我们也有年份列时,我们可以做 MIN(month),MIn(year)
  • @sai 你可能不得不以某种方式嵌套它,但想法是相似的。您想选择最早的年份,然后从中选择最早的月份。
【解决方案2】:

您不需要 JOIN 并且 case 语句可能会过大...

SELECT CUST_ID, IF(COUNT(1)>1, 'Returning', 'New') AS blah
FROM the_table
WHERE ORDER_MONTH <= the_month
GROUP BY CUST_ID
;

当然,仅使用月份会在一年后(或者实际上,在十二月之后)引起问题。

这样会更好

SELECT CUST_ID, IF(COUNT(1)>1, 'Returning', 'New') AS blah
FROM the_table
WHERE order_date <= some_date
GROUP BY CUST_ID
;

【讨论】:

    【解决方案3】:

    我不推荐这种方式,但这是你想要的。

    select *
    ,case when order_month = (select MIN(order_month) from #temp t2 where t1.cust_ID =t2.cust_id) THEN 'NEW' ELSE 'Return' end 'Type'
    from #temp t1
    

    【讨论】:

    • CASE 语句不能有选择
    • 为什么不呢?这对我来说很好。我并不是说它的代码很好,但他要求提供一个与我的完全一样的案例声明
    • 我在使用 Teradata,出现 ILLEGAL EXPRESSION IN CASE 错误
    • 我使用的是 SQL Server 2008 R2,没有任何问题。
    【解决方案4】:

    我想我明白你想要做什么。您的案例陈述基本上只需要检查客户的月份是否等于您过滤的月份。像这样的:

    SELECT 
    <your other fields>,
    CASE WHEN Order_Month = <your filter> THEN 'New'   
        ELSE 'Return' 
        END  AS 'SomeName'
    FROM <your table>
    

    【讨论】:

      【解决方案5】:

      试试这个查询

      select a.CUST_ID,  a.ORDER_MONTH ,case when b is not null then 'Return' else 'New' end as type
       from tablename a
      join tablename b on a.CUST_ID=b.CUST_ID and a.ORDER_MONTH>b.ORDER_MONTH
      

      【讨论】:

      • 我相信你应该在这里使用外连接而不是内连接。
      【解决方案6】:
      SELECT *, 
         CASE 
           WHEN EXISTS (SELECT * 
                        FROM   [YourTable] t2 
                        WHERE  t1.cust_id = t2.cust_id 
                               AND t2.order_month < t1.order_month) THEN 'Return' 
           ELSE 'New' 
         END
      FROM   [YourTable] t1 
      

      此查询在 EXISTS 子句上使用 CASE。 EXISTS 位于一个子查询上,该查询在同一个表中查询前几个月的任何行。 如果有前几个月的行,则 EXISTS 为真,CASE 返回“返回”。如果前几个月没有行,则 EXISTS 为 false,CASE 返回“New”。

      【讨论】:

      • 这行得通,而且是一个很好的答案,但在 StackOverflow 上通常不鼓励仅使用代码的答案。您可以为您的答案添加解释吗?
      • 感谢 McAdam331。我是新手。
      • case语句不能有select
      • 赛,select 是exists 子句的一部分,而不是case 子句的一部分。您能否发布您的代码,以便我了解它为什么不适合您?顺便说一句,你在使用 SQL Studio 吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-09
      相关资源
      最近更新 更多