如何在Snowflake的WHERE子句中编写CASE语句

时间:2020-05-28 15:30:40

标签: sql snowflake-cloud-data-platform

我正在尝试重写最初为Vertica编写的一段SQL代码。 Vertica具有AGE_IN_YEARS()内置功能,非常适合提高年龄。但是,现在,我需要找到一种方法使其在Snowflake中工作,而我做到了。

在Snowflake中替换AGE_IN_YEARS(DateOfBirth)的等效语句可以是:

case when dateadd(year, datediff(years, DateOfBirth, CURRENT_DATE), DateOfBirth) > CURRENT_DATE
then datediff(years, DateOfBirth, CURRENT_DATE) -1
else datediff(years, DateOfBirth, CURRENT_DATE)
end as AGE

问题是当我必须在WHERE子句中使用它时。原始的Vertica代码是:

SELECT name, dob,
(SELECT AgeRangeCode
   FROM AgeRangeTable
   WHERE AGE_IN_YEARS(DateOfBirth) BETWEEN MinAge AND MaxAge) AS AgeRangeCode,
CURRENT_DATE as TODAY
from MemberInfoTable

并且如果我将AGE_IN_YEARS()替换添加到上述查询中,则会得到

SQL编译错误:无法评估不受支持的子查询类型

如何在WHERE子句中编写此案例

3 个答案:

答案 0 :(得分:2)

问题是当我必须在WHERE子句中使用它时。

如何将年龄添加到dateofbirth上?

where dateadd(year, minage, dateofbirth) <= current_date and
      dateadd(year, maxage + 1, dateofbirth) > current_date

答案 1 :(得分:1)

不使用函数来计算年龄,而只是将其加入您喜欢的数据即可:

with age_range_table as (
    select * from values (0,16, 'A'),(16,18, 'B'),(18,1000, 'C') v(min_age, max_age, age_range_code)
), member_info_table as (
    select name, dob::date as dob from values ('user_80s', '1980-01-01'),('user_90s', '1990-01-01'),('user_10s', '2010-01-01') v(name, dob)
)
select m.name,
    m.dob,
    a.age_range_code
from member_info_table AS m
join age_range_table AS a
    ON m.dob < dateadd('years',-a.min_age, current_date)
    AND m.dob >= dateadd('years',-a.max_age, current_date);

给予:

NAME    DOB AGE_RANGE_CODE
user_80s    1980-01-01  C
user_90s    1990-01-01  C
user_10s    2010-01-01  A

但是在WHERE子句中进行函数调用有点麻烦。

with age_range_table as (
    select * 
    from values 
        (0,16, 'A'),
        (16,18, 'B'),
        (18,1000, 'C') 
        v(min_age, max_age, age_range_code)
), member_info_table as (
    select name, dob::date as dob 
    from values 
       ('user_80s', '1980-01-01'),
       ('user_90s', '1990-01-01'),
       ('user_10s', '2010-01-01')
       v(name, dob)
), today_age_range_table as (
    select age_range_code
        ,dateadd('years',-min_age, current_date) as range_end_date
        ,dateadd('years',-max_age, current_date) as range_start_date
    from age_range_table
)
select m.name,
    m.dob,
    a.age_range_code
from member_info_table AS m
join today_age_range_table AS a
    ON m.dob < a.range_end_date
    AND m.dob >= a.range_start_date;

贷方说明:这与Gordon的解决方案相同,但已明确显示。并且更改范围逻辑以在CTE中更改所有行的user.dob一次更改范围时间。根据假设,您的用户数超过了范围数,并且如果两个用户均小于1000,则以太币没有问题。

答案 2 :(得分:0)

如果您的年龄范围表中有“年龄”列,并且您希望将每个客户/参与者的年龄与年龄范围表的最小和最大范围进行比较,那么您可以简单地通过两种方式进行操作。

SELECT name, dob,
       [AgeRangeCode] = (SELECT AgeRangeCode FROM AgeRangeTable WHERE DATEDIFF(Year,mi.dob,CURRENT_DATE) = mi.age 
                                                         AND DATEDIFF(Year,mi.dob,CURRENT_DATE) BETWEEN MinAge AND MaxAge),
       CURRENT_DATE as TODAY
from MemberInfoTable mi

或具有如下所示的简单连接

SELECT mi.name, mi.dob, art.AgeRangeCode,
       CURRENT_DATE as TODAY
FROM  MemberInfoTable mi
JOIN  AgeRangeTable art ON art.age = DATEDIFF(Year,mi.dob,CURRENT_DATE)
WHERE DATEDIFF(Year,mi.dob,CURRENT_DATE) BETWEEN art.MinAge AND art.MaxAge