【问题标题】:Oracle function exchange for SQL Server用于 SQL Server 的 Oracle 函数交换
【发布时间】:2020-05-10 10:24:37
【问题描述】:

我做了一个Oracle to SQL Server的项目,现在我有一个无法重建的功能,不知道是什么问题,

该函数用于获取Oracle sequene,结果错误。

Oracle函数代码

  CREATE FUNCTION [test].[GETWORKORDERID] (numberPre varchar2)
  return varchar2 is
  PRAGMA AUTONOMOUS_TRANSACTION;
  findId     number(8); --maxid
  nowNumber  varchar2(50);
  n_count    number(8);
  n_count2   number(8);
  nowNumber2 varchar2(50);
begin

  nowNumber := to_char(sysdate, 'yyyymmdd');

  nowNumber2 := to_char(sysdate - 1, 'yyyymmdd');

  select count(1)
    into n_count2
    from user_sequences t
   where t.sequence_name = 'SEQ_' || numberPre || '_' || nowNumber2;

  if n_count2 > 0 then
    execute immediate 'drop sequence SEQ_' || numberPre || '_' ||
                      nowNumber2;
  end if;

  select count(1)
    into n_count
    from user_sequences t
   where t.sequence_name = 'SEQ_' || numberPre || '_' || nowNumber;

  if n_count = 0 then
    execute immediate 'create sequence SEQ_' || numberPre || '_' ||
                      nowNumber ||
                      ' minvalue 10000 maxvalue 99999999 start with 10000 increment by 1 NOCYCLE NOCACHE';
  end if;

  execute immediate 'select SEQ_' || numberPre || '_' || nowNumber ||
                    '.nextval from dual'
    into findId;

  commit;
  return numberPre || nowNumber || findId;
end;**

我把SQL Server改成:

CREATE FUNCTION [test-CSR].[GETWORKORDERID] 
     (@numberPre nvarchar(max))
RETURNS TABLE
AS
BEGIN
    DECLARE @findId    bigint;
    DECLARE @nowNumber bigint;
    DECLARE @n_count  bigint;
    DECLARE @n_count2  bigint;
    DECLARE @nowNumber2 bigint;
    DECLARE @sql1 nvarchar(max);
    DECLARE @sql2 nvarchar(max);
    DECLARE @sql3 nvarchar(max);
    DECLARE @sql4 nvarchar(max);
    DECLARE @result nvarchar(max);

    SET @nowNumber = CONVERT(varchar(30), GETDATE(), 20)
    SET @nowNumber2 = CONVERT(varchar(30), GETDATE(), 20)

    SELECT COUNT(1)
    INTO n_count2
    FROM user_sequences t
    WHERE t.sequence_name = 'SEQ_' + numberPre + '_' + nowNumber2;

    IF n_count2 > 0 
    BEGIN
        SET @sql1 = 'drop sequence SEQ_' + numberPre + '_' + nowNumber2;
        EXECUTE (@sql1) 
    END;

    SELECT COUNT(1)
    INTO n_count
    FROM user_sequences t
    WHERE t.sequence_name = 'SEQ_' + @numberPre + '_' + @nowNumber;

    IF n_count = 0 
    BEGIN
        SET @sql2 = 'create sequence SEQ_ ' + @numberPre + '_' + @nowNumber +
                          ' minvalue 10000 maxvalue 99999999 start with 10000 increment by 1 NOCYCLE NOCACHE';
        EXECUTE (@sql2)
    END;

    SET @sql3 = 'select SEQ_ ' + @numberPre + '_' + @nowNumber + '.NEXT VALUE FOR user_sequences';
    SET @findId = @sql3;
    SET @sql4 = @numberPre + @nowNumber + @findId;

    INSERT INTO @result 
        EXEC (@sql4)
END;

现在我在SQL Server中重建函数,但是SQL Server运行的时候结果是错误的,不知道是什么错误?

【问题讨论】:

  • 具体说明“运行错误”的含义。你有错误吗?如果是这样,消息是什么?事情是否没有像您期望的那样工作?如果是这样,你期望什么?我们没有你的数据库,其他人调试你的代码比你做的工作要多得多。
  • 您的新函数甚至可以在 SQL Server 上编译吗?用户定义的函数一般不允许有 DDL 或execute 语句。

标签: sql-server oracle function


【解决方案1】:
  1. 在函数中不能使用EXECUTE。您尝试创建序列。 SQL Server 中的函数是纯函数。他们不能更改数据库中的对象和数据。我可以建议您使用PROCEDURE 而不是FUNCTION

  2. 如果你声明一个FUNCTION,它应该这样定义:

CREATE FUNCTION [test-CSR].[GETWORKORDERID] 
     (@numberPre nvarchar(max))
RETURNS @result TABLE (...)
AS
BEGIN
...
    RETURN;
END
  1. 您应该像这样将计数保存到变量中:
SELECT @n_count2 = COUNT(1)
FROM user_sequences t
WHERE t.sequence_name = 'SEQ_' + numberPre + '_' + nowNumber2;

然后写:

IF @n_count2 > 0 ...
  1. 最后,您应该删除 INSERT INTO @result。应该只提供 EXEC (@sql4)

希望对你有帮助。

【讨论】:

    【解决方案2】:

    如果可能的话,您必须将其更改为过程。在 SQL Server 中运行副作用函数有一些不太好的方法,但应该避免它们。查看SQL Server Migration Assistant for Oracle 的自动翻译了解详细信息。

    在移植代码时,通常您应该迁移到“SQL Server 方式”。

    无论如何,这是该过程的惯用 SQL Server 翻译。但是整个丢弃序列的过程很奇怪。

    --create schema [test-CSR]
    go
    CREATE or alter procedure [test-CSR].[GETWORKORDERID] @numberPre nvarchar(max), @result nvarchar(max) out
    AS
    /*
    declare @result nvarchar(max)
    exec [test-CSR].[GETWORKORDERID] N'foo', @result out
    print @result
    */
    BEGIN
        DECLARE @findId    bigint;
        DECLARE @nowNumber bigint = CONVERT(varchar(30), GETDATE(), 112);
        DECLARE @nowNumber2 bigint = CONVERT(varchar(30), GETDATE()-1, 112);
        DECLARE @sql nvarchar(max);
    
    
        declare @seq sysname = concat('SEQ_',  @numberPre, '_', @nowNumber);
        declare @seq2 sysname = concat('SEQ_',  @numberPre, '_', @nowNumber2);
    
        IF exists (select * from sys.sequences where name = @seq2)
        BEGIN
            SET @sql = concat('drop sequence ', quotename(@seq2));
            --print @sql;
            EXECUTE (@sql);
        END;
    
    
        IF not exists (select * from sys.sequences where name = @seq)
        BEGIN
            SET @sql = concat('create sequence ', quotename(@seq), 
                               ' start with 10000 increment by 1 minvalue 10000 maxvalue 99999999 NO CYCLE NO CACHE');
            --print @sql;
            EXECUTE (@sql)
        END;
    
        SET @sql = concat('select @findId = NEXT VALUE FOR ', quotename(@seq)) ;
        --print @sql;
        exec sp_executesql @sql, N'@findId bigint out', @findId = @findId out;
    
        set @result = concat(@numberPre, @nowNumber, @findId);
    
    END;
    

    如果您可以进行更改,我可能会有一个序列对象,并将其下一个值传递给这样的函数:

    create sequence WORKORDERID_seq start with 10000 increment by 1 minvalue 10000 maxvalue 99999999 NO CYCLE NO CACHE
    
    go
    create function [test-CSR].[GETWORKORDERID2] (@nowNumber nvarchar(max), @nv int)
    returns nvarchar(max)
    as
    begin
      return concat(CONVERT(varchar(30), GETDATE(), 112),@nowNumber,@nv)
    end
    

    并运行批处理作业以每晚重置序列值。

    【讨论】:

      猜你喜欢
      • 2021-06-14
      • 2023-02-23
      • 2021-11-18
      • 2011-01-07
      • 1970-01-01
      • 2020-03-22
      • 1970-01-01
      • 2021-01-21
      • 1970-01-01
      相关资源
      最近更新 更多