This post is a continuation of our SQL Server project that uses exception handling in our code to import a text file that is not a delimited file.
In our example project, below is what our input file looks like. ABC Inc. sends us files periodically that have this format. Each time we get this file we need to run a stored procedure, called [AllProcedures] that will import this file into a table in SQL Server called [dbo].[Reports]. We expect the file to be in the same format each time we receive one. We also expect that the four-digit code number is different each time. For this example, we also expect that the file has exactly nine rows. In the real world that number would likely be higher, allowing for more transaction lines. In the real world there would also likely be more information in the file such as the date and more information for each transaction. However, for now, we want to focus on the process and not make things too detailed so as to cloud the important parts of the exercise. In the real world we would use more descriptive names for our tables and stored procedures that we are using here.
Full Listing
This post includes a full SQL Server query listing that will create a new database, tables and stored procedures that allow you to test out this code for yourself. Feel free to make changes to the code and use it freely in your own projects. Part 9 also has a full listing like this one, but that is based on a previous version of the program, I encourage you to use this updated version.
Below is a screen shot of the above file’s data after it has been imported into the table dbo.Reports using the sql listing provided below.
Here is a screenshot from SQL Server Management Studio (SSMS).
It shows the database and the table objects and the stored procedures that the below sql script will create for you. As a use of the program you will need to first create the input file in the directory C:\incoming\rpt2.txt. You could change the folder name or place the folder deeper in the hierarchy, but you will need to change the code as well.
Copy this code listing into a new query in SSMS. Execute the query with the Execute button. Don’t worry about the dependency message you get. It will still work. Next, Right click the stored procedure called AllProcedures and select Execute Stored Procedure… and then click the OK button. Now right-click the table dbo.Reports and click Select Top 1000 Rows. You should see the critical contents of your input text file listed in the Results pane of SSMS.
Below is the complete sql listing. It creates a new database, creates the necessary tables and the stored procedures as well. If you wish, feel free to copy this entire listing into a new query in SSMS. Execute the query. Run the stored procedure AllProcedures. You should have imported the file you created in the instructions above.
To copy the listing below, click on the icon with the two blue brackets in the upper right corner of the box that contains the listing. In Windows, click Ctrl+A then Ctrl+C to copy the text. Paste that into a new query window in SSMS and then execute the query. Have a look at the Results pane. Right-click the table dbo.Reports and view the rows in the table with Select Top 1000 Rows, or just write your own select query.
Try to import the same file again and see what message you get. You should get an error that says you would have duplicates.
Try changing the one aspect of the contents of the file and run it again. Try changing the code number. Try changing the code number and the amounts. Notice how delicate the program is.
-- An error occurred; must determine which type of rollback will
642
-- roll back only the work done in the procedure.
643
IF @TranCountAtStart = 0
644
BEGIN
645
-- Transaction started in procedure. Roll back complete transaction.
646
ROLLBACK TRANSACTION;
647
PRINT 'InSProc [AllProcedures], *** Rolling Back Transaction***';
648
END
649
ELSE
650
-- Transaction started before procedure called, do not roll back modifications
651
-- made before the procedure was called.
652
IF XACT_STATE() <> -1
653
BEGIN
654
-- If the transaction is still valid, just roll back to the savepoint set at the
655
-- start of the stored procedure.
656
ROLLBACK TRANSACTION ProcedureSave;
657
-- If the transaction is uncommitable, a rollback to the save point is not allowed
658
-- because the save point rollback writes to the log. Just return to the caller, which
659
-- should roll back the outer transaction.
660
PRINT 'InSProc [AllProcedures], *** Rolling Back Procedure***';
661
END
662
663
-- After the appropriate rollback, echo error information to the caller.
664
DECLARE@ErrorMessage NVARCHAR(4000);
665
DECLARE@ErrorSeverity INT;
666
DECLARE@ErrorState INT;
667
668
SELECT@ErrorMessage = ERROR_MESSAGE();
669
SELECT@ErrorSeverity = ERROR_SEVERITY();
670
SELECT@ErrorState = ERROR_STATE();
671
672
RAISERROR (@ErrorMessage, -- Message text.
673
@ErrorSeverity, -- Severity.
674
@ErrorState -- State.
675
);
676
ENDCATCH
677
GO
678
679
CREATEPROCEDURE[dbo].[xDropandCreateAllTables]
680
-- Use this one for debugging purposes.
681
AS
682
BEGIN
683
-- SET NOCOUNT ON added to prevent extra result sets from
684
-- interfering with SELECT statements.
685
SETNOCOUNT ON;
686
687
DROPTABLE[dbo].[InReport]
688
CREATETABLE[dbo].[InReport](
689
[InRows] [varchar](400) NULL
690
) ON[PRIMARY]
691
692
693
DROPTABLE[dbo].[InReportHistory]
694
CREATETABLE[dbo].[InReportHistory](
695
[Id] [int] IDENTITY(1,1) NOTNULL,
696
[SystemDateTime] [datetime] NOTNULL,
697
[InRows] [varchar](400) NOTNULL
698
) ON[PRIMARY]
699
700
DROPTABLE[dbo].[Reports]
701
CREATETABLE[dbo].[Reports](
702
[FullFileName] [varchar](50) NULL,
703
[SourceCompany] [varchar](50) NULL,
704
[CodeNumber] [varchar](4) NULL,
705
[TransNumber] [varchar](5) NULL,
706
[TransAmount] [varchar](8) NULL
707
) ON[PRIMARY]
708
END
709
GO
Current Procedure
One improvement to the error trapping code is to use a variable to get the current running stored procedure. The current procedure is stored in @@PROCID. We could use this instead of “hard-coding” the stored procedure name inside of the error message. In this way if we ever need to change the name of the procedure we don’t need to change the error messages. That makes it much easier to maintain the code.
Global Variables
In SQL Server, global variables start with @@. The website Code Project has a very good article on these global variables. Global variables represent a special type of variable. The server always maintain the values of these variables. All the global variables represent information specific to the server or a current user session. You do not need to declare them, since the server constantly maintains them. They are system-defined functions and you cannot declare them.