case 语句中的多个条件重复表中的行

Posted

技术标签:

【中文标题】case 语句中的多个条件重复表中的行【英文标题】:multiple conditions in a case statement duplicates lines in the table 【发布时间】:2021-07-27 20:17:32 【问题描述】:

我正在尝试根据以下案例语句的条件对客户端进行集群,在我添加此内容之前一切正常 - 并且 pbs.pb_plano_assinatura != "Anual" - 之后,它重复了一些行和此 case 语句对应的列的值为 null。我知道这段代码有点混乱,这只是更大查询的一部分,我很想知道如何做这种操作的任何建议,这个查询涉及多个连接,所以我想我不能把它变成物化视图。无论如何,欢迎任何帮助。谢谢!

CASE 
  WHEN ((IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding))) < date("2021-02-25") AND pbs.pb_plano_assinatura != "Anual") THEN "Mensal Antigo"
  WHEN ((IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding))) >= date("2021-02-25") and (IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding))) < date("2021-06-02") AND pbs.pb_plano_assinatura != "Anual") and pb_codigo_promocional is NULL THEN "Mensal Pgto Entrada"
  WHEN ((IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding))) >= date("2021-06-02") AND pbs.pb_plano_assinatura != "Anual") THEN "Mensal Gratuidade" 
  WHEN ((IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding))) >= date("2021-02-25") and (IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding))) < date("2021-06-02") AND pbs.pb_plano_assinatura != "Anual") and pb_codigo_promocional is not NULL THEN "Mensal Cupom"  
  WHEN (pbs.pb_plano_assinatura = "Anual" AND p.value >= 250.0 AND p.status IN('RECEIVED' ,'CONFIRMED', 'RECEIVED_IN_CASH') AND p.originalDueDate = min(p.originalDueDate) over (partition by pbs.pb_id)) OR PBS.pb_id = 'ddcdff35-a044-5ccc-a65d-7e51692b269a' THEN "Anual Entrada" 
  WHEN ((IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding))) < date("2021-02-25"))AND(pbs.pb_plano_assinatura = "Anual" AND p.value < 250.0 AND p.status IN('RECEIVED' ,'CONFIRMED', 'RECEIVED_IN_CASH') AND p.originalDueDate = min(p.originalDueDate) over (partition by  pbs.pb_id)) THEN "Mensal Antigo"
  WHEN ((IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding))) >= date("2021-02-25")and (IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding))) < date("2021-06-02")) and pb_codigo_promocional is NULL AND(pbs.pb_plano_assinatura = "Anual" AND p.value < 250.0 AND p.status IN('RECEIVED' ,'CONFIRMED', 'RECEIVED_IN_CASH') AND p.originalDueDate = min(p.originalDueDate) over (partition by  pbs.pb_id)) THEN "Mensal Pgto Entrada"
  WHEN ((IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding))) >= date("2021-06-02"))AND(pbs.pb_plano_assinatura = "Anual" AND p.value < 250.0 AND p.status IN('RECEIVED' ,'CONFIRMED', 'RECEIVED_IN_CASH') AND p.originalDueDate = min(p.originalDueDate) over (partition by  pbs.pb_id)) THEN "Mensal Gratuidade"
  WHEN ((IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding))) >= date("2021-02-25")AND (IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding))) < date("2021-06-02")) and pb_codigo_promocional is not NULL AND(pbs.pb_plano_assinatura = "Anual" AND p.value < 250.0 AND p.status IN('RECEIVED' ,'CONFIRMED', 'RECEIVED_IN_CASH') AND p.originalDueDate = min(p.originalDueDate) over (partition by  pbs.pb_id)) THEN "Mensal Cupom" 
  END as pb_safra,  

【问题讨论】:

【参考方案1】:

我会推荐两个步骤来清理 SQL 语句。 case 语句本身不能重复任何行。

将case语句拆分成多个部分

在这种情况下多次使用的计算语句应设置为内部选择语句中的列值 在case语句中加入case语句

