2

我正在尝试在 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)

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

4

1 回答 1

0

同意 - 它看起来很丑!
所以,我看到你正在重用下面的表达式八(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)])
));

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

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)])
));       

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

于 2021-12-16T23:03:43.660 回答