Initiate Rollback if any SQL command fails - sql

I'm looking at updating an old PowerShell script I ran for inserting Exchange Message Tracking logs into SQL. Due to the way I am pulling the Message Tracking logs into a tab delimited CSV file and then importing them, I have quite a big SQL statement that I'd like to Rollback and throw an exception in case of errors or problems...
I am doing this in the following order:
Truncating a Temp Table I'd created earlier in the script.
Bulk inserting the Logs from the CSV file into the Temp Table.
Inserting the Message Tracking rows into a Message Tracking table
from the Temp Table
Inserting the Recipient info into a Recipients table from the Temp
Table.
Updating my Servers table to reflect the fact that I've successfully
stepped forwards in time and inserted the logs.
Below is my function from PowerShell, should be easy to see what is running even if you don't know PowerShell:
Function Import-TrackingLogs
{
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
$Command.CommandTimeOut = 2000
$Command.CommandText = "
TRUNCATE TABLE $TempTable1;
BULK INSERT $TempTable1
FROM '$ExportTrackingFile'
WITH
(
FIRSTROW = 2,
FIELDTERMINATOR = '\t'
);
INSERT INTO E12_MessageTracking
SELECT
CASE LEN([TimeStamp]) WHEN 2 THEN NULL ELSE REPLACE([TimeStamp], '" + [char]34 + "', '') END AS [TimeStamp],
CASE LEN([Sender]) WHEN 2 THEN NULL ELSE REPLACE([Sender], '" + [char]34 + "', '') END AS [Sender],
CASE LEN([Recipients]) WHEN 2 THEN NULL ELSE REPLACE([Recipients], '" + [char]34 + "', '') END AS [Recipients],
CASE LEN([MessageSubject]) WHEN 2 THEN NULL ELSE REPLACE([MessageSubject], '" + [char]34 + "', '') END AS [MessageSubject],
CASE LEN([EventId]) WHEN 2 THEN NULL ELSE REPLACE([EventId], '" + [char]34 + "', '') END AS [EventId],
CASE LEN([Source]) WHEN 2 THEN NULL ELSE REPLACE([Source], '" + [char]34 + "', '') END AS [Source],
CASE LEN([MessageId]) WHEN 2 THEN NULL ELSE REPLACE([MessageId], '" + [char]34 + "', '') END AS [MessageId],
CASE LEN([InternalMessageId]) WHEN 2 THEN NULL ELSE REPLACE([InternalMessageId], '" + [char]34 + "', '') END AS [InternalMessageId],
CASE LEN([RecordGuid]) WHEN 2 THEN NULL ELSE REPLACE([RecordGuid], '" + [char]34 + "', '') END AS [RecordGuid],
CASE LEN([ClientIp]) WHEN 2 THEN NULL ELSE REPLACE([ClientIp], '" + [char]34 + "', '') END AS [ClientIp],
CASE LEN([ServerHostname]) WHEN 2 THEN NULL ELSE REPLACE([ServerHostname], '" + [char]34 + "', '') END AS [ServerHostname],
CASE LEN([ConnectorId]) WHEN 2 THEN NULL ELSE REPLACE([ConnectorId], '" + [char]34 + "', '') END AS [ConnectorId],
CASE LEN([RecipientStatus]) WHEN 2 THEN NULL ELSE REPLACE([RecipientStatus], '" + [char]34 + "', '') END AS [RecipientStatus],
CASE LEN([RecipientCount]) WHEN 2 THEN NULL ELSE REPLACE([RecipientCount], '" + [char]34 + "', '') END AS [RecipientCount],
CASE LEN([TotalBytes]) WHEN 2 THEN NULL ELSE REPLACE([TotalBytes], '" + [char]34 + "', '') END AS [TotalBytes],
CASE LEN([FromServer]) WHEN 2 THEN NULL ELSE REPLACE([FromServer], '" + [char]34 + "', '') END AS [FromServer]
FROM $TempTable1;
INSERT INTO E12_MessageTracking_Recipients
SELECT
SUBSTRING (s.[TimeStamp], 2, LEN(s.[TimeStamp]) -2) AS [TimeStamp],
CASE LEN(s.[MessageId]) WHEN 2 THEN NULL ELSE (SUBSTRING (s.[MessageId], 2, LEN(s.[MessageId]) -2)) END AS [MessageId],
CASE LEN(s.[InternalMessageId]) WHEN 2 THEN NULL ELSE (SUBSTRING (s.[InternalMessageId], 2, LEN(s.[InternalMessageId]) -2)) END AS [InternalMessageId],
CASE LEN(s.[RecordGuid]) WHEN 2 THEN NULL ELSE (SUBSTRING (s.[RecordGuid], 2, LEN(s.[RecordGuid]) -2)) END AS [RecordGuid],
f.Value AS [Recipient]
FROM #E12_MessageTracking AS s
CROSS APPLY dbo.SplitStrings(SUBSTRING(s.[Recipients], 2, LEN(s.[Recipients]) -2), '|') AS f;
UPDATE E12_MessageTracking_Servers
SET LogUpdatedTime = '$EndTime';"
$Command.ExecuteNonQuery() | Out-Null
}
I could wrap each individual command into a Powershell try/catch block, but figured it might be better to see if SQL can handle this for me.
This was my previous rollback in PowerShell:
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
$Command.CommandTimeOut = 30
$Command.CommandText = "
DELETE FROM E12_MessageTracking WHERE TimeStamp >= '$StartTime';
DELETE FROM E12_MessageTracking_Recipients WHERE TimeStamp >= '$StartTime';
UPDATE E12_MessageTracking_Servers
SET LogUpdatedTime = '$StartTime';"
$Command.ExecuteNonQuery() | Out-Null
I was looking at this page SQL Server - transactions roll back on error?, but unsure how I would wrap that into my commands as I'm not just running one thing, but multiple commands.
Thanks!

