How to continue sql script on error? - sql

We have a couple of migration scripts, which alter the schema from version to version.
Sometimes it happens, that a migration step (e.g. adding a column to a table) was already done manually or by a patch installation, and thus the migration script fails.
How do I prevent the script from stopping on error (ideally at specific expected errors) and instead log a message and continue with the script?
We use PostgresQL 9.1, both a solution for PostgresQL as well as a general SQL solution would be fine.

Although #LucM's answer seems to be good recommendation - #TomasGreif pointed me to an answer that went more in the direction of my origin request.
For the given example of adding a column, this can be done by using the DO statement for catching the exception:
DO $$
BEGIN
BEGIN
ALTER TABLE mytable ADD COLUMN counter integer default 0;
EXCEPTION
WHEN duplicate_column THEN RAISE NOTICE 'counter column already exists';
END;
END;
$$;
The hint led me to the right PostgresQL site, describing the error codes one could trap - so that was the right solution for me.

I don't think that you have another solution than running the entire script outside of a transaction.
What I would do if I was in that situation:
Do the modifications to the metadata (drop/create table/column...) outside of a
transaction.
Do all modifications to the data (update/insert/delete)
inside a transaction.

Related

PL/SQL Developer Can't See Results Of Insert Statement

As the title says - when I perform an "INSERT" statement, I can't see the results unless I re-open PL/SQL Developer.
To make things a bit more clear:
After I perform this statement on the empty table "worker_temp" -
insert into worker_temp
select * from worker_b
I see that 100 records have been inserted:
But when I try to see the results using this query:
select * from worker_temp;
I still see an empty table:
But only after I quit PL/SQL Developer and re-open it, I can see the records that I inserted earlier:
Is there a way to see the changes without closing and re-opening PL/SQL Developer?
What I've tried so far:
I've tried to refresh the table using right click on it:
And I've also tried to refresh the whole tables folder:
I also tried committing -
commit;
But I'm not sure what that even is.
Tool agnostic way:
begin
insert into worker_temp
select * from worker_b;
commit;
end;
Judging by all the screenshots you are likely getting separate database sessions in 'each' tab you are using - which is a good thing. You have to issue the commit on the same session that performed the insert. Another way of understanding this:
begin
insert into worker_temp select * from worker_b;
DBMS_OUTPUT.PUT_LINE('Rows inserted but not committed ' || SQL%ROWCOUNT);
-- 'undo' the insert by rolling back the insert instead of commit.
rollback;
end;
The default setting in PL/SQL Developer is Multi session:
This means that each editor window you have open is logged into the database in a separate session. A session can't see another session's changes until it commits. This is rather like saving a shared Excel spreadsheet on a network drive. Nobody can see your changes until you have finished making them, which you'll appreciate is an important feature in a multi-user database.
In PL/SQL Developer, the Multi session default setting means that you can start a long-running query in one SQL window, and then get on with something else in another without being blocked and having to wait for it. With this setting, you'll need to commit your changes before any other editor window can see them. There are Commit and Rollback icons in the toolbar, or you can type commit; and execute it.
However, I always set mine to Dual session, meaning all windows are part of the same session, even if it means I sometimes have to wait for something. I find this simplifies things considerably, and also I can make changes across multiple windows without needing to commit, which can be helpful when working with global temporary tables or alter session commands.
Read more in this setup guide.

Unable to use transactions on db2 with ibm400

I'm trying to combine dynamic update and select on db2.
Everything works fine until I'm applying transactioning (i.e. commit,rollback or savepoint)
For instance, executing very basic command
SAVEPOINT SAVEPOINT1 ON ROLLBACK RETAIN CURSORS
gives COMMIT, ROLLBACK, or SAVEPOINT not valid.
Same effect for simple commit and others.
Can anybody explain why I'm unable to execute this commands and how to fix it?
Google shows only ibm docs with examples that are not applicable.
You Library (schema) where you have your tables must be journalised. Look this link for create your journalisation

Table is automatically truncated on SQL Server

I have a really strange problem on my SQL Server.
Every night 2 tables, that I have recently created, are being automatically truncated...
I am quite sure, that it is truncate, as my ON DELETE Trigger does not log any delete transactions.
Additionally, using some logging procedures, I found out, that this happens between 01:50 and 01:52 at night. So I checked the scheduled Jobs on the server and did not find anything.
I have this problem only on our production server. That is why it is very critical. On the cloned test server everything works fine.
I have checked transaction log entries (fn_dblog), but didnt find any truncate logs there.
I would appreciate any help or hints that will help me to find out process/job/user who truncates the table.
Thanks
From personal experience of this, as a first step I would look to determine whether this is occurring due to a DROP statement or a TRUNCATE statement.
To provide a possible answer, using SSMS, right click the DB name in Object Explorer, mouse over Reports >> Standard Reports and click Schema Changes History.
This will open up a simple report with the object name and type columns. Find the name of the table(s), click the + sign to expand, and it will provide you history of what has happened at the object level for that table.
If you find the DROP statement in there, then at least you know what you are hunting for, likewise if there is no DROP statement, you are likely looking for a TRUNCATE.
Check with below query,
declare #var as varchar(max)='tblname'
EXEC sp_depends #objname =#var;
it will return number of stored procedure name which are using your table and try search for any truncate query if you have wrote by mistake.
Thanks a lot to everyone who has helped!
I've found out the reason of truncating. It was an external application.
So if you experience the same problem, my hint is to check your applications that could access the data.
I don't know if can help you to resolve the question.
I often encounter the following situations.
Look at this example:
declare #t varchar(5)
set #t='123456'
select #t as output
output:12345

SQL Server: verbose error messages?

