SQLServer: хранимая процедура без добавления каких-либо данных без ошибок - PullRequest
0 голосов
/ 26 июня 2019

У меня есть две таблицы мастер и детали. Я передаю XML для сохранения процедуры в качестве значения параметра, но когда мой код процедуры хранения выполняется, то никакие данные не вставляются и не выдает ошибку. я не могу понять, в чем проблема.

любой может помочь мне получить неправильную область в коде процедуры моего магазина, которая вызывает проблему.

Table code
-------------

CREATE TABLE TblTickerTemplate (
    ID int identity,
    Ticker varchar(20),
    LineItem varchar(100),
    Insertdate datetime DEFAULT GETDATE()

    CONSTRAINT PK_ID PRIMARY KEY CLUSTERED (ID)
);

ALTER Table TblTickerTemplate
Add CONSTRAINT UC_Ticker_LineItem UNIQUE (Ticker, LineItem)

CREATE TABLE TblTickerTemplateDetail (
    MasterTemplateID int,
    ID int identity,
    LineItem varchar(100),
    XFundCode varchar(100),
    Action Char(1),
    UserID varchar(20),
    Insertdate datetime DEFAULT GETDATE()
    FOREIGN KEY(MasterTemplateID) REFERENCES TblTickerTemplate(ID)
);

Procedure code
-------------
ALTER Procedure USP_InsertUniqueLineItems
(
    @INPUTXML xml,
    @STATUS VARCHAR(MAX) OUTPUT  
)

AS 

BEGIN
    SET NOCOUNT ON

    BEGIN TRANSACTION   
    BEGIN TRY  
        Declare @TblTickerTemplateDetailID  AS INT 

        Declare @XMLFormat                  AS INT

        Declare @Ticker                     AS VARCHAR(MAX)
        Declare @ID                         AS INT
        Declare @Lineitem                   AS VARCHAR(MAX)
        Declare @XFundCode                  AS VARCHAR(MAX)
        Declare @UserID                     AS VARCHAR(MAX)

        --load xml data into cursor
        Exec sp_xml_preparedocument @XMLFormat OUTPUT, @INPUTXML

        DECLARE CURRECORD
        CURSOR LOCAL FOR
        SELECT Ticker,ID,Lineitem,XFundCode,@UserID
        FROM OPENXML (@XMLFORMAT, '/Lineitems', 1)
        WITH (
            Ticker                  VARCHAR(MAX),
            ID                      INT,
            Lineitem                VARCHAR(MAX),
            XFundCode               VARCHAR(MAX),
            UserID                  VARCHAR(MAX)
         )


        SET @TblTickerTemplateDetailID = 0

        -- open cursor
        OPEN CURRECORD
        FETCH NEXT FROM CURRECORD INTO @Ticker,@ID,@Lineitem,@XFundCode,@UserID

        -- iterate in cursor to fetch value
        WHILE (@@FETCH_STATUS=0)
        BEGIN

            -- if ID == 0 then new data it will be inserted in TblTickerTemplate & TblTickerTemplateDetail table
            IF @ID = 0
            BEGIN
                IF NOT EXISTS(SELECT LineItem  FROM TblTickerTemplate WHERE LineItem = @Lineitem AND Ticker = @Ticker)
                BEGIN
                    INSERT INTO TblTickerTemplate(Ticker,LineItem)
                        VALUES (@Ticker,@Lineitem)

                    SET @TblTickerTemplateDetailID = SCOPE_IDENTITY()

                    INSERT INTO TblTickerTemplateDetail (MasterTemplateID,LineItem,XFundCode,UserID,[Action])
                        VALUES (@TblTickerTemplateDetailID,@Lineitem,@XFundCode,@UserID,'I')                    
                END
            END
            ELSE
            BEGIN
                    -- if ID > 0 means existing data & the data will be inserted in TblTickerTemplateDetail table only

                    INSERT INTO TblTickerTemplateDetail (MasterTemplateID,LineItem,XFundCode,UserID,[Action])
                        VALUES (@ID,@Lineitem,@XFundCode,@UserID,'U')
            END

        FETCH NEXT FROM CURRECORD INTO @Ticker,@ID,@Lineitem,@XFundCode,@UserID
        END

        IF @ID = 0
        BEGIN                       
            SET @STATUS='New Line items successfully inserted' 
        END
        ELSE IF @ID > 0
        BEGIN     
            SET @STATUS='Existing Line items successfully updated' 
        END

        CLOSE CURRECORD
        DEALLOCATE CURRECORD    
        COMMIT TRANSACTION



    END TRY  

    BEGIN CATCH  

        DECLARE @ERROR INT, @MESSAGE VARCHAR(4000)
        SELECT @ERROR = ERROR_NUMBER(),@MESSAGE = ERROR_MESSAGE()   

        --SET @STATUS='Line items insert fail' 
        ROLLBACK TRANSACTION 

        RAISERROR ('USP_InsertUniqueLineItems:', 16, 1, @ERROR, @MESSAGE) 
        --SET @STATUS='Fail-- '+@MESSAGE
        --RETURN

    END CATCH;

    SET NOCOUNT OFF