Consider using xact_abort:
set xact_abort on
begin transaction
<your big sql statement here>
commit transaction

Related

using Transaction query in jsp page

I use below query in my jsp page. but I'm not sure Is it true to use this query in jsp page.
int i = st.executeUpdate("'BEGIN TRANSACTION DECLARE #id [int] SELECT #id = SCOPE_IDENTITY() INSERT INTO Viewer(Reserve_ID, F_Name, L_Name, Competition_ID, City, Phone, [E-mail]) VALUES (#id, '" + fname + "','" + lname + "','" + 30 + "','" + city + "','" + phone + "','" + email + "' ) INSERT INTO Reservation_Inf(Reservation_Date, Competition_ID, NumberOfTicket, Position_ID) VALUES ('" + dNow + "','" + 30 + "','" + 1 + "','" + 8 + "' ) COMMIT TRANSACTION '" );
if (i > 0) {
response.sendRedirect("Success.jsp");
} else {
response.sendRedirect("Fail.jsp");
}
It gives this error :
Incorrect syntax near 'BEGIN TRANSACTION DECLARE #id [int] SELECT #id = SCOPE_IDENTITY() INSERT INTO Viewer(Reserve_ID, F_Name, L_Name, Competition_ID,'.

Getting Error: Column does not exist

When adding rows to a table I am getting Error: column does not exist and I am not sure why. I know the table does and it is fairly straight forward. Here is what I have to add and here is what the table looks like. Any help would be great and let me know if you have any questions. Thanks!
Whatever value I have in emailField it is giving me the error that emailfield column does not exist
final String addemployee = "insert into employee values ('" + name_field.getText() + "', '" + usersSuper.getText() + "', '" + true + "' , md5('" + passwordField.getText() + "') , " + emailField.getText() + ");";
Here is the table
CREATE TABLE employee
(
name text NOT NULL,
manageremail text,
isadmin boolean NOT NULL,
userpassword text NOT NULL,
email text NOT NULL,
CONSTRAINT "user_Email" PRIMARY KEY (email)
)
Try
final String addemployee = "insert into employee values ('" + name_field.getText() + "', '" + usersSuper.getText() + "', '" + true + "' , md5('" + passwordField.getText() + "') , '" + emailField.getText() + "');";
You've missed quotes around emailField.getText()? it should be '" + emailField.getText() + "'

Can these two SQL statements be made into one? Changing multiple indices with two constraints