作为建议,请检查自己,因为我没有要测试的数据集。

select * except(pb_safra_tmp,Anual,pok,pset,SGorder1,ISminOrginalDueDate) ,
ifnull(pb_safra_tmp ,
    Case when Anual AND not pset AND pok AND ISminOrginalDueDate OR PBS_pb_id = 'ddcdff35-a044-5ccc-a65d-7e51692b269a' 
        THEN "Anual Entrada" end
    )as pb_safra
from(
Select *,
 
CASE 
 WHEN SGorder1 < date("2021-02-25") then 
    Case
        When not Anual THEN "Mensal Antigo"
        When Anual AND pok and pset AND ISminOrginalDueDate THEN "Mensal Antigo"
    end
 WHEN SGorder1 >= date("2021-02-25") and SGorder1 < date("2021-06-02") then
    Case 
        when not Anual then if (pb_codigo_promocional is NULL, "Mensal Pgto Entrada", "Mensal Cupom" )
        when Anual AND pok and pset AND ISminOrginalDueDate THEN if (pb_codigo_promocional is NULL, "Mensal Pgto Entrada", "Mensal Cupom")
    end
 WHEN SGorder1 >= date("2021-06-02") then
    case
        when not Anual THEN "Mensal Gratuidade" 
        when Anual AND pok and pset AND ISminOrginalDueDate THEN "Mensal Gratuidade"
    end
#else null
 END as pb_safra_tmp, 
 
 
  FROM
 (
 SELECT *, pbs.pb_id as pbs_pb_id,
 IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding)) as SGorder1,
 p.value < 250.0 as pset,
 p.status IN('RECEIVED' ,'CONFIRMED', 'RECEIVED_IN_CASH') as pok,
 pbs.pb_plano_assinatura = "Anual" as Anual,
 p.originalDueDate =  min(p.originalDueDate) over (partition by pbs.pb_id)   as ISminOrginalDueDate
 


from # dummy table
(select current_date() as  originalDueDate, 55 value, 'RECEIVED' status  ) as p cross join 
(select current_date() as order_created_at , 5 pb_codigo_promocional ) as o cross join 
(select current_date() as order_created_at, current_date() as pb_dt_onboarding , current_date() pb_dt_primeiro_onboarding,
 "Anual" pb_plano_assinatura ,  " " pb_id) as PBS

 )
)

UDF - 清理代码的函数

这是解决这些复杂case语句的最佳方式。将其拆分为上面有用的部分后,现在可以将其转换为 UDF。 select 语句可读性很好。

CREATE TEMP FUNCTION pb_safra(SGorder1 date,Anual bool, PBS_pb_id string)
  RETURNS string
  AS 
  (
    ifnull(
    Case
    WHEN SGorder1 < date("2021-02-25") then 
        Case
        When not Anual THEN "Mensal Antigo"
        When Anual #AND pok and pset AND ISminOrginalDueDate 
            THEN "Mensal Antigo"
        end
    # the other cases ....
    end, 
      case when Anual #AND not pset AND pok AND ISminOrginalDueDate
        or PBS_pb_id = 'ddcdff35-a044-5ccc-a65d-7e51692b269a'  then "Anual Entrada" end  
      )

  )
  ;
   
  SELECT *, 
    pb_safra(
         IF (o.order_created_at < pbs.pb_dt_onboarding, date(pbs.pb_dt_primeiro_onboarding), date(pbs.pb_dt_onboarding)), #SGorder1
         pbs.pb_plano_assinatura = "Anual", # Anual
         PBS.pb_id
 ) as pb_safra

【讨论】:

以上是关于case 语句中的多个条件重复表中的行的主要内容,如果未能解决你的问题,请参考以下文章

select语句如何找重复的信息

c# 8.0 switch 表达式中的多个案例[重复]

同一个 SQL 语句中的多个条件计数 [重复]

switch 语句中的多个情况

sql中的case语句对齐和清理

条件删除表中重复的列