Any ideas on how to accomplish this?
USE [db_name]
BEGIN TRANSACTION
...TONS OF INSERTS
COMMIT;
RAISERROR (..) WITH NOWAIT; //If error continue with next batch
BEGIN TRANSACTION
...TONS OF INSERTS
COMMIT;
RAISERROR (..) WITH NOWAIT;
...
Use the -V flag on the command-line. If you set a sufficiently large enough value (e.g 17), even fairly severe errors will not stop the script.
e.g. sqlcmd ... -V 17 -i MyFile.sql
I will assume that you know what you're doing when you do this and are monitoring the error messages nonetheless.
You could go higher, up to level 25, but if you're getting errors between level 17 and 25, it's unlikely that you're going to be able to progress much because they tend to be caused by software or hardware errors on the server, rather than errors in the scripts you're inputting.
The behavior of batch interruption on error is a SQL Server (ie. backend) option and is governed by error severity. There is no way to change the server behavior, errors that interrupt the batch will always interrupt the batch, period.
The behavior of file continuation (run the next GO delimited batch after error) is a sqlcmd option and is controlled by the -b switch. By default is ON (meaning sqlcmd continues with the next batch).
Related
Today in SSMS I misplaced my pointer and clicked the Execute button instead of the Database drop-down (they're adjacent on the screen). Fortunately no damage done, but it scared me that I might have executed everything in the current query window since nothing was highlighted. I'd like to put a simple command at the top of any new query window which will stop an F5 type of execution in its tracks. This seemed to work:
UPDATE atable SET intfield = 'freakout prevention' WHERE tablekey = 123
UPDATE atable SET intfield = 55 WHERE tablekey = 123
where intfield is a column defined as an int. Running both lines resulted in
Conversion failed when converting the varchar value 'freakout prevention' to data type int.
Furthermore, the value of intfield was NOT set to 55.
So is this a fairly reliable (I don't need 100.00% here -- just enough to catch the rare time when I accidentally execute a "bare" F5) method of "prefixing" a query window to prevent wild execution when nothing is highlighted and the execute command is given?
If you don't have batches (e.g., GO), then you can put a RETURN as the first line.
If you need to prevent all batches from running, you can put a delay at the beginning of the script. Or you can add a bit of messaging....
I edited this answer to add some extra code to check for an open transaction. This has nothing to do with the original question, but I have found this to be a bigger issue with some developers.
RAISERROR('You ran me by accident. I will be wait for an hour for you to kill me.', 10, 1) WITH NOWAIT
WHILE (1=1) BEGIN
WAITFOR DELAY '1:00:00'
RAISERROR('I''m still waiting. Please kill me. Here goes another hour...', 10, 1) WITH NOWAIT
END
GO
RAISERROR('OMG! Get the backups ready for a restore in production! Also, update the resume.', 16, 1) WITH NOWAIT
GO
BEGIN TRAN
GO
-- [Updated] Extra check - open transaction
WHILE ( ##TRANCOUNT > 0 ) BEGIN
RAISERROR('Execution is almost complete; however, a transaction is open. Please COMMIT or ROLLBACK after you kill me. Waiting 1 minute...', 10, 1) WITH NOWAIT
WAITFOR DELAY '0:01:00'
END
RAISERROR('Execution is complete.', 10, 1) WITH NOWAIT
Per the comment, one option is to add set noexec on to the top of the query window. This setting persists across batches. It is evaluated at execution time and can therefore be run conditionally (unlike many other set statements).
As noted by Randy in Marin, this is still not completely safe because the script could contain a set noexec off. If you set noexec on SQL will still execute the set noexec off (obviously, otherwise there wouldn't be a way to turn it off!), and then any subsequent statements would be executed.
Another option - and possibly an even better one - would be set parseonly on.
One difference between the two is that with set parseonly on The engine will literally do only that - parse the syntax. It won't actually do any "work". With set noexec on any statements will still produce plans, but the plans won't be executed. So set parseonly on is "cheaper" than set noexec on.
The other difference is that set parseonly on cannot be executed conditionally. That is to say, a line of code like if (1 = 0) set parseonly on will result in parseonly being set to "on", because the if is evaluated at execution time, but for obvious reasons parseonly is not evaluated at execution time, because that would defeat the point!
And another difference: while parseonly will persist across batches, only one parseonly within each individual batch counts, and it's the last one. For example:
set parseonly on;
select 'hello';
set parseonly off;
go
This will return the result set "hello", because there is a parseonly off in the batch, and it is the last parseonly setting in the batch.
And of course, even with parseonly a similar danger applies: If the script has a set parseonly off, then some statements can still get executed. Not just the statements following, but even other statements that precede it in the same batch, if it is the last setting for parseonly in that batch.
Is there anything else you can do? Yes. Enter sqlcmd. The :on error exit sqlcmd directive will tell sqlcmd to stop executing anything if any kind of error occurs - batch terminating or otherwise.
What we do in our deployment scripts is this:
:on error exit
set xact_abort on;
begin tran;
-- migration script content here
commit;
You can do something similar here to avoid execution of anything in the script in a way that has no danger of being turned off, you can put the query window into sqlcmd mode, and put this at the top:
:on error exit
throw;
-- rest of script here
Now, the throw here won't actually throw an error, since we're not in a catch block. In fact, it is an error to have this throw here. But... that's all we need. The error will cause the :on error exit to terminate all further execution of the file. You could also just have a raiserror (...) instead, but that means more typing :P
Is this now a guaranteed solution? No, because what if you forget to put your window into sqlcmd mode? You can set windows to open in sqlcmd mode by default... but what if you turn it off? The first batch will fail (syntax error since the sqlcmd syntax won't be valid), but subsequent batches will execute.
You can of course combine both methods...
:on error exit
throw;
go
set noexec on;
-- ... rest of script with many batches
But as already described, its still possible for statements to be executed if you are not in sqlcmd mode and there are set noexec off statements anywhere in the script.
I want to enable TIMING on oracle TimesTen. Its working if i execute TIMING 1 from ttsql command prompt but when I tried the command EXECUTE IMMEDIATE 'TIMING 1' from a function, i got the error ORA-06512 Syntax error in SQL statement before or at: "TIMING", character position: 1. Any pointers on this?
setting the Timing ON worked . SET TIMING ON;
My current scenario is like this:
I need to login to sqlplus from a shell script to call a stored procedure.
After that I need to create a CSV file by SPOOLING data from a table.
Then I need to check whether the CSV file has been created in a particular directory and depending on the result an update query needs to be run.
I know that this can be checked within sqlplus with the help of UTL_FILE package but unfortunately due to Client policies,the access of this package is restricted in the current system.
Another way is to exit from sqlplus and perform the file check in UNIX and then again log in to sqlplus to perform the rest actions. But this I believe would result in slower execution time and performance is an important factor in this implementation as the tables contain huge volumes of data(in millions).
So is there any other way to check this from sqlplus without exiting from the current session?
System Info:
OS - Red Hat Enterprise Linux
Database - Oracle 11g
If the file is on the same machine that you're running SQL*Plus on, you could potentially use the host command.
If the file you're checking is the same one you're spooling to, it must exist anyway, or you would have got an SP error of some kind; but if you do want to check the same file for some reason, and assuming you have a substitution variable with the file name:
define csv_file=/path/to/spool.csv
-- call procedure
spool &csv_file
-- do query
spool off
host ls &csv_file
update your_table
set foo=bar
where &_rc = 0;
If the file exists when the host command is run, the _rc substitution variable will be set to zero. If the file doesn't exist or isn't readable for any reason it will be something else - e.g. 2 if the file just doesn't exist. Adding the check &_rc = 0 to your update will mean no rows are updated if there was an error. (You can of course still have whatever other conditions you need for the update).
You could suppress the display of the file name by adding 1>/dev/null to the host command string; and could also suppress any error messages by also adding 2>/dev/null, though you might want to see those.
The documentation warns against using &_rc as it isn't portable; but it works on RHEL so as long as you don't need your script to be portable to other operating systems this may be good enough for you. What you can't do, though, is do anything with the contents of the file, or interpret anything about it. All you have available is the return code from the command you run. If you need anything more sophisticated you could call a script that generates specific return codes, but that's getting a bit messy.
If I execute the following script:
EXECUTE LongRunningSP1
GO
EXECUTE LongRunningSP2
GO
Assuming both procedures take several minutes, will the GO batching cause any concurrency to happen or is LongRunningSP1 guaranteed to finish before LongRunningSP2 starts?
The GO will just split your code in batches, but it won't cause any concurrency: all batches are executed one at time, in the order they appear in the code.
LongRunningSP1 is guaranteed to finish before LongRunningSP2 with or without the GO in between; GO is a batch separator for the command processor.
It's easier to see what it does when using the command line utility SQLCMD.
SQLCMD
1> exec LongRunningSP1
-- nothing happens
2> exec LongRunningSP2
-- nothing happens
3> GO
-- both procs are run, first SP1, then SP2
Yes!! Go will actually make it into batches to be executed.
So it's LongRunningSP1 which gets completed first, ALWAYS!
GO is not a Transact-SQL statement; it is a command recognized by the sqlcmd and osql utilities and SQL Server Management Studio Code editor. It is a batch terminator, it will not change the order of your query. You can however change it to whatever you want under options.
Here are a set of very simple, easy steps to customize the batch separator in SSMS:
Launch SSMS
Go to Tools –> Options
Click on the “Query Execution” node
Notice that we have an option to change the Batch Separator
Change the batch separator
Click “OK”
I have a stored procedure in Sybase that uses reorg rebuild statement in a loop for all the tables in my database. What I want to do is to suppress the reorg rebuild sysmessages for tables that succedeed the procedure and only to print the tables that were locked etc...thus the problematic ones....The thing is that I did not succeed to find out anything to use in manual or in any workshops...dow you have any idea?
Thanks in advance !!!!!
If you are running the SQL with isql at a command prompt, you can always capture the output in a text file and filter it out with other tools.
Create a script to run the SQL in isql and then use a script that calls a text processing tool (awk,sed,...) to only find the lines of interest.
Here is an example from a windows batch file with a regex that removes lines that start with a space (i.e. Rows Effected messages)
isql -SDBDEV1 -DMyDbName -U%DBLOG% -P%DBPWD% -iLoadBatchStats.sql -o%TEMP%\LoadBatchStats.log
type %TEMP%\LoadBatchStats.log | gawk "/^[ ]/{print $0}" >>%TEMP%\LoadBatchSummary.log