将 3 个案例陈述合并或简化为一个

Posted

技术标签:

【中文标题】将 3 个案例陈述合并或简化为一个【英文标题】:Merging or Simplifying 3 case statements to One 【发布时间】:2020-03-31 17:11:36 【问题描述】:

我会将以下 3 个 case 语句合并为一个并尽可能简化。查询的目的是根据 3 列找出任何具有无效或有效电话号码的成员。如果任何列具有有效的电话号码,则它是有效的。如果全部无效,则视为无效。任何帮助都会很棒。

    CASE 
        WHEN REGEXP_REPLACE(DAY_PH, '[^[:digit:]'''']', NULL) IS NULL
            THEN 1
  WHEN REGEXP_REPLACE(DAY_PH, '[^[:digit:]'''']', NULL) ='9999999999'
    THEN 1
        WHEN LENGTH(TRIM(REGEXP_REPLACE(DAY_PH, '[^[:digit:]'''']', NULL))) = 10
            THEN 0
        ELSE 1
        END INVALID_DAY_PH,
    CASE 
        WHEN REGEXP_REPLACE(EVE_PH, '[^[:digit:]'''']', NULL) IS NULL
            THEN 1
  WHEN  REGEXP_REPLACE(EVE_PH, '[^[:digit:]'''']', NULL)='9999999999'
    THEN 1  
        WHEN LENGTH(TRIM(REGEXP_REPLACE(EVE_PH, '[^[:digit:]'''']', NULL))) = 10
            THEN 0
        ELSE 1
        END INVALID_EVE_PH,
    CASE 
        WHEN REGEXP_REPLACE(MOB_PH, '[^[:digit:]'''']', NULL) IS NULL
            THEN 1
   WHEN REGEXP_REPLACE(MOB_PH, '[^[:digit:]'''']', NULL)='9999999999'
    THEN 1  
        WHEN LENGTH(TRIM(REGEXP_REPLACE(MOB_PH, '[^[:digit:]'''']', NULL))) = 10
            THEN 0
        ELSE 1
        END INVALID_MOB_PH,

【问题讨论】:

您能否逐字说明在哪些情况下电话号码无效? 当然,1)。如果 3 列为空白则无效.. 2). 如果 3 列全部为 999999999 - 10 位则无效..1 和 2 可以像 2 列有空白和第 3 列全部为 9 一样无效..跨度> 显示所有排列的示例数据和您想要的结果可能会使这更清楚一点。为什么你的正则表达式类中有单引号(两次);为什么 9999999999 是一个神奇的数字? 【参考方案1】:

您可以通过将正则表达式调用推入内联视图或 CTE 来简化一点,这样您就不必重复它们:

select id, day_ph, eve_ph, mob_ph,
  case when length(day_ph_cln) = 10 and day_ph_cln != '9999999999'
    then 0 else 1 end as invalid_day_ph,
  case when length(eve_ph_cln) = 10 and eve_ph_cln != '9999999999'
    then 0 else 1 end as invalid_eve_ph,
  case when length(mob_ph_cln) = 10 and mob_ph_cln != '9999999999'
    then 0 else 1 end as invalid_mob_ph
from (
  select id, day_ph, eve_ph, mob_ph,
    regexp_replace(day_ph, '[^[:digit:]'''']') as day_ph_cln,
    regexp_replace(eve_ph, '[^[:digit:]'''']') as eve_ph_cln,
    regexp_replace(mob_ph, '[^[:digit:]'''']') as mob_ph_cln
  from your_table
);

trim() 似乎没有做任何事情,所以我把它省略了 - 正则表达式已经删除了所有空格,因为它们不是数字(或单引号......我已经离开了模式完好无损,但不确定它是否有意义......)

如果您想要一个最终标志来显示是否所有其他标志都无效,那么您可以使用least(),如果其他三个标志中的任何一个为零,它将给您零,否则为 1。

select id, day_ph, eve_ph, mob_ph,
  case when length(day_ph_cln) = 10 and day_ph_cln != '9999999999'
    then 0 else 1 end as invalid_day_ph,
  case when length(eve_ph_cln) = 10 and eve_ph_cln != '9999999999'
    then 0 else 1 end as invalid_eve_ph,
  case when length(mob_ph_cln) = 10 and mob_ph_cln != '9999999999'
    then 0 else 1 end as invalid_mob_ph,
  least(
    case when length(day_ph_cln) = 10 and day_ph_cln != '9999999999'
      then 0 else 1 end,
    case when length(eve_ph_cln) = 10 and eve_ph_cln != '9999999999'
      then 0 else 1 end,
    case when length(mob_ph_cln) = 10 and mob_ph_cln != '9999999999'
      then 0 else 1 end
  ) as all_invalid
from (
  select id, day_ph, eve_ph, mob_ph,
    regexp_replace(day_ph, '[^[:digit:]'''']') as day_ph_cln,
    regexp_replace(eve_ph, '[^[:digit:]'''']') as eve_ph_cln,
    regexp_replace(mob_ph, '[^[:digit:]'''']') as mob_ph_cln
  from your_table
);

或使用其他级别的子查询(或 CTE)来删除重复:

select id, day_ph, eve_ph, mob_ph,
  invalid_day_ph, invalid_eve_ph, invalid_mob_ph,
  least(invalid_day_ph, invalid_eve_ph, invalid_mob_ph) as all_invalid
from (
  select id, day_ph, eve_ph, mob_ph,
    case when length(day_ph_cln) = 10 and day_ph_cln != '9999999999'
      then 0 else 1 end as invalid_day_ph,
    case when length(eve_ph_cln) = 10 and eve_ph_cln != '9999999999'
      then 0 else 1 end as invalid_eve_ph,
    case when length(mob_ph_cln) = 10 and mob_ph_cln != '9999999999'
      then 0 else 1 end as invalid_mob_ph
  from (
    select id, day_ph, eve_ph, mob_ph,
      regexp_replace(day_ph, '[^[:digit:]'''']') as day_ph_cln,
      regexp_replace(eve_ph, '[^[:digit:]'''']') as eve_ph_cln,
      regexp_replace(mob_ph, '[^[:digit:]'''']') as mob_ph_cln
    from your_table
  )
);