END

Calling procedure this way
--------------------------

Declare @inputxml xml  
Declare @Status VARCHAR(MAX)

 set @inputxml='<Lineitems>
  <Lineitem>
    <Ticker>TER</Ticker>
    <ID>0</ID>
    <LineItem>Net Revenue</LineItem>
    <XFundCode>TRIN</XFundCode>
    <UserID>TDP</UserID>
  </Lineitem>
  <Lineitem>
    <Ticker>TER</Ticker>
    <ID>0</ID>
    <LineItem>Cost of Revenue</LineItem>
    <XFundCode>XXP</XFundCode>
    <UserID>TDP</UserID>    
  </Lineitem>
</Lineitems>'

 EXEC [dbo].USP_InsertUniqueLineItems @inputxml, @Status output

 Select @Status

Редактировать

Я решил таким образом

/*
SAMPLE XML to insert
<Lineitems>
  <Lineitem>
    <Ticker>TER</Ticker>
    <ID>0</ID>
    <LineItem>Net Revenue</LineItem>
    <XFundCode>TRIN</XFundCode>
    <UserID>TDP</UserID>
  </Lineitem>
  <Lineitem>
    <Ticker>TER</Ticker>
    <ID>0</ID>
    <LineItem>Cost of Revenue</LineItem>
    <XFundCode>XXP</XFundCode>
    <UserID>TDP</UserID>    
  </Lineitem>
</Lineitems>
*/

ALTER Procedure USP_InsertUniqueLineItems
(
    @INPUTXML xml,
    @STATUS VARCHAR(MAX) OUTPUT  
)

AS 

