【问题标题】:Storing Variable in BigQuery SQL UDF在 BigQuery SQL UDF 中存储变量
【发布时间】:2021-12-16 09:57:59
【问题描述】:

我正在尝试在 bigQuery 中创建一个 SQL UDF 来计算每月的周数。我得到了我期望的结果,但我的函数看起来超级混乱。

create or replace function internal.week_in_month(my_date TIMESTAMP)
returns FLOAT64 as
(

case when 
        (case when EXTRACT(DAYOFWEEK FROM date_add(date(my_date), INTERVAL -(EXTRACT(DAY FROM my_date))+1 day)) = 1 then 7 
                          else EXTRACT(DAYOFWEEK FROM date_add(date(my_date), INTERVAL -(EXTRACT(DAY FROM my_date))+1 day)) -1 end) > 1 then -- check first day of month to decide if it's a complete week (starts on Monday)
                case when EXTRACT(DAY FROM my_date) <= 7 then -- for incomplete week
                    case when 
                            (case when EXTRACT(DAYOFWEEK FROM my_date) = 1 then 7 else EXTRACT(DAYOFWEEK FROM my_date)-1 end)  -  EXTRACT(DAY FROM my_date) =
                                 (case when EXTRACT(DAYOFWEEK FROM date_add(date(my_date), INTERVAL -(EXTRACT(DAY FROM my_date))+1 day)) = 1 then 7 
                                   else EXTRACT(DAYOFWEEK FROM date_add(date(my_date), INTERVAL -(EXTRACT(DAY FROM my_date))+1 day)) -1 end) -1 then 1 -- incomplete week 1
                      else FLOOR(( EXTRACT(DAY FROM my_date) + (case when EXTRACT(DAYOFWEEK FROM date_add(date(my_date), INTERVAL -(EXTRACT(DAY FROM my_date))+1 day)) = 1 then 7
                                                                 else EXTRACT(DAYOFWEEK FROM date_add(date(my_date), INTERVAL -(EXTRACT(DAY FROM my_date))+1 day)) -1 end) -2 )/7)+1 end  -- calculate week based on date
            else FLOOR(( EXTRACT(DAY FROM my_date) + (case when EXTRACT(DAYOFWEEK FROM date_add(date(my_date), INTERVAL -(EXTRACT(DAY FROM my_date))+1 day)) = 1 then 7 
                                                         else EXTRACT(DAYOFWEEK FROM date_add(date(my_date), INTERVAL -(EXTRACT(DAY FROM my_date))+1 day)) -1 end) -2 )/7)+1 end -- calculate week based on date
     else FLOOR((EXTRACT(DAY FROM my_date)-1)/7)+1 -- for complete week
        end
)

有没有办法在 bigQuery 中存储变量,这样我的代码看起来不会那么混乱?到目前为止,我一直在阅读 bQ 文档,但还没有找到在函数内部存储变量的方法(对于 SQL UDF)

任何帮助将不胜感激,谢谢!

【问题讨论】:

    标签: sql google-bigquery bigquery-udf


    【解决方案1】:

    同意 - 它看起来很丑!
    所以,我看到你正在重用下面的表达式八(8)次

    EXTRACT(DAYOFWEEK FROM date_add(date(my_date), INTERVAL -(EXTRACT(DAY FROM my_date))+1 day))         
    

    考虑以下方法来重构您的初始代码,以便将该表达式仅在 ABC 别名/字段中使用一次,然后以“可变”方式重用它

    create or replace function internal.week_in_month(my_date TIMESTAMP)
    returns FLOAT64 as
    ((
    select case 
      when (case when ABC = 1 then 7 else ABC -1 end) > 1 then -- check first day of month to decide if it's a complete week (starts on Monday)
        case when EXTRACT(DAY FROM my_date) <= 7 then -- for incomplete week
          case when 
           (case when EXTRACT(DAYOFWEEK FROM my_date) = 1 then 7 else EXTRACT(DAYOFWEEK FROM my_date)-1 end)  -  EXTRACT(DAY FROM my_date) =
              (case when ABC = 1 then 7 
                else ABC -1 end) -1 then 1 -- incomplete week 1
              else FLOOR(( EXTRACT(DAY FROM my_date) + (case when ABC = 1 then 7
            else ABC -1 end) -2 )/7)+1 end  -- calculate week based on date
          else FLOOR(( EXTRACT(DAY FROM my_date) + (case when ABC = 1 then 7 
        else ABC -1 end) -2 )/7)+1 end -- calculate week based on date
      else FLOOR((EXTRACT(DAY FROM my_date)-1)/7)+1 -- for complete week
    end
    from unnest([struct(EXTRACT(DAYOFWEEK FROM date_add(date(my_date), INTERVAL -(EXTRACT(DAY FROM my_date))+1 day)) as ABC)])
    ));
    

    我们可以更进一步,对使用六 (6) 次的 EXTRACT(DAY FROM my_date) 应用相同的方法

    create or replace function internal.week_in_month(my_date TIMESTAMP)
    returns FLOAT64 as
    ((
    select case 
      when (case when ABC = 1 then 7 else ABC -1 end) > 1 then -- check first day of month to decide if it's a complete week (starts on Monday)
        case when XYZ <= 7 then -- for incomplete week
          case when 
           (case when EXTRACT(DAYOFWEEK FROM my_date) = 1 then 7 else EXTRACT(DAYOFWEEK FROM my_date)-1 end)  -  XYZ =
              (case when ABC = 1 then 7 
                else ABC -1 end) -1 then 1 -- incomplete week 1
              else FLOOR(( XYZ + (case when ABC = 1 then 7
            else ABC -1 end) -2 )/7)+1 end  -- calculate week based on date
          else FLOOR(( XYZ + (case when ABC = 1 then 7 
        else ABC -1 end) -2 )/7)+1 end -- calculate week based on date
      else FLOOR((XYZ-1)/7)+1 -- for complete week
    end
    from unnest([struct(EXTRACT(DAY FROM my_date) as XYZ)]),
      unnest([struct(EXTRACT(DAYOFWEEK FROM date_add(date(my_date), INTERVAL -(XYZ)+1 day)) as ABC)])
    ));       
    

    在上面的例子中 - 我很懒,只使用了 XYZ 和 ABC - 希望你会使用适当的命名,这将使我们的最终代码可读性足以让我们满意

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-18
      • 1970-01-01
      • 2019-07-19
      • 2019-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-20
      相关资源
      最近更新 更多