I have a form that users can use to edit data in my database. The database is structured like this:
If a user wants to edit both a FAVE_COLOR and a FAVE_FOOD, how would I go about doing that in my SQL statement? I can think of this, but is there a way to do this in one statement?
string sql1 = "UPDATE MYTABLE " +
"SET PROP_VALUE = '" + form["color"] + "' " +
"WHERE ID = " + form["id"] + " " +
"AND PROP_NAME = 'FAVE_COLOR'"
string sql2 = "UPDATE MYTABLE " +
"SET PROP_VALUE = '" + form["food"] + "' " +
"WHERE ID = " + form["id"] + " " +
"AND PROP_NAME = 'FAVE_FOOD'"
string sql = "UPDATE MYTABLE " +
"SET PROP_VALUE = CASE " +
"WHEN PROP_NAME = 'FAVE_COLOR' THEN '" + form["color"] + "' " +
"WHEN PROP_NAME = 'FAVE_FOOD' THEN '" + form["food"] + "' " +
"END " +
"WHERE ID = " + form["id"] + " " +
"AND PROP_NAME IN ('FAVE_COLOR', 'FAVE_FOOD')"
But beware of SQL injection! You really should be using prepared statements, into which you pass your variables as parameters that do not get evaluated for SQL. If you don't know what I'm talking about, or how to fix it, read the story of Bobby Tables.
You can use case statements:
UPDATE MYTABLE
SET PROP_VALUE = (
CASE favefood
WHEN PROP_NAME = 'FAVE_FOOD'
THEN 'PIZZA'
CASE favecolor
WHEN PROP_NAME = 'FAVE_COLOR'
THEN 'BLUE'
WHERE ID = #myIdValue
For MS SQL Server you can use an UPDATE FROM which will update two properties at the same time, like this:
CREATE TABLE MYTABLE (
ID INT,
PROP_NAME VARCHAR(20),
PROP_VALUE VARCHAR(20));
go
INSERT INTO MYTABLE VALUES (1, 'A','B')
go
INSERT INTO MYTABLE VALUES (1, 'C', 'D')
go
UPDATE MYTABLE
SET PROP_VALUE = X.PROP_VALUE
FROM MYTABLE MT JOIN (
SELECT 'A' AS PROP_NAME, 'F' AS PROP_VALUE
UNION
SELECT 'C' AS PROP_NAME, 'G' AS PROP_VALUE) AS X ON MT.PROP_NAME = X.PROP_NAME
WHERE ID = 1
For other SQL DB server the solution should be similar if not identical.

SQL UPDATE doesn't work with foreign languages (Arabic)

the UPDATE gives ???? if the updater field was written in Arabic and this is my query:
UPDATE students
SET first_name = 'الاسم' , last_name = 'الاسم الاخير' ,
father_name = 'الاسم الاخير' , mother_name = '',
birth_date = '1/1/1990 12:00:00 AM' , education_level = '' ,
address = '' , notes = ''
WHERE student_id = 33
And here is the result of the update:
student_id first_name last_name mother_name father_name birth_date
33 ????? ????? ?????? ??????????? 1990-01-01
//the answer is great and thank you people, another question is that I am using this UPDATE syntax in my C# program
command.CommandText = "UPDATE students SET " +
"first_name = " + "'" + first_name + "'" + " , last_name = " + "'" + last_name + "'" +
" , father_name = " + "'" + father_name + "'" + " , mother_name = " +
"'" + mother_name + "'" + ", birth_date = " + "'" + birth_date + "'" +
" , education_level = " + "'" + education_level + "'" +
" , address = " + "'" + address + "'" + " , notes = " + "'" + notes + "'" +
" WHERE student_id = " + id ;
//how to use the character N
You have forgotten the N prefix before your string literals which is required so they will be treated as nvarchar rather than varchar
SET first_name = N'الاسم' etc.
without that the text is coerced into whatever characters the code page of your default collation can deal with.
Create the database with this collation Arabic_CI_AS, you won't need to put N before the Arabic characters.

How to fetch distinct values from multiple rows of select query?

I have used query as
string getPlayers = " Select Player1,Player2,Player3,Player4,Player5 from tbl_game where Player1=" + userid + " OR Player2=" + userid + " OR Player3=" + userid + " OR Player4=" + userid + " OR Player5=" + userid + " AND Complete = 'No' ";
It gives result as multiple rows that fulfills the condition.
But I want to store values of distinct Player1,Player2,Player3,Player4,Player5 in variables returned from select query, so that i can use these values for further case.
How can i do this ?
Please help me. I am very confused.
EDITED :
I got the result of select query as -
(1,2,2,4,5)
(2,3,1,4,5)
(4,3,5,1,2)
Where 1,2,3,4,5 are userids(players).
I want store these userids in variables as -
p1=1 , p2=2 , p3=3 ,p4=4, p5=5
string getPlayer1 = (" select var1 from (" Select distinct Player1 as var1 ,Player2,Player3,Player4,Player5 from tbl_game where Player1=" + userid + " OR Player2=" + userid + " OR Player3=" + userid + " OR Player4=" + userid + " OR Player5=" + userid + " AND Complete = 'No' "));
var1 will have a value of player1. Repeat this for all other players. Hope this is what you want.