如果您想要最后一个标志,那么您可以组合大小写表达式:

select id, day_ph, eve_ph, mob_ph,
  case when (length(day_ph_cln) = 10 and day_ph_cln != '9999999999')
         or (length(eve_ph_cln) = 10 and eve_ph_cln != '9999999999')
         or (length(mob_ph_cln) = 10 and mob_ph_cln != '9999999999')
    then 0 else 1 end as all_invalid
from (
  select id, day_ph, eve_ph, mob_ph,
    regexp_replace(day_ph, '[^[:digit:]'''']') as day_ph_cln,
    regexp_replace(eve_ph, '[^[:digit:]'''']') as eve_ph_cln,
    regexp_replace(mob_ph, '[^[:digit:]'''']') as mob_ph_cln
  from your_table
);

您没有提供任何样本数据来验证这是否提供了您想要的结果;但是here's a db<>fiddle 有一些非常基本的虚构数据。

【讨论】:

提供的答案和示例非常好,感谢您抽出宝贵时间,我不打算使用 CTE 或派生表。我想将所有 3 个电话号码合并为一个,这意味着我需要自定义列 - 基于 3 个电话号码的 Y/N。如果有效 Y,否则为 N。 使用 Y/N 代替 0/1 不是问题。 (对于某些示例,可能需要最大而不是最小)。我不确定您为什么不想使用 CTE/内联视图/派生表。这应该是结果集中的额外列,还是实际基表中的列?相同的逻辑可以用于虚拟列。

以上是关于将 3 个案例陈述合并或简化为一个的主要内容,如果未能解决你的问题,请参考以下文章

计数,拥有和案例陈述

使用 2 个不同字段的案例陈述

用于更新表但多列的 DB2 案例语句

结合案例陈述[重复]

为什么我们需要突破案例陈述?

案例表达与案例陈述