在Oracle脚本中使用变量

时间:2011-02-18 13:09:46

标签: sql sql-server oracle plsql ansi-sql

有一个复杂的查询可以生成报告。该查询具有多个子查询,可为不同的产品生成3列表。每个子查询返回一行。然后所有返回的行需要联合起来。 但有一个要求。如果子查询没有结果行,我们需要将相应的产品包含在最终报告中,但指定Trades_Count等于零。

我可以使用一组变量来实现这一点。以下代码将在MS SQL Server中完美运行:

DECLARE @PRODUCT_NAME_1 nvarchar(100);
DECLARE @OFFER_VALID_DATE_1 datetime;
DECLARE @TRADES_COUNT_1 int;

DECLARE @PRODUCT_NAME_2 nvarchar(100);
DECLARE @OFFER_VALID_DATE_2 datetime;
DECLARE @TRADES_COUNT_2 int;

--Product 1 
select @PRODUCT_NAME_1 = PRODUCT_NAME, @OFFER_VALID_DATE_1 = MAX(EXPIRY_DATE), @TRADES_COUNT_1 = COUNT(DEAL_NUMBER)
from (
        --Data extractions with several joins goes here....

) as TempTable1
GROUP BY PRODUCT_NAME


--Product 2
select @PRODUCT_NAME_2 = PRODUCT_NAME, @OFFER_VALID_DATE_2 = MAX(EXPIRY_DATE), @TRADES_COUNT_2 = COUNT(DEAL_NUMBER)
from (
        --Data extractions with several joins goes here....
) as TempTable2
GROUP BY PRODUCT_NAME


SELECT ISNULL(@PRODUCT_NAME_1,'Product 1') AS PRODUCT_NAME, @OFFER_VALID_DATE_1 AS MAX_MATURITY, ISNULL(@TRADES_COUNT_1,0)
UNION
(
SELECT ISNULL(@PRODUCT_NAME_2,'Product 2') AS PRODUCT_NAME, @OFFER_VALID_DATE_2 AS MAX_MATURITY, ISNULL(@TRADES_COUNT_2,0)
)

我认为我没有使用任何特定于T-SQL的东西,但是纯ANSI-SQL(我不是100%肯定)。

所以这在Oracle中无效

首先,它只需要一个DECLARE关键字。然后它强迫我使用Begin ... End执行范围。然后它不允许我像我一样分配变量(参见上面的例子) - 我需要使用“Select INTO”语句。完成所有计算后,它不允许我从局部变量中选择值。赫克。

有谁知道如何让它在Oracle中运行?

谢谢!

2 个答案:

答案 0 :(得分:7)

PL / SQL与t-sql不同,我为你做了一些改动,但肯定会看看Andy的链接。这是在oracle的免费SQL Developer(也有一个“Translation Scratch Handler(工具> Migration> Translation Scratch Handler))中运行的,可能有用。

--this creates a refcursor to allow us to simply print the results
var refc refcursor
/

declare --here we declare our variables
    product_name_1 varchar2(15) ;
    offer_valid_date_1 date ;
    trade_count_1 number ;
    product_name_2 varchar2(15) ;
    offer_valid_date_2 date ;
    trade_count_2 number ;    
begin
    begin --this creates a block so we may handle any exceptions just to this
          select PRODUCT_NAME,    MAX(EXPIRY_DATE),    COUNT(DEAL_NUMBER)
            into product_name_1 , offer_valid_date_1 , trade_count_1
            --in oracle you select INTO, not var=COL
        from (
                --Data extractions with several joins goes here....
                select 
                    123 PRODUCT_NAME,    
                    sysdate EXPIRY_DATE,    
                    5 DEAL_NUMBER
                from dual --this is a 'fake' table to generate some data for testing

        )  TempTable1 --drop the "as"
        GROUP BY PRODUCT_NAME ;
    exception --if not data is found, then this error is thrown
              --if multiple values are thrown an error will also be thrown (not caught here)
    when no_data_found then
        product_name_1 := null ; --note, to do a var = , we use "var := value;"
        offer_valid_date_1 := null;
        trade_count_1 := null;
    end ;
    begin
          select PRODUCT_NAME,    MAX(EXPIRY_DATE),    COUNT(DEAL_NUMBER)
            into product_name_2 , offer_valid_date_2 , trade_count_2
            --in oracle you select INTO, not var=COL
        from (
                --Data extractions with several joins goes here....
                select 555 PRODUCT_NAME,    sysdate EXPIRY_DATE,    6 DEAL_NUMBER
                from dual

        )  TempTable2 -- drop the "as"
        GROUP BY PRODUCT_NAME ;
    exception --if not data is found, then this error is thrown
              --if multiple values are thrown an error will also be thrown (not caught here)
    when no_data_found then
        product_name_2 := null ;
        offer_valid_date_2 := null;
        trade_count_2 := null;
    end ;

    open :refc for  --you cannot just have a select statement, you must "open" a cursor for it    
    --oracle IsNull is NVL (or NVL2 or you can do a case or decode...)
    SELECT nvl(PRODUCT_NAME_1,'Product 1') AS PRODUCT_NAME
          , OFFER_VALID_DATE_1 AS MAX_MATURITY
          , nvl(TRADE_COUNT_1,0)
      FROM DUAL --you also must have a table, DUAL is an oracle table for this tasks
        UNION
   SELECT nvl(PRODUCT_NAME_2,'Product 2') AS PRODUCT_NAME
          , OFFER_VALID_DATE_2 AS MAX_MATURITY
          , nvl(TRADE_COUNT_2,0)
    FROM DUAL;

end ;
/

--now print the results, if you did this in a proc you would simple have this as an output
print refc;

-------------
PRODUCT_NAME MAX_MATURITY              NVL(:B1,0)             
-------------------------------------- ---------------------- 
123          18.FEB.2011 08:43         1                      
555          18.FEB.2011 08:43         1                      

此处使用的Oracle概念: Dual TableNVLVariablespl/sql Exception

并查看此http://www.dba-oracle.com/t_convent_sql_server_tsql_oracle_plsql.htm

答案 1 :(得分:1)

PL / SQL格式化程序块与T-SQL不同。

您需要使用以下结构:

DECLARE
    astring varchar2(1000);
    anumber number;

BEGIN
   my SQL code here...
END;

您不在PL / SQL中使用@。只需直接使用变量名称。