MSSQL - Zapisywanie błędów zwracanych przez procedurę do Tabeli

0

Mam pewien problem - nie wiem czy wstawiam swój wątek w odpowiednią kategorię, czy nie powinien być w Newbie.
Napisałem dwa skrypty - jeden tworzy tabele (tu chyba nie ma problemu) drugi z definicją procedury SQL, której głównym założeniem jest zapisywanie błędów (w moim przypadku powstających przez niezgodność danych typu VARCHAR z INT w tabeli.
Czy możecie coś zasugerować lub podpowiedzieć czy był już taki problem? W załączeniu obydwa skrypty.
Skrypt tablic Tabele.sql
(Tablica1 i Tablica2 - tablice z zapisywanymi danymi, TablicaBlad - tablica do gromadzenia danych o błędach)

use master
use Przechwyt
CREATE TABLE [Tabela1]
(  [a][int] NOT NULL  )
CREATE TABLE [Tabela2]
(  [b][int] NOT NULL  )
CREATE TABLE [TabelaBlad]
(   [ErrorMessage][NVARCHAR] NOT NULL  )

Procedura do zapisywania danych i rejestrowania błędów

USE [Przechwyt]
GO
IF EXISTS (SELECT NAME
            FROM SYSOBJECTS
            WHERE NAME = N'spPrzechwytywanieDodaj'
            AND TYPE = 'P')
DROP PROCEDURE spPrzechwytywanieDodaj
GO
CREATE PROCEDURE spPrzechwytywanieDodaj
--ALTER PROCEDURE spPrzechwytywanieDodaj
     --Parametry
     @a VARCHAR(10),
     @b VARCHAR(10)
AS
BEGIN
     begin try
          INSERT INTO Tabela1(a) values (@a)
     end try
     begin catch
         DECLARE @ErrorMessage NVARCHAR(4000);
         DECLARE @ErrorSeverity INT;
         DECLARE @ErrorState INT;    -- Nie jestem pewien czy te trzy linie są potrzebne
         SELECT
          ERROR_NUMBER() AS ErrorNUMBER,
          ERROR_SEVERITY() AS ErrorSeverity, -- poziom wywołanego błędu
          ERROR_STATE() AS ErrorState, -- numer stanu błędu
          ERROR_PROCEDURE() AS ErrorProcedure,
          ERROR_LINE() AS ErrorLine,
          ERROR_MESSAGE() AS ErrorMESSAGE
          Insert into TabelaBlad(ErrorMessage) values(@ErrorMessage) --czy to jest dobrze
          print ERROR_MESSAGE()    -- i to też
     end catch

/* PRÓBOWAŁEM TEŻ TAKICH WARUNKÓW
IF @@ERROR = 245
 BEGIN
 PRINT N'An error occurred deleting the candidate information.';
     RETURN 245;
 END
 ELSE
 INSERT INTO Tabela1 values(0)
     RETURN 0;
 END     
 */

     begin try    
         INSERT INTO Tabela2(b) values(@b)    
     end try
     begin catch
         SELECT ERROR_MESSAGE() AS ErrorMESSAGE,
         ERROR_NUMBER() AS ErrorNUMBER,
         ERROR_PROCEDURE() AS ErrorProcedure,
          --ERROR_SEVERITY() AS ErrorSeverity,
          --ERROR_STATE() AS ErrorState,
          ERROR_LINE() AS ErrorLine  
     end catch
 END
 GO
0
 
USE [Przechwyt]
GO

CREATE PROCEDURE dbo.spPrzechwytywanieDodaj
	@a VARCHAR(10),
	@b VARCHAR(10)
AS
BEGIN
	begin try
		INSERT INTO Tabela1(a) values (@a)
	end try
	begin catch
		Insert into TabelaBlad(ErrorMessage) values(ERROR_MESSAGE()) 
		print ERROR_MESSAGE()    -- to wypisze treść błędu w MSSMS
	end catch

	RETURN
END
0

Bez deklaracji

 DECLARE @ErrorMessage NVARCHAR(4000) 

procedura się nie wykonuje
Po wykonaniu :

EXEC spPrzechwytywanieDodaj	
	@a = 'a',
	@b = 'b'

Z deklaracją mam błąd :

 (0 row(s) affected)
Msg 515, Level 16, State 2, Procedure spPrzechwytywanieDodaj, Line 26
Cannot insert the value NULL into column 'ErrorMessage', table 'Przechwyt.dbo.TabelaBlad'; column does not allow nulls. INSERT fails.
The statement has been terminated.
Conversion failed when converting the varchar value 'a' to data type int.
(0 row(s) affected)
(1 row(s) affected)
0

A u mnie działa :)

