【问题标题】:Redshift: Executing a dynamic query from a stringRedshift:从字符串执行动态查询
【发布时间】:2017-01-12 22:52:25
【问题描述】:

我想执行存储在 Amazon Redshift 上的字符串字段中的动态 SQL 查询。

我的背景主要是 T-SQL 关系数据库。我曾经动态构建 SQL 语句,将它们存储到变量中并执行它们。我知道 Redshift 可以准备和执行语句,但我想知道是否可以执行存储在字符串字段中的查询。

我有一段代码可以使用 pg_* 系统表在多个表上动态构建下面的代码。每个列/表名都是动态计算的。这是查询输出的示例:

SELECT h_article_id AS key, 'transport_parameters_weight_in_grams' AS col_name, COUNT(DISTINCT transport_parameters_weight_in_grams) AS count_value FROM dv.s_products GROUP BY h_article_id UNION ALL
SELECT h_article_id AS key, 'transport_parameters_width_in_mm' AS col_name, COUNT(DISTINCT transport_parameters_width_in_mm) AS count_value FROM dv.s_products GROUP BY h_article_id UNION ALL
SELECT h_article_id AS key, 'label_owner_info_communication_address' AS col_name, COUNT(DISTINCT label_owner_info_communication_address) AS count_value FROM dv.s_products GROUP BY h_article_id

我想在另一个查询中输入这段动态代码,以便进行一些统计,如下所示:

SELECT col_name, AVG(count_value*1.00) AS avg_count
FROM (
  'QUERY ABOVE'
) A
GROUP BY col_name;

这将输出如下内容:

col_name                                avg_count
transport_parameters_weight_in_grams    1.00
transport_parameters_width_in_mm        1.00
label_owner_info_communication_address  0.60

我这样做的自然方法是将所有内容作为字符串存储在变量中并执行它。但是恐怕Redshift不支持这个。

是否有其他方法可以真正构建动态 SQL 代码?

【问题讨论】:

    标签: sql dynamic amazon-redshift


    【解决方案1】:

    没有。在 Redshift 中运行动态构建的 SQL 代码没有直接的方法。

    您不能像在 MS SQL Server 中那样定义 SQL 变量或创建存储过程。

    您可以创建Python Functions in Redshift,但您将使用 Python 与 SQL 进行编码。

    您可以使用"PREPARE" and "EXECUTE" statements to run "pre-defined" SQL 查询,但您必须在数据库之外创建语句,然后再将它们传递给执行命令。通过在数据库之外创建语句,在某种程度上违背了目的......您可以使用“最喜欢的”编程语言创建任何语句。

    正如我所说,这种基于 SQL 的数据库内动态 SQL 不存在。

    基本上,您需要在应用程序中运行此逻辑,或使用 AWS Data Pipeline 等工具。

    【讨论】:

    • 感谢您的回复。您说“在将它们传递给执行之前,您必须在数据库之外创建语句”。我知道我可以传递语句,但它们几乎是硬编码的(除了 $ 变量)。想象一下,我有一个包含多个 SQL 查询的列的表。是否可以将这些查询传递给EXECUTE 命令?
    • 是的,有可能,但你必须先“准备”它们。
    • 好的,但我仍然不知道这怎么可能。考虑一个包含选择查询的 varchar 列“查询”的表 A。这是prepare 语句的示例,但它似乎过于硬编码。 PREPARE prep_select_plan (int) AS select * from prep1 where c1 = $1;如何引用另一个表的 varchar 字段中包含的查询?
    【解决方案2】:

    我在 Redshift 上使用 Postgre,我遇到了这个问题并找到了解决方案。

    我试图创建一个动态查询,输入我自己的日期。

    date = dt.date(2018, 10, 30)
    
    query = ''' select * from table where date >= ''' + str(my_date) + ''' order by date '''
    

    但是,以这种方式输入时,查询完全忽略了条件。

    但是,如果使用百分号 (%),则可以正确插入日期。

    上述语句的正确写法是:

    query = ''' select * from table where date >= ''' + ''' '%s' ''' % my_date + ''' order by date '''
    

    所以,也许这有帮助,也可能没有。我希望它至少对我的情况有帮助!

    最好的祝愿。

    【讨论】:

      【解决方案3】:

      现在我们已经添加了对存储过程的支持,这成为可能。 "Overview of Stored Procedures in Amazon Redshift"

      例如,此存储过程计算表中的行数并将表名和行数插入到另一个表中。两个表名都作为输入提供。

      CREATE PROCEDURE get_tbl_count(IN source_tbl VARCHAR, IN count_tbl VARCHAR) AS $$
      BEGIN
      EXECUTE 'INSERT INTO ' || quote_ident(count_tbl) 
              || ' SELECT ''' || source_tbl ||''', COUNT(*) FROM ' 
              || quote_ident(source_tbl) || ';' 
      RETURN;
      END;
      $$ LANGUAGE plpgsql;
      

      在您的示例中,要执行的查询可以作为字符串传入。

      【讨论】:

      • 如果需要添加 IF 语句呢?例如,如果您需要根据参数之一的值向 SELECT 语句添加 WHERE 或 AND。你会声明一个字符串,设置它然后执行它吗?
      • GitHub 上提供了几个示例存储过程。他们有使用条件动态 SQL 创建的示例。 github.com/awslabs/amazon-redshift-utils/tree/master/src/…
      猜你喜欢
      • 2019-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多