【问题标题】:Pivoting Snowflake query with dynamic date values in either SQL/Python在 SQL/Python 中使用动态日期值透视雪花查询
【发布时间】:2020-05-17 10:44:11
【问题描述】:

我已经在这个网站上搜索了很多关于此的主题,但无法实施任何解决方案。我正在使用雪花来提取数据,然后使用数据透视函数来转置表格。问题是我必须在数据透视函数中指定静态字段。在我的查询中,我将日期范围设为 90 天,因此不断更改日期并不是很有效。我正在使用雪花连接在 Jupyter 中提取数据,因此 python 是一个选项。

示例查询(可行):

select * from (
   select date, id, count(products) as prod_count 
   from table1 where date >= '2019-01-01' and date <= '2019-01-05' 
   group by 1, 2) d
pivot (
   max(prod_count) for date in ('2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04', '2019-01-05')) piv 

我尝试在“for date in”部分中传递一个选择不同的日期查询,但这不起作用。我还尝试创建单独的数据框和包含所有日期的 python 列表,然后将它们传递进去,但这也不起作用。我还在这个论坛上尝试了各种其他解决方案,但它们似乎专注于 TSQL 或 SQL Server 语法,这在我的情况下不起作用(至少在我尝试时..)感谢任何帮助。

编辑:

显示输入与预期输出的示例:

输入:

Date        ID  Products
2019-01-01  1   A
2019-01-01  1   B
2019-01-01  2   A
2019-01-02  1   A
2019-01-02  1   B
2019-01-02  1   C
2019-01-02  2   A
2019-01-02  2   B

当前(和预期,但日期动态)输出:

ID  2019-01-01   2019-01-02
1   2            3
2   1            2

【问题讨论】:

  • 您能否展示一些数据样本以及动态部分需要放在哪里?
  • @Datanovice 编辑了我的帖子以向您展示示例
  • 谢谢,SQL 查询或 Python 代码到底需要动态什么?从您的输出中,无论日期如何,一个简单的 pivot 或 groupby 总是会给出相同的结果?
  • @Datanovice 在 SQL 查询中可以看到日期 >= 2019-01-01 和日期
  • 知道了,等一下,我会用 Python 提供答案。

标签: python sql pandas snowflake-cloud-data-platform


【解决方案1】:

这对于评论来说太长了,但我对 Python 的了解还不够多,无法为您提供功能齐全的答案。不过,我可以解释一下构建动态支点的方法。

一旦您的结果集就位,请使用工具从您将要旋转并转换为列名称的列中获取不同值的列表。在这种情况下,这似乎是您的date 列。至于工具,SQL SELECT DISTINCT 可以工作,但 Python 可以做同样的事情。一种或另一种方式,获取值列表,用逗号分隔它们并在需要时将它们包装在分隔符中(并且对于需要它的日期),然后将该逗号分隔的列表保存到字符串变量中。这在 Python 中可能更容易实现,但我也认为it can be done in Snowflake。无论你更舒服。

接下来,您将使用该列名列表来构建另一个变量,该变量将包含您的其余查询。在 IN 子句中,您将在列列表中附加上面的变量。

SET @queryText = 'select * from (
   select date, id, count(products) as prod_count 
   from table1 where date >= '2019-01-01' and date <= '2019-01-05' 
   group by 1, 2) d
pivot (
   max(prod_count) for date in (' + @listOfColumnValues + ')) piv '

最后,执行@queryText 中包含的查询。

【讨论】:

  • 遵循这些说明并在 SET @queryText 片段上收到语法错误。
  • 我一点也不惊讶。如前所述,这是一种方法,而不是解决方案。您将需要填补空白,或者等着看是否有人为您提供更具体的东西。
【解决方案2】:

如果范围是 90 天,您可以调整函数,但我们可以做的是返回一个动态查询,其中包含您的动态参数作为输入:

import pandas as pd


