【问题标题】:Declaring and Setting Variables of Different Data Types in Oracle SQL在Oracle SQL中声明和设置不同数据类型的变量
【发布时间】:2013-06-29 03:22:50
【问题描述】:

我目前正在编写一个 SQL 查询,它首先使用 WITH 运算符和 SELECT 语句创建大量临时表,然后在最后连接所有临时语句。

我所有创建临时表的 SELECT 语句都依赖于某些过滤器......所以我的查询看起来有点像

  WITH 

  table_1 as (
  SELECT  product_id 
          avg(price)
  FROM daily_sales 
  WHERE product_category = 1 
  AND sell_date BETWEEN TO_DATE('2012/01/07','YYYY/DD/MM') AND TO_DATE('2012/30/09','YYYY/DD/MM')
  GROUP BY ds.product_id
  ),

  table_2 as (....
 ),


SELECT FROM table_1 JOIN table_2.... 

我想针对“sell_date”(日期或字符串)的范围和“product_category”(整数值)的不同值运行此查询。

目前,我正在手动替换这些,但我想知道是否可以声明用我在查询顶部设置的变量替换这些硬编码值。

我知道以前可能有人问过这个问题 - 但我很困惑,因为有多种解决方案取决于您使用的 SQL 的确切版本以及您声明的变量类型。

在这种情况下,我正在寻找一种适用于 Oracle SQL 的解决方案,并且我可以在其中指定类型变量。

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    这取决于您运行查询的方式。

    如果您使用 SQL*Plus 或 TOAD 等交互式客户端,则应使用替换变量:

      WITH 
          table_1 as (
          SELECT  product_id 
                  avg(price)
          FROM daily_sales 
          WHERE product_category = &product_cat 
          AND sell_date BETWEEN TO_DATE('&start_date','YYYY/DD/MM') AND TO_DATE('&end_date','YYYY/DD/MM')
          GROUP BY ds.product_id
          ),
    

    每次运行查询时,系统都会提示您为这些变量提供值。如果您想在多个位置使用相同的值,则使用双&符号声明所有出现的变量 - &&product_category - 然后只会提示您一次。 SQL*Plus 文档有更多信息:find out more

    如果您要在存储过程中运行查询,则将值定义为参数...

    procedure process_sales_details
         ( i_product_category in number
           , i_start_date in date
           , i_end_date in date )
    

    ...您在查询中引用的(无论您在哪里声明)...

      WITH 
          table_1 as (
          SELECT  product_id 
                  avg(price)
          FROM daily_sales 
          WHERE product_category = i_product_cat 
          AND sell_date BETWEEN i_start_date AND i_end_date
          GROUP BY ds.product_id
          ),
    

    【讨论】:

      【解决方案2】:

      进一步了解 APC 的回答,在 SQL*Plus 或 SQL Developer 中,您还可以声明可以在匿名 PL/SQL 块中为其赋值的变量,然后在纯 SQL 查询中作为绑定变量引用:

      variable v_product_cat number;
      variable v_start_date varchar2(10);
      variable v_end_date varchar2(10);
      
      begin
          :v_product_cat := 1;
          :v_start_date := '2012/01/07';
          :v_end_date := '2012/30/09';
      end;
      /
      
      WITH table_1 as (
          SELECT  product_id 
                  avg(price)
          from daily_sales 
          where product_category = :v_product_cat 
          AND sell_date BETWEEN TO_DATE(:v_start_date,'YYYY/DD/MM')
              AND TO_DATE(:v_end_date,'YYYY/DD/MM')
          group by ds.product_id
      )
      ...
      

      注意变量名前的: 表示绑定变量,并且在这种形式中,字符串没有用引号括起来。不幸的是,您不能声明 date 变量,这会使这更加整洁。

      如果您使用替换变量,您可以在开始时define 它们,这样您就不会收到提示;在这种情况下,您也不需要使用 && 表示法:

      define v_product_cat=1
      define v_start_date=2012/01/07
      define v_end_date=2012/30/09
      
      ...
          where product_category = &v_product_cat 
          and sell_date between to_date('&v_start_date','YYYY/DD/MM')
              AND TO_DATE('&v_end_date','YYYY/DD/MM')
      ...
      

      ... 包含在 APC 链接到的文档中。

      【讨论】:

        【解决方案3】:

        您可以添加一个或多个常用表表达式来封装这些:

        with
          cte_sell_dates as (
            select date '2012-07-01' from_date,
                   date '2012-09-30' to_date
            from dual),
          cte_products as (
            select 1 id from dual union all
            select 28 id from dual),
          ... as (
            select ...
            from   ...
            where  sell_date between (select from_date from cte_sell_dates) and
                                     (select to_date   from cte_sell_dates) and
                   product_id in     (select id        from cte_products  )
          ...
        

        ...当然也可以直接使用连接,而不是子查询。

        【讨论】:

          【解决方案4】:

          使用匿名 PL/sql 块并使用 for 循环,您可以在其中循环所有不同的值。

          以下是 pl/sql 块的结构:

          DECLARE
           <constant name> CONSTANT <data type> := <value>;
           <constant name> CONSTANT <data type> DEFAULT <value>;
          BEGIN
            <valid statement>;
          EXCEPTION
            <exception handler>;
          END;
          

          您还可以选择一个参数化光标,您可以在其中传递您的值。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-07-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-04-28
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多