在 SQL/Python 中使用动态日期值旋转 Snowflake 查询
Pivoting Snowflake query with dynamic date values in either SQL/Python
我在本网站上搜索了很多与此相关的主题,但无法实施任何解决方案。我正在使用 snowflake 提取数据,然后使用 pivot 函数转置 table。问题是我必须在数据透视函数中指定静态字段。在我的查询中,我将日期范围设为 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" 片段中传递一个 select 不同的日期查询,但这不起作用。我也尝试创建单独的数据框和 python 列表,其中包含所有日期并将它们传递进去,但这也不起作用。我还在这个论坛上尝试了各种其他解决方案,但它们似乎专注于 TSQL 或 SQL 服务器语法,这在我的情况下不起作用(至少在我尝试时......)任何帮助都是赞赏。
编辑:
显示输入与预期输出的示例:
输入:
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
这太长了,无法发表评论,但我 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
中包含的查询。
如果范围是 90 天,您可以调整函数,但我们可以做的是 return 以您的动态参数作为输入的动态查询:
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"""
运行 这个 returns :
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
现在,如果您的日期需要是动态的,即您的 运行 每天并希望它以触发器开始,您可以使用日期时间函数,就像 GETDATE()
在 SQL:
start = (pd.to_datetime('today')).strftime('%Y-%m-%d')
end = (pd.to_datetime('today') + pd.DateOffset(days=90)).strftime('%Y-%m-%d')
然后您可以将它们传递给函数 - 或者将它们保留为默认值。
我会保留关于类似问题的最新答案版本 。
我写了一个 Snowflake 存储过程来获取 Snowflake 内部的动态枢轴,3 个步骤:
- 查询
- 调用存储过程
call pivot_prev_results()
- 查找结果
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 了解更多。
我在本网站上搜索了很多与此相关的主题,但无法实施任何解决方案。我正在使用 snowflake 提取数据,然后使用 pivot 函数转置 table。问题是我必须在数据透视函数中指定静态字段。在我的查询中,我将日期范围设为 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" 片段中传递一个 select 不同的日期查询,但这不起作用。我也尝试创建单独的数据框和 python 列表,其中包含所有日期并将它们传递进去,但这也不起作用。我还在这个论坛上尝试了各种其他解决方案,但它们似乎专注于 TSQL 或 SQL 服务器语法,这在我的情况下不起作用(至少在我尝试时......)任何帮助都是赞赏。
编辑:
显示输入与预期输出的示例:
输入:
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
这太长了,无法发表评论,但我 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
中包含的查询。
如果范围是 90 天,您可以调整函数,但我们可以做的是 return 以您的动态参数作为输入的动态查询:
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"""
运行 这个 returns :
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
现在,如果您的日期需要是动态的,即您的 运行 每天并希望它以触发器开始,您可以使用日期时间函数,就像 GETDATE()
在 SQL:
start = (pd.to_datetime('today')).strftime('%Y-%m-%d')
end = (pd.to_datetime('today') + pd.DateOffset(days=90)).strftime('%Y-%m-%d')
然后您可以将它们传递给函数 - 或者将它们保留为默认值。
我会保留关于类似问题的最新答案版本
我写了一个 Snowflake 存储过程来获取 Snowflake 内部的动态枢轴,3 个步骤:
- 查询
- 调用存储过程
call pivot_prev_results()
- 查找结果
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 了解更多。