【问题标题】:Transact SQL CASE over a variable length input_expression通过可变长度 input_expression 处理 SQL CASE
【发布时间】:2009-08-06 15:41:07
【问题描述】:

我必须制作一份关于使用不同信用卡类型进行的交易数量的临时报告。出于报告的目的,可以假设所有以 4 开头的信用卡都是 VISA 卡,而以 5 开头的信用卡是 MasterCard。

此查询适用于上述区别:

select card_type = 
    case substring(pan,1,1) 
        when '4' then 'VISA'
        when '5' then 'MasterCard'
        else 'unknown' 
    end,count(*),
    sum(amount)
from transactions
group by card_type

但是在我们的情况下(不确定这在全球范围内如何运作)所有以 3 开头的卡都可以被视为大来卡,但以 37 开头的那些是美国运通卡。

像这样扩展上述查询似乎是一个完整的黑客攻击

select card_type = 
    case substring(pan,1,2) 
        when '30' then 'Diners'
        ...
        when '37' then 'AMEX'
        ...
        when '39' then 'Diners'
        when '40' then 'VISA'
        ...
        when '49' then 'VISA'
        when '50' then 'MasterCard'  
        ...
        when '59' then 'MasterCard'  
        else 'unknown' 
    end,count(*),
    sum(amount)
from transactions
group by card_type

除了前两位数字与特殊情况匹配外,是否有一种优雅的方法可以在所有情况下按第一位数字进行分组?

我也不知道该怎么写标题如果有人想帮忙的话……

编辑:我把 MasterCard 和 VISA 的值弄混了,所以只是正确的 :)

【问题讨论】:

  • 这个答案几乎让我的问题看起来很傻,不敢相信我从来没有见过这个。谢谢。

标签: sql tsql case


【解决方案1】:

你可以做如下的case语句:

select case
    when substring(pan,1,2) = '37' then 'AMEX'
    when substring(pan,1,1) = '3' then 'Diners'
    when substring(pan,1,1) = '4' then 'Mastercard'
    when substring(pan,1,1) = '5' then 'VISA'
    else 'unknown' 
end,
count(*),
sum(amount)
from transactions
group by card_type

【讨论】:

  • +1 完美答案。还应该补充一点,案例陈述的顺序很重要;在检查“3”之前检查“37”,否则“3”将首先触发
【解决方案2】:

不确定您的系统,但在 Oracle CASE 表达式中正是如此,因此您可以嵌套它们:

case substring(pan,1,1)
        when '3' then case substring(pan,2,1)
                             when '7' then 'Amex'
                             else 'Diners'
                      end
        when '4' then 'VISA'
        when '5' then 'MasterCard'  
        else 'unknown'
end

【讨论】:

  • 除了 T-SQL 中缺少的 'end' 关键字之外,以上是我要建议的内容。
  • 哎呀,添加了“结束”——Oracle 也需要
【解决方案3】:

您可以将卡片类型列存储在您的表中,并将 FK 存储到卡片类型表中,或者尝试类似的方法:

CASE
    WHEN LEFT(pan,2)='37' then ...
    WHEN LEFT(pan,1)='3' then ...
    .....

编辑
您真的应该考虑将卡片类型值存储在表中。插入时确定一次,然后您就可以查询您的数据,而无需每次都跳过这些箍。如果算法在某个时候发生变化,您也会保护自己,所有现有数据都是正确的

【讨论】:

  • 将卡片类型存储在表中显然是一个更好的解决方案。但是像我们大多数人一样,我相信你不得不使用其他人都害怕修改的遗留系统。如果这份报告要更频繁地运行,我会更加努力地争取更好的解决方案。
【解决方案4】:

就个人而言,我认为您的“普通”方式很优雅,因为它比我找到答案@samjudson 更容易阅读和维护(但我确实看到了他们的方法的吸引力)。您可以使用OR 在每个案例中测试多个值。我发现LIKE 更容易阅读,但那可能就是我;)例如

CASE
   WHEN card_type LIKE '37%' 
      THEN 'AMEX'
   WHEN (
         card_type LIKE '30%' 
         OR card_type LIKE '39%' 
        )  
      THEN 'Diners'
   WHEN (
         card_type LIKE '40%' 
         OR card_type LIKE '49%' 
        ) 
      THEN 'VISA'
   WHEN (
         card_type LIKE '50%' 
         OR card_type LIKE '59%' 
        ) 
      THEN 'MasterCard'  
   ELSE 
      'unknown' 
END

【讨论】:

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