1

我目前正在编写一个 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 的解决方案,并且我可以在其中指定类型变量。

4

4 回答 4

3

这取决于您如何运行查询。

如果您使用 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 文档包含更多信息:了解更多信息。

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

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
      ),
于 2013-06-29T09:34:13.390 回答
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 链接到的文档中有所介绍。

于 2013-06-29T10:08:11.033 回答
2

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

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  )
  ...

...或者直接使用连接,而不是子查询,当然。

于 2013-06-29T12:59:43.417 回答
0

使用匿名 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;

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

于 2013-06-29T03:32:52.770 回答