What happens in this case, assuming col1 has initially the value of 10:
UPDATE myTable
SET col1 = 20,
col2 = col1 + 10
Will col2 be 20 or 30 after the update?
Too long for a comment.
It will be 20 according to the rules of standard SQL. The new values do not get committed until the end of the update statement. They are not committed row-by-row or column-by-column. Remember the ACID properties of databases -- all the changes take effect at the same time.
It is possible that some database out there does not behave this way. It is easy enough to check in practice.
The column will show 20
the Update function is running as a bulk.
you can do this quick test:
/* Create Test Table
select
10 as col1,
0 as col2
into TestTable
*/
/* update
update TestTable
set col1 = 20,
col2 = col1 + 10
*/
select * from TestTable
Related
Say I have something like this :
UPDATE my_table set col2 = '5' where col1 = '111';
UPDATE my_table set col2 = '5' where col3 = '112';
And now I make a before update trigger and I want to know the columns used in UPDATE statement (i.e col1, col3). In other words, can I see the exact update statement that was used in trigger?. Is this possible ?
Thank you!
No you can't. The trigger has no knowledge of what statement led to its execution.
I have a database which collects data from an application. And now, I have to create another column that will be populated with predefined data depending on the values in other columns. So, no math, just to look up the values in two other columns and insert the data into the newly added column.
Example
id column1 column2 newColumn
1 15 3 100
So when column1 has 15, and column2 has 3, the newColumn should be auto-populated with 100. Again, the number 100 is predifned, not calcualted.
I know I can use triggers for new entries, but the database already has a large amount of data entered, so is there a way to auto populate the newColumn for data that is already tere?
EDIT --------------------------------
So I can use update to populate the column for the records that are already entered ?!
Can i make a trigger which will wait for both values and until both are entered it will return NULL?
You can create scalar function:
ALTER FUNCTION [dbo].[Test] ( #column1 INT, #column2 INT)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
DECLARE #r INT
IF #column1 = 15 AND #column2 = 3
SET #r = 100
ELSE
SET #r = NULL
RETURN #r
END
And then add new computed column:
ALTER TABLE TableName ADD ColumnName AS dbo.Test(column1, column2) PERSISTED
Persisted means, that column is not calculated on the fly, but data is saved.
That's why you used WITH SCHEMABINDING. Without binding you can not make the column persisted.
You can also update your current data with simple update statement like in #Rhys Jones answer and add trigger on table like:
ALTER TRIGGER trTest ON TableName
AFTER INSERT, UPDATE
AS
BEGIN
IF UPDATE(column1) AND UPDATE(column2)
BEGIN
UPDATE TableName
SET NewColumn = CASE
WHEN column1 = 15 and column2 = 3 then 100
ELSE NULL
END
FROM Inserted i
JOIN TableName t ON t.id = i.id
END
END
You could just use a single UPDATE to update the missing values, then use the TRIGGER for new rows.
update MyTable set
newColumn = case
when column1 = 15 and column2 = 3 then 100
when ...
end
where
newColumn is null
However, note what #jarlh says above, there are usually better ways of doing this such as views or computed columns.
This question already has answers here:
T-SQL conditional UPDATE (v2)
(8 answers)
Closed 8 years ago.
I've been given a list of changes to make to a table. I was wondering how it would be possiblet to make all of the changes in one script...I've tried the following
UPDATE tableA
SET col1 = 'somedata' WHERE col2 = 'somereference'
SET col1 = 'someotherdata' WHERE col2 = 'someotherreference'
SET col1 = 'evenmoredata' WHERE col2 = 'anotherreference'
but this doesn't work. Is there a specific syntax I can use to achieve this, or am I stuck with doing it like this:-
UPDATE tableA
SET col1 = 'somedata' WHERE col2 = 'somereference'
UPDATE tableA
SET col1 = 'someotherdata' WHERE col2 = 'someotherreference'
for each change I want to make?
Use a case statement in the single set statement:
UPDATE tableA
SET col1 = case col2
when 'somereference' then 'somedata'
when 'someotherreference' then 'someotherdata'
when 'anotherreference' then 'evenmoredata'
else col1
end
Its a good idea to put the default in of the original value incase whatever where clause you're using mis-fires (and you should use the where clause anyway otherwise you'll update all rows)
Is it possible (in SQL SERVER 2012) to read data before update in one transaction.
Example:
I have one table, name: tab with two columns col1 and col2. I have one record: col1 = 1 and col2 = 'a'
begin transaction
update tab set col2 = 'A' where col1 = 1
-- here i want to read data before update (in this example 'a')
-- here i want to read data after update (in this example 'A')
Committ transaction
Before committ transaction when using select always i get data after update (in this example 'A'). I try to do
select * from tab with(nolock)
but it doesn't work.
Question: In section: after update and before committ - can i read data which was before update ?
Thanks.
Locking hints determine how nicely you read data that is being updated by another transaction. But code that runs in a transaction always sees changes made earlier in the same transaction.
If you need the old state, why not store the old version in a variable? Like:
begin transaction
declare #old_col2 int
select #old_col2 = col2 from tab where id = 1
update tab set col2 = 'A' where id = 1
... now you can access both the old and the new data ...
You can achieve the same using below sample :
USE AdventureWorks2012;
GO
DECLARE #MyTableVar table(
EmpID int NOT NULL,
OldVacationHours int,
NewVacationHours int,
ModifiedDate datetime);
UPDATE TOP (10) HumanResources.Employee
SET VacationHours = VacationHours * 1.25,
ModifiedDate = GETDATE()
OUTPUT inserted.BusinessEntityID,
deleted.VacationHours,
inserted.VacationHours,
inserted.ModifiedDate
INTO #MyTableVar;
--Display the result set of the table variable.
SELECT EmpID, OldVacationHours, NewVacationHours, ModifiedDate
FROM #MyTableVar;
GO
--Display the result set of the table.
SELECT TOP (10) BusinessEntityID, VacationHours, ModifiedDate
FROM HumanResources.Employee;
GO
This is elegant solution instead of writing seperate SELECTs in the code.
Reference http://msdn.microsoft.com/en-IN/library/ms177564.aspx
In a trigger, I have code like:
SET #var1 = (SELECT col1 FROM Inserted);
SET #var2 = (SELECT col2 FROM Inserted);
Is it possible to write the above in a single line? Something conceptually like:
SET (#var1,#var2) = (SELECT col1,col2 FROM Inserted);
Obviously I tried the above, without success; am I just stuck with the first method?
Even if possible, is that a good idea?
Thanks!
yes, use first method.
Or...
SELECT
#var1 = col1
,#var2 = col2
FROM
Inserted;
However, it is a major red flag if you are expecting to set variable values like that in a trigger. It generally means the trigger is poorly designed and needs revision. This code expects there will be only one record in inserted and this is something that is not going to be true in all cases. A multiple record insert or update will have multiple records in inserted and the trigger must account for that (please without using a trigger!!!). Triggers should under no circumstances be written to handle only one-record inserts/updates or deletes. They must be written to handle sets of data.
Example to insert the values from inserted to another table where the trigger is on table1:
CREATE TRIGGER mytrigger on table1
AFTER INSERT
AS
INSERT table2 (field1, field2, field3)
SELECT field1, 'test', CASE WHEN field3 >10 THEN field3 ELSE 0 END
FROM inserted
No, it is not possible. SET accepts a single target and value. AFAIK.