BEGIN
    SET NOCOUNT ON

    BEGIN TRANSACTION   
    BEGIN TRY  
        Declare @TblTickerTemplateDetailID  AS INT 

        Declare @XMLFormat                  AS INT

        Declare @Ticker                     AS VARCHAR(MAX)
        Declare @ID                         AS INT
        Declare @Lineitem                   AS VARCHAR(MAX)
        Declare @XFundCode                  AS VARCHAR(MAX)
        Declare @UserID                     AS VARCHAR(MAX)

        --load xml data into cursor
        Exec sp_xml_preparedocument @XMLFormat OUTPUT, @INPUTXML

        DECLARE CURRECORD
        CURSOR LOCAL FOR
        SELECT ID,Ticker,LineItem,XFundCode,UserID
        FROM OPENXML (@XMLFORMAT, '/Lineitems/Lineitem', 2)
        WITH (
            ID                      INT,
            Ticker                  VARCHAR(MAX),
            LineItem                VARCHAR(MAX),
            XFundCode               VARCHAR(MAX),
            UserID                  VARCHAR(MAX)
         )


        SET @TblTickerTemplateDetailID = 0

        -- open cursor
        OPEN CURRECORD
        FETCH NEXT FROM CURRECORD INTO @ID,@Ticker,@Lineitem,@XFundCode,@UserID

        -- iterate in cursor to fetch value
        WHILE (@@FETCH_STATUS=0)
        BEGIN

            -- if ID == 0 then new data it will be inserted in TblTickerTemplate & TblTickerTemplateDetail table
            IF @ID = 0
            BEGIN
                IF NOT EXISTS(SELECT *  FROM TblTickerTemplate WHERE LineItem = @Lineitem AND Ticker = @Ticker)
                BEGIN
                    Print @Ticker+' '+@Lineitem

                    INSERT INTO TblTickerTemplate(Ticker,LineItem)
                        VALUES (@Ticker,@Lineitem)

                    SET @TblTickerTemplateDetailID = SCOPE_IDENTITY()
                    SET @STATUS='New Line items successfully inserted' 

                    INSERT INTO TblTickerTemplateDetail (MasterTemplateID,LineItem,XFundCode,UserID,[Action])
                        VALUES (@TblTickerTemplateDetailID,@Lineitem,@XFundCode,@UserID,'I')                    
                END
            END
            ELSE
            BEGIN
                    -- if ID > 0 means existing data & the data will be inserted in TblTickerTemplateDetail table only

                    INSERT INTO TblTickerTemplateDetail (MasterTemplateID,LineItem,XFundCode,UserID,[Action])
                        VALUES (@ID,@Lineitem,@XFundCode,@UserID,'U')
            END

        FETCH NEXT FROM CURRECORD INTO @ID,@Ticker,@Lineitem,@XFundCode,@UserID
        END

        -- storing message to OUTPUT type variable
        IF @ID = 0
        BEGIN                       
            SET @STATUS='New Line items successfully inserted' 
        END
        ELSE IF @ID > 0
        BEGIN     
            SET @STATUS='Existing Line items successfully updated' 
        END

        CLOSE CURRECORD
        DEALLOCATE CURRECORD    
        COMMIT TRANSACTION

    END TRY  

    BEGIN CATCH  

        -- Error handling part
        DECLARE @ERROR INT, @MESSAGE VARCHAR(4000)
        SELECT @ERROR = ERROR_NUMBER(),@MESSAGE = ERROR_MESSAGE()   

        SET @STATUS='Fail-- '+@MESSAGE      
        ROLLBACK TRANSACTION 

        --RAISERROR ('USP_InsertUniqueLineItems:', 16, 1, @ERROR, @MESSAGE) 
        RETURN

    END CATCH;

    SET NOCOUNT OFF
END

но если я раскомментирую эту строку RAISERROR ('USP_InsertUniqueLineItems:', 16, 1, @ERROR, @MESSAGE), то придет ошибка. как это исправить ... поделись идеей. спасибо

Ответы [ 3 ]

1 голос
/ 26 июня 2019

Привет попробуйте этот код при вставке.

Declare @inputxml xml  


 set @inputxml='<Lineitems>
  <Lineitem>
    <Ticker>TER</Ticker>
    <ID>1</ID>
    <LineItem>Net Revenue</LineItem>
    <XFundCode>TRIN</XFundCode>
    <UserID>TDP</UserID>
  </Lineitem>
  <Lineitem>
    <Ticker>TER</Ticker>
    <ID>2</ID>
    <LineItem>Cost of Revenue</LineItem>
    <XFundCode>XXP</XFundCode>
    <UserID>TDP</UserID>    
  </Lineitem>
</Lineitems>'


        SELECT

      T.C.value('(ID)[1]', 'int')

      ,T.C.value('(Ticker)[1]', 'varchar(max)')

      ,T.C.value('(LineItem)[1]', 'varchar(max)')

      ,T.C.value('(XFundCode)[1]', 'varchar(max)')
      ,T.C.value('(UserID)[1]', 'varchar(max)')


   FROM @inputxml.nodes('Lineitems/Lineitem') T(C)

