【问题标题】:Not sure of the correct syntax for a stored procedure不确定存储过程的正确语法
【发布时间】:2019-05-29 11:20:41
【问题描述】:

我正在处理我刚刚在此站点上获得的一些其他代码,这是我第一次使用存储过程,所以我真的不确定语法应该如何工作。我在 Teradata SQL 助手工作。目标基本上是用这些变量创建一个宏。

CREATE PROCEDURE member_count(
        IN state CHAR(2),
        IN state_mbr CHAR(9))

--We have to tell it here that we will be returning a result set
DYNAMIC RESULT SETS 1
BEGIN

--Declare variables we will be using at the top
--One variable for the sql string
DECLARE my_sql VARCHAR(5000);

--And another for the cursor that we will open for the result set
DECLARE my_cursor CURSOR WITH RETURN ONLY FOR my_statement;

--Now we build our dynamically generated sql statement
--we use two single quotes together to escape the quote character
--(essentially we want a single quote in the SQL statement so we must
--double it as it's already inside single quotes).
SET my_sql = 'Select
    ''' || state || ''' as state
,case when m.var1 not in ('PREM','MPP') then 'SF'
        when m.var1 in ('JG',) then 'FI'
        when m.var1 in ('STU') and (m.var2 is not null or m.var2 not in ('xxx')) then 'HIM'
              else 'Other' end as lob
    ,count(m.dw_mbr_key) as members
FROM database. || state_mbr
group by 1,2
order by 1,2;'

---Now we "prepare" the "statement" from our string
PREPARE my_statement FROM my_sql;

---and we open the cursor. We don't close it because we want it returned.
OPEN my_cursor;
END;

CALL member_count(NM, NM_MBR);

我的问题是如何处理单引号?比如case when语句,是不是一个问题,需要做一些不同的事情?

这很难,因为我没有得到任何结果或错误消息。只有“导入查询中找到的样式参数”的内容。

【问题讨论】:

  • 转义单引号看起来很讨厌。通常你只需将它们放 4 次并摆弄。我首选的方法是与返回单引号字符的函数连接。例如,在 Oracle 中,您可以使用 CHR(10)。在 Teradata 中,我认为您可以使用十六进制值“27”XC。不过,目前我的机器上没有 Teradata 实例,因此无法对其进行测试。但只要看看 SELECT '27'XC || 的输出'测试' || '27XC'
  • 我把它完全一样,它返回'test27XC
  • 我稍微摆弄了一下引号,这应该给出格式良好的 SQL '''Select ''' ||状态 || ''' 作为状态,当 m.var1 不在 (''PREM''' || ',''MPP''' || ' 然后 ''SF''' || ' 当 m.var1 在 (' 'JG''' || ',) THEN ''FI''' || ' 当 m.var1 在 (''STU''' || ') 和 (m.var2 不为空或 m.var2 不在(''xxx''' || ')) then ''HIM''' || ' else ''Other''' || ' end as lob ,count(m.dw_mbr_key) as members FROM database. || state_mbr按 1,2 分组,按 1,2 排序;'
  • 糟糕。如果您想使用十六进制功能路线,请实际使用它-- SELECT '27'XC || '测试' || '27'XC 。只是为了调试,我会创建一个 volatile 表,如 CREATE VOLATILE TABLE DEBUG_VT ( sqlStatement VARCHAR(2000)) ON COMMIT PRESERVE ROWS;然后在你的过程中有 INSERT INTO DEBUG_VT VALUES (my_sql);这样您就可以单独运行您的动态语句,以确保它确实在执行您想要的操作。

标签: sql stored-procedures teradata teradata-sql-assistant


【解决方案1】:

正如@Error_2646 已经写过在动态 SQL 中摆弄带引号的字符串是 难的。您应该从不带参数的工作查询开始

SELECT
   'NM' AS state
   ,CASE WHEN m.var1 NOT IN ('PREM','MPP') THEN 'SF'
         WHEN m.var1 IN ('JG') THEN 'FI'
         WHEN m.var1 IN ('STU') AND (m.var2 IS NOT NULL OR m.var2 NOT IN ('xxx')) THEN 'HIM'
         ELSE 'Other'
    END AS lob
   ,Count(m.dw_mbr_key) AS members
FROM db.NM_MBR AS m
GROUP BY 1,2
ORDER BY 1,2;

然后你搜索并用''替换所有'

SELECT
   ''NM'' AS state
   ,CASE WHEN m.var1 NOT IN (''PREM'',''MPP'') THEN ''SF''
         WHEN m.var1 IN (''JG'') THEN ''FI''
         WHEN m.var1 IN (''STU'') AND (m.var2 IS NOT NULL OR m.var2 NOT IN (''xxx'')) THEN ''HIM''
         ELSE ''Other''
    END AS lob
   ,Count(m.dw_mbr_key) AS members
FROM db.NM_MBR AS m
GROUP BY 1,2
ORDER BY 1,2;

单引号整个查询

'SELECT
   ''NM'' AS state
   ,CASE WHEN m.var1 NOT IN (''PREM'',''MPP'') THEN ''SF''
         WHEN m.var1 IN (''JG'') THEN ''FI''
         WHEN m.var1 IN (''STU'') AND (m.var2 IS NOT NULL OR m.var2 NOT IN (''xxx'')) THEN ''HIM''
         ELSE ''Other''
    END AS lob
   ,Count(m.dw_mbr_key) AS members
FROM db.NM_MBR AS m
GROUP BY 1,2
ORDER BY 1,2;'

最后你用' || myparam || '替换参数,这里是''NM'' & NM_MBR

'SELECT
   ' || NM || ' AS state
   ,CASE WHEN m.var1 NOT IN (''PREM'',''MPP'') THEN ''SF''
         WHEN m.var1 IN (''JG'') THEN ''FI''
         WHEN m.var1 IN (''STU'') AND (m.var2 IS NOT NULL OR m.var2 NOT IN (''xxx'')) THEN ''HIM''
         ELSE ''Other''
    END AS lob
   ,Count(m.dw_mbr_key) AS members
FROM db.' || NM_MBR || ' AS m
GROUP BY 1,2
ORDER BY 1,2;'

现在你得到了一个有效的 SQL 字符串,可以在动态 SQL 中使用。

由于仍然存在很多潜在的问题/错误,我通常会定义一些错误处理和返回有关成功执行或失败信息的输出消息:

REPLACE PROCEDURE member_count(
        IN state CHAR(2),
        IN state_mbr CHAR(9),
        OUT msg VARCHAR(1000))

--We have to tell it here that we will be returning a result set
DYNAMIC RESULT SETS 1
BEGIN   
   -- constants
   DECLARE CRLF CHAR(2) DEFAULT '0D0A'xc; -- to simplify adding linebreaks
   -- I usually got multiple constants, e.g. for debugging.

   --Declare variables we will be using at the top
   --One variable for the sql string
   DECLARE my_sql VARCHAR(5000);

   --And another for the cursor that we will open for the result set
   DECLARE my_cursor CURSOR WITH RETURN ONLY FOR my_statement;

   --Now we build our dynamically generated sql statement
   --we use two single quotes together to escape the quote character
   --(essentially we want a single quote in the SQL statement so we must
   --double it as it's already inside single quotes).
   SET my_sql =
'SELECT
   ' || state|| ' AS state
   ,CASE WHEN m.var1 NOT IN (''PREM'',''MPP'') THEN ''SF''
         WHEN m.var1 IN (''JG'') THEN ''FI''
         WHEN m.var1 IN (''STU'') AND (m.var2 IS NOT NULL OR m.var2 NOT IN (''xxx'')) THEN ''HIM''
         ELSE ''Other''
    END AS lob
   ,Count(m.dw_mbr_key) AS members
FROM db.' || state_mbr || ' AS m
GROUP BY 1,2
ORDER BY 1,2;'
   ;

   ---Now we "prepare" the "statement" from our string
   BEGIN
      -- adding a handler to catch error information
      DECLARE EXIT HANDLER FOR SqlException
      BEGIN -- there was an error during PREPARE or OPEN
         DECLARE errortext VARCHAR(1000);
         DECLARE Errorcode CHAR(5);
         GET DIAGNOSTICS EXCEPTION 1
             errortext = Message_Text,
             Errorcode = Returned_SqlState;

         SET msg = 'Failed: ' || Errorcode || ': ' || errortext
                   || CRLF || 'SQL Statement: ' 
                   || CRLF || my_sql;
      END;

      PREPARE my_statement FROM my_sql;

      ---and we open the cursor. We don't close it because we want it returned.
      OPEN my_cursor;

      -- only execute if there was no error
      SET msg = 'Finished: ' || Trim(Activity_Count) || ' rows returned';
   END;

END;

现在 SP 已编译,但您的原始 CALL 将失败并显示 [3810] Column/Parameter 'member_count.NM' does not exist.。您必须将参数作为字符串传递:

CALL member_count('NM', 'NM_MBR', msg);

运行并返回这个msg

Failed: 52004: Database 'db' does not exist.
SQL Statement: 
SELECT
   NM AS state
   ,CASE WHEN m.var1 NOT IN ('PREM','MPP') THEN 'SF'
         WHEN m.var1 IN ('JG') THEN 'FI'
         WHEN m.var1 IN ('STU') AND (m.var2 IS NOT NULL OR m.var2 NOT IN ('xxx')) THEN 'HIM'
         ELSE 'Other'
    END AS lob
   ,Count(m.dw_mbr_key) AS members
FROM db.NM_MBR    AS m
GROUP BY 1,2
ORDER BY 1,2;

注意,CALL 没有失败,它运行成功,但是处理程序捕获了错误并且没有返回结果集。

如果 Select 运行成功,则返回两个结果集,第一个是消息 ''Finished: xxx rows returned',第二个是实际结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-23
    • 2011-06-12
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    • 2020-07-05
    • 1970-01-01
    相关资源
    最近更新 更多