Is there some configuration option for MS SQL Server which enables more verbose error messages.
Specific example: I would like to see the actual field values of the inserted record which violates a constraint during an insert, to help track down a bug in stored procedures which I haven't been able to reproduce.
I don't believe there is any such option. There are trace flags that give more information about deadlocks, but I've never heard of one that gives more information on a constraint violation.
If you control the application that is causing the crash then extending it's handling (as Jenn suggested) to include parameter values etc. Once you have the parameter values you can get a copy of live setup on a non-live server and start debugging the issue.
For more options, can any of the users affected reliably reproduce the issue? If they can then you might be able to run a profiler trace to capture the actual statements / parameter values being sent to the database. Of course, if you can figure out the steps to reproduce the issue then you can probably use more traditional debugging methods...
You don't say what the constraint is, I'm assuming it is a fairly complex constraint. If so, could it be broken down into several constraints so you can get more of a hint about the problem with the data?
You could also re-write the constraint as a trigger which could then include more information in the error that it raises. Although this would obviously need testing before being deployed to a production server!
Personally, I would go with changing the error handling of the application. It is probably the less risky change.
PS The application that I helped write, and now spend my time supporting, logs quite a lot of data when an unhandled exception occurs. If it is during a save then our data access layer attaches the complete list of all commands that were being run as part of the save transaction including parameter values. This has proved to be invaluable on many occasions, including some when tracking down constraint violations.
In a stored proc, what I do to get better informatino in a complex SP about the errors is take advantage of the fact that table variables are not affected by a rollback. So I put the information I want to use to troubleshoot into table variables at the time I create it and then if I hit the catch block and rollback, after the rollback I insert the data from the table variable into an exception table along with some meta data like the datetime.
With some thought you can design an exception table that will capture what you need from just about any proc (for instance you could concatenate all the input variables into one field, you could put in the step number that failed (of course then you have to assign stepnumbers to a variable) or you could log every step along the awy and then the last one logged is the one it failed on. Belive me when you are looking at troubleshooting a 100 line SP, this can come in handy. If I have dymanic SQl inteh proc, I can log the SQL variable that contains the dynamic code that was run.
The beauty of this is now you don't have to try to reproduce the error, you know what the input parameters were and any other information you find useful. Yes it can take a bit of time to set up once, but once you do it is relatively easy to get in the habit of putting it into any complex proc that you will want to log errors on.
You might also want to set a an nongeneralized one if you want to return spefic data values of a select used for an insert or the result set of a select that would tell you waht what wopuld have been being updated or deleted. Then you would have that only if the proc failed. This is a little more work than the general exception table but may be needed in some complex cases.

How to detect that trigger fails after calling a stored procedure from .Net application?

We have a .NET application (VB / VS2010) and are calling many stored procedures on a SQL Server 2008 for database queries. We also have quite a few update/insert/delete triggers that are executed automatically once these stored procedures modify the database tables.
There are quite often situations when a stored procedure is called and it seems to perform ok as no error is raised and the .NET app continues as usual. However if I then look under the covers and perform the stored procedure call manually via SQL Server Client I see that a trigger that's executed right after the stored procedure fails, thus rolling back all changes.
So my question is: what's the best way to detect and pass through errors in our .NET --> stored procedure --> trigger scenario to know for sure in the .NET app that everything succeeded or not in case of an error?
Many thanks in advance,
Steve
Update: I am at home now and away from my desk (and the code base) for the weekend, so won't have a chance to check the very details of the stored procedures. Thanks so much for the answers given so far. I can have a look at the code again next week.
But in the meantime...
One question was about the version of MS SQL Server: it's 2008.
From what I know out of the top of my head we are calling the stored procedures (at least those that don't read data and "just" update, delete or insert data) in this manner:
Using connection As New SqlConnection("connectionString")
Dim command As New SqlCommand("EXEC STORED_PROCEDUR_ENAME), connection)
command.Connection.Open()
command.ExecuteNonQuery()
End Using
I think the assumption behind the code above is the expectation that if something fails within the stored procedure or a related trigger, that
command.ExecuteNonQuery()
would then fail. That might be my first problem, i.e. will I have to alter this code?
One question below was if I use ExecuteDataReader, so the answer is no, at least not so far...
I'll comment on the SQL specific questions and suggestions below.
I actually had the same issue today,
to solve it i used an output #msg and placed it after each function in the sproc.
SET #msg = 'Test print 1'
each section i added one so i know what ever the last number printed was where the sproc failed. I then went to the table where the trigger was failing and adjusted it until it printed the last number and passed.
You should check ##error after each statement, and return the error if one exists.
Here's a good article for you. Check out the section "Why is My Error Not Raised". It describes a scenario that could be your problem.
http://www.sommarskog.se/error-handling-II.html
You might also want to try turning XACT_ABORT on, so stored procedures would fail for most errors.
EDIT: Here's another link that might help explain this.
http://www.novicksoftware.com/tipsandtricks/tips-erorr-handling-in-a-stored-procedure.htm
You can either return an error from your procedure if you check ##error and find it != 0, or you can use RAISERROR, which will definitely result in an exception in calling code.
http://msdn.microsoft.com/en-us/library/ms178592.aspx
as you mention that you are using sql server 2008. this gives capacity to use try.. catch. here is the article.
http://msdn.microsoft.com/en-us/library/ms175976.aspx
Also look at this forum.
http://social.msdn.microsoft.com/Forums/eu/transactsql/thread/03eae70e-d478-44a7-90f3-8e1d27d9f22e
i think try..catch will do the job. also in .net side i would use following code.
try
{
// your stored procedure execution code.
}
Catch (sqlexception e)
{
// do something with sql exception.
}
try this scenario see if that solves your issue.