Пожалуйста, измените тип данных переменной в соответствии с вашим требованием в операторе выбора, иначе это будет вашей ошибкой.

1 голос
/ 26 июня 2019

Ваш код имеет множество проблем, больше, чем я хочу сосчитать. Похоже, что он был портирован из базы данных SQL Server 2000 с некоторыми минимальными добавлениями, такими как try / catch block и max типы данных.

По сути, все ваши TRY могут быть заменены этими двумя утверждениями:

insert into dbo.TblTickerTemplate (LineItem, Ticker)
select t.c.value('(./LineItem/text())[1]', 'varchar(100)'),
  t.c.value('(./Ticker/text())[1]', 'varchar(100)')
from @inputxml.nodes('./Lineitems[1]/Lineitem[(./ID/text())[1] = "0"]') t(c);

insert into dbo.TblTickerTemplateDetail ([Action], LineItem, MasterTemplateID, UserID, XFundCode)
select case t.c.value('(./ID/text())[1]', 'int') when 0 then 'I' else 'U' end as [Action],
  t.c.value('(./LineItem/text())[1]', 'varchar(100)') as [LineItem],
  m.ID as [MasterTemplateId],
  t.c.value('(./UserID/text())[1]', 'varchar(20)') as [UserId],
  t.c.value('(./XFundCode/text())[1]', 'varchar(100)') as [XFundCode]
from dbo.TblTickerTemplate m
  inner join @inputxml.nodes('./Lineitems[1]/Lineitem') t(c) on
    m.LineItem = t.c.value('(./LineItem/text())[1]', 'varchar(100)')
    and m.Ticker = t.c.value('(./Ticker/text())[1]', 'varchar(100)');

Это не особенно оптимально - для XML приличного размера (более 100 узлов) обычно лучше сначала кэшировать данные в реляционной форме, либо в переменную @table (да, они уже существовали в 2000 году), либо в таблице #tevent. Кроме того, при первой вставке вы захотите добавить проверку существования, чтобы вновь вставленные строки не нарушали ваш естественный ключ. Но в качестве скелета этого будет достаточно, да.

Еще одна вещь, которую я заметил, это то, что атрибут ./UserID фактически никогда не используется - ваш код помещает переменную @UserID в объявление курсора, а затем назначается переменная (которая на данном этапе NULL) к себе в fetch next. Несомненно, опечатка или копия-паста.

0 голосов
/ 26 июня 2019

Процедура сохранения без добавления данных без ошибок

Это потому, что OPENXML просто возвращает NULL.

SELECT Ticker,ID,Lineitem,XFundCode,@UserID
FROM OPENXML (@XMLFORMAT, '/Lineitems', 1)
        WITH (
            Ticker                  VARCHAR(MAX),
            ID                      INT,
            Lineitem                VARCHAR(MAX),
            XFundCode               VARCHAR(MAX),
            UserID                  VARCHAR(MAX)
         );

должно быть:

SELECT Ticker,ID,Lineitem,XFundCode,@UserID
    FROM OPENXML (@XMLFORMAT, '/Lineitems/Lineitem', 2)
    WITH (
        Ticker                  VARCHAR(MAX),
        ID                      INT,
        Lineitem                VARCHAR(MAX),
        XFundCode               VARCHAR(MAX),
        UserID                  VARCHAR(MAX)
     )

Обратите внимание, что изменилось с 1 (ориентированный на атрибут) на 2 (ориентированный на элемент) режим OPENXML и изменилось с '/Lineitems' на '/Lineitems/Lineitem'.

Также: Exec sp_xml_preparedocument должен иметь соответствующий EXEC sp_xml_removedocument.

Подводя итог: я согласен с комментарием, что вам следует избегать sp_xml_preparedocument/OPENXML/CURSOR и полностью переписать его, используя синтаксис .value/nodes.

db <> fiddle demo

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...