Definicja tabelki

 
USE [JakasBaza]
GO

CREATE TABLE [dbo].[b](
	[id] [int] NULL,
	[napis] [varchar](100) NULL
)

Alter procedury

 
alter PROCEDURE dbo.spPrzechwytywanieDodaj
    @a VARCHAR(10),
    @b int
AS
BEGIN
    BEGIN try
        INSERT INTO dbo.b(id) VALUES (@a)
    END try
    BEGIN catch
        INSERT INTO dbo.b(napis) VALUES(ERROR_MESSAGE()) 
        print ERROR_MESSAGE()    -- to wypisze treść błędu w MSSMS
    END catch
 
    RETURN
END

I wywołanie

 
USE [JakasBaza]
GO

EXECUTE [dbo].[spPrzechwytywanieDodaj] 
   @a = 'a'
  ,@b = 1
GO
0

@_pytek próbuje jeszcze na rożne sposoby żeby wpisywała się wartość "a" i/lub "b" do pierwszej kolumny czyli id. Dodałem również po kolumnie 'id' nowa kolumnę 'a', zmieniłem na NOT NULL i sypie błędami.

0

Czy aby na pewno tam się nic nie wykonuje?

roboskobo napisał(a):

Conversion failed when converting the varchar value 'a' to data type int.
(0 row(s) affected) <- to z bloku try
(1 row(s) affected) <- to z bloku catch

0

Tak zgadza się ale chciałem aby w przypadku gdy nie wystąpi błąd, wartość "a" wpisała się do kolumny o tej samej nazwie, natomiast gdy będzie błąd wpisze się do tej samej tabeli tylko z pominięciem kolumny 'a'.
Obrazuje to mniej więcej zrzut z załącznika.
Kod jest taki - Tabele :

USE [Przechwyt]
GO
CREATE TABLE [dbo].[Tabela11]
(    [id] [INT] NULL
    ,[a] [INT] NULL
    ,[ErrorMessage] [VARCHAR](100) NULL
    ,[ErrorNumber] [VARCHAR](100) NULL
    ,[ErrorProcedure] [VARCHAR](100) NULL
    ,[ErrorSeverity] [VARCHAR](100) NULL
    ,[ErrorState] [VARCHAR](100) NULL
    ,[ErrorLine] [VARCHAR](100) NULL
)
CREATE TABLE [dbo].[Tabela22]
(    [b] [INT] NOT NULL
)
CREATE TABLE [dbo].[TabelaBlad]
(    [id] [INT] NULL
    ,[ErrorMessage] [VARCHAR](100) NULL
    ,[ErrorNumber] [VARCHAR](100) NULL
    ,[ErrorProcedure] [VARCHAR](100) NULL
    ,[ErrorSeverity] [VARCHAR](100) NULL
    ,[ErrorState] [VARCHAR](100) NULL
    ,[ErrorLine] [VARCHAR](100) NULL
) 

Procedura :

CREATE PROCEDURE dbo.spPrzechwytywanieDodaj1122
    @a VARCHAR(10),
    @b VARCHAR(10)
AS
BEGIN
    BEGIN try
        INSERT INTO dbo.Tabela11(a) VALUES (@a)
    END try
    BEGIN catch
        BEGIN
        INSERT INTO dbo.Tabela11(a, ErrorMessage, ErrorNumber, ErrorProcedure, ErrorSeverity, ErrorState, ErrorLine) VALUES(@a, ERROR_MESSAGE(), ERROR_NUMBER(), ERROR_PROCEDURE(), ERROR_SEVERITY(), ERROR_STATE(), ERROR_LINE()) 
        INSERT INTO dbo.Tabela11(id) VALUES (@a)
        END
    END catch
    
    BEGIN try
        INSERT INTO dbo.Tabela22(b) VALUES (@b)
    END try
    BEGIN catch
        BEGIN
        INSERT INTO dbo.TabelaBlad(ErrorMessage, ErrorNumber, ErrorProcedure, ErrorSeverity, ErrorState, ErrorLine) VALUES(ERROR_MESSAGE(), ERROR_NUMBER(), ERROR_PROCEDURE(), ERROR_SEVERITY(), ERROR_STATE(), ERROR_LINE()) 
        INSERT INTO dbo.Tabela22(b) VALUES (@b)
        END
    END catch
    RETURN
END
GO

EXECUTE [dbo].[spPrzechwytywanieDodaj1122]
	@a = 1,
	@b = 2
EXECUTE [dbo].[spPrzechwytywanieDodaj1122] 
	@a = 11,
	@b = 'b'	
EXECUTE [dbo].[spPrzechwytywanieDodaj1122] 
	@a = 'a',
	@b = 4
1

Myślenie naprawdę nie boli :)

 
CREATE PROCEDURE dbo.spPrzechwytywanieDodaj1122
    @a VARCHAR(10),
    @b VARCHAR(10)
AS
BEGIN
    BEGIN try
        INSERT INTO dbo.Tabela11(a) VALUES (@a)
    END try
    BEGIN catch
        BEGIN
        INSERT INTO dbo.Tabela11(a, ErrorMessage, ErrorNumber, ErrorProcedure, ErrorSeverity, ErrorState, ErrorLine) VALUES(@a, ERROR_MESSAGE(), ERROR_NUMBER(), ERROR_PROCEDURE(), ERROR_SEVERITY(), ERROR_STATE(), ERROR_LINE()) 
        INSERT INTO dbo.Tabela11(id) VALUES (@a)
        END
    END catch
[ciach]

W tabelce pole 'a' masz zdefiniowane jako INT, w procedurze parametr @a to VARCHAR(10) czyli insert w bloku try skończy się błędem konwersji.
A co robisz w bloku catch? Dokładnie to samo, próbujesz wepchnąć varchara do pól typu int.
Najsampierw dopasuj typy parametrów to typów pól. Jeżeli chcesz przechowywać wartość która powoduje błąd to dodaj sobie do tabelki z błędami pole typy varchar(max) i tam ją przechowuj.
Moja propozycja:

 
alter table dbo.Tabela11 add BadValue varchar(max)


CREATE PROCEDURE dbo.spPrzechwytywanieDodaj1122
    @a int,
    @b VARCHAR(10)
AS
BEGIN
    BEGIN try
        INSERT INTO dbo.Tabela11(a) VALUES (@a)
    END try
    BEGIN catch
        BEGIN
			INSERT INTO dbo.Tabela11(BadValue, ErrorMessage, ErrorNumber, ErrorProcedure, ErrorSeverity, ErrorState, ErrorLine) VALUES(cast(@a as varchar(max)), ERROR_MESSAGE(), ERROR_NUMBER(), ERROR_PROCEDURE(), ERROR_SEVERITY(), ERROR_STATE(), ERROR_LINE()) 
        END
    END catch
[ciach]

1 użytkowników online, w tym zalogowanych: 0, gości: 1