def generate_sql_dates(start_date="2019-01-01", end_date="2019-01-05"):
"""Date Generator, takes in a start and end date"""
   date_arrays = pd.date_range(start_date, end_date,freq='D')

   pivot_dates = tuple([x.strftime("%Y-%m-%d") for x in date_arrays])

   return f"""select * from (
   select date, id, count(products) as prod_count 
   from table1 where date >= '{start_date}' and date <= '{end_date}'
   group by 1, 2) d
   pivot (
   max(prod_count) for date in {pivot_dates}) piv"""

运行返回:

qry = generate_sql_dates('2019-03-05','2019-04-05')
print(qry)

输出:

select * from (
   select date, id, count(products) as prod_count 
   from table1 where date >= '2019-03-05' and date <= '2019-04-05'
   group by 1, 2) d
   pivot (
   max(prod_count) for date in ('2019-03-05', '2019-03-06', '2019-03-07', '2019-03-08', '2019-03-09', '2019-03-10', '2019-03-11', '2019-03-12', '2019-03-13', '2019-03-14', '2019-03-15', '2019-03-16', '2019-03-17', '2019-03-18', '2019-03-19', '2019-03-20', '2019-03-21', '2019-03-22', '2019-03-23', '2019-03-24', '2019-03-25', '2019-03-26', '2019-03-27', '2019-03-28', '2019-03-29', '2019-03-30', '2019-03-31', '2019-04-01', '2019-04-02', '2019-04-03', '2019-04-04', '2019-04-05')) piv

现在如果您的日期需要是动态的,即您每天运行它并希望它从触发器开始,您可以使用 datetime 函数,就像 SQL 中的GETDATE()

start = (pd.to_datetime('today')).strftime('%Y-%m-%d')
end = (pd.to_datetime('today') + pd.DateOffset(days=90)).strftime('%Y-%m-%d')

然后您可以将它们传递给函数 - 或将它们保留为默认值。

【讨论】:

  • 抱歉耽搁了,我一会儿试试。如果它解决了我的问题,会告诉你 - 谢谢!!
  • @cexcelc 很高兴这对您有所帮助,如果您需要任何其他帮助,请告诉我
  • 嘿,这个解决方案有效,谢谢!我现在遇到的唯一问题是将它与 Jupyter 中的 %%snowflake 函数结合起来。我无法弄清楚如何在 Jupyter 中实际执行查询,因为我收到了语法错误。例如“%%snowflake Using... Using... qry”不起作用。也不使用 select * from ({{qry}})"
  • @cexcelc 我不知道对不起!最好问一个新问题
【解决方案3】:

我将在类似问题How to pivot on dynamic values in Snowflake 上保留此答案的最新版本。

我编写了一个 Snowflake 存储过程来获取 Snowflake 内部的动态枢轴,三个步骤:

  1. 查询
  2. 调用存储过程call pivot_prev_results()
  3. 查找结果select * from table(result_scan(last_query_id(-2)))

程序:

create or replace procedure pivot_prev_results()
returns string
language javascript
execute as caller as
$$
  var cols_query = `
      select '\\'' 
        || listagg(distinct pivot_column, '\\',\\'') within group (order by pivot_column)
        || '\\'' 
      from table(result_scan(last_query_id(-1)))
  `;
  var stmt1 = snowflake.createStatement({sqlText: cols_query});
  var results1 = stmt1.execute();
  results1.next();
  var col_list = results1.getColumnValue(1);
  
  pivot_query = `
         select * 
         from (select * from table(result_scan(last_query_id(-2)))) 
         pivot(max(pivot_value) for pivot_column in (${col_list}))
     `
  var stmt2 = snowflake.createStatement({sqlText: pivot_query});
  stmt2.execute();
  return `select * from table(result_scan('${stmt2.getQueryId()}'));\n  select * from table(result_scan(last_query_id(-2)));`;
$$;

查看https://hoffa.medium.com/dynamic-pivots-in-sql-with-snowflake-c763933987c了解更多信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-28
    • 1970-01-01
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多