How to generate update statement on the whole table with some condition ? For example I have table
and I would like to specify date (for this example '3/16/2016') and generate something like following Update
UPDATE TableName SET ColumnValue = 30 AND ModifiedDate = '2016-03-17' WHERE Id = 2
If there will be more changes after specified date, I would like to generate all the updates for these changes.
Is there some easy solution or I have to script all this by some customized C# script ?
If you have 2 identical tables and need to update one of the tables based on changes happed after a particular timestamp (#Date) in another table then you can use below query.
UPDATE T1
SET T1.ColumnValue=T2.ColumnValue,T1.ModifiedDate=T2.ModifiedDate
FROM Table1 T1 inner join Table2 T2 on T1.ID=T2.ID
WHERE T2.ModifiedDate>=#Date
If you just want to generate update statements, you could do something like this:
declare #afterDate date = '20160316';
select update_statements = 'update table t set columnvalue = '
+convert(varchar(10),columnvalue)
+', modifieddate = '''
+replace(convert(varchar(10),modifieddate,120),'-','')+''''
+' where id = '+convert(varchar(10),id)+';'
from t
where modifieddate > #afterdate;
rextester demo: http://rextester.com/MZQ68677
returns:
+------------------------------------------------------------------------------+
| update_statements |
+------------------------------------------------------------------------------+
| update table t set columnvalue = 30, modifieddate = '20160317' where id = 2; |
+------------------------------------------------------------------------------+
This gives the trigger to track all the updates for a table. Based on table structure you can add required columns in the tracking table.
CREATE TABLE EMP(ID int, NAME VARCHAR(20), SALARY MONEY)
CREATE TABLE TrackUpdate (Id int identity, updatestmt varchar(500), DateCreated datetime)
GO
INSERT INTO EMP
VALUES
(1, 'A', 10),(2, 'E',40 ),(3,'B',5),(4,'F',40),(5,'I',50)
GO
ALTER TRIGGER TR_EMP ON EMP
INSTEAD OF UPDATE
AS
BEGIN
declare #Name varchar(10)
declare #Salary MONEY
SELECT #Name=Name,#Salary=Salary FROM inserted
insert into TrackUpdate values ('update Emp SET E.Name='''+#Name+''', '+'E.Salary='+CAST(#Salary as varchar(20)),getdate())
update E SET E.Name=I.Name, E.Salary=I.Salary
FROM EMP E inner join inserted I on I.ID=E.ID
END
update EMP set Name='D' where ID=4
select updatestmt from TrackUpdate
--drop table EMP
--drop table TrackUpdate
Related
I created a trigger that performs a check and automatically populates data into 2 tables. Only what happens the following error :
IDENTITY_INSERT is already ON for table 'X'. Cannot perform SET operation for table 'Y'.
I found this while researching the error:
"At any time, only one table in a session can have the IDENTITY_INSERT property set to ON.”
So the fix was easy:
SET IDENTITY_INSERT Table1 ON
-- insert statements for table1
SET IDENTITY_INSERT Table1 OFF
SET IDENTITY_INSERT Table2 ON
-- insert statements for table2
SET IDENTITY_INSERT Table2 OFF
SET IDENTITY_INSERT Table3 ON
-- insert statements for table3
SET IDENTITY_INSERT Table3 OFF
But as the data is populated via trigger is not possible to do so.
Does anyone have a solution to my problem please?
I apologize.
Thank you all.
Trigger-----
CREATE TRIGGER Alert ON registos AFTER INSERT AS
BEGIN
DECLARE #comp decimal = 0
DECLARE #id_sensores_em_alerta decimal
DECLARE #tempmin decimal = 0
DECLARE #current_max_idAlarme int = (SELECT MAX(IdAlarme) FROM alarmes)
DECLARE #maxidAlarme int
DECLARE #temp decimal = (SELECT s.lim_inf_temp from sensores s JOIN inserted i ON s.idSensor=i.idSensor )
-- Insert into alarmes from the inserted rows if temperature less than tempmin
INSERT alarmes (IdAlarme, descricao_alarme,data_criacao, idRegisto)
SELECT
ROW_NUMBER() OVER (ORDER BY i.idRegisto) + #current_max_idAlarme, 'temp Error', GETDATE(), i.idRegisto
FROM
inserted AS i
WHERE
i.Temperatura < #temp
SET #maxidAlarme = (SELECT MAX(IdAlarme) FROM alarmes)
INSERT INTO sensores_tem_alarmes(idSensor,idAlarme,dataAlarme)
SELECT i.idSensor, #maxidAlarme, GETDATE()
FROM inserted i
SET #comp += 1;
SET #id_sensores_em_alerta=1;
SET #id_sensores_em_alerta = (SELECT MAX(id_sensores_em_alerta) FROM sensores_em_alerta)
INSERT INTO sensores_em_alerta(id_sensores_em_alerta, idSensor, idAlarme, data_registo, numerosensoresdisparados)
SELECT #id_sensores_em_alerta, i.idSensor, #maxidAlarme, GETDATE(), #comp
FROM inserted i
end
DataBase----
I had a similar problem but it did not involve table triggers. I was running a script that refreshes data for multiple tables and I hit a foreign key reference error.
According to MSDN:
At any time, only one table in a session can have the IDENTITY_INSERT
property set to ON.
To resolve this, I ran SET IDENTITY_INSERT [dbo].[table_name] OFF for each table I was trying to insert into. Then I was able to refresh my tables again after I corrected the reference error.
Edit: I should also mention that you can just disconnect and then reconnect to reset your session.
Allow SQL Server to insert the identity values automatically for you. Since this is a trigger, there could multiple rows being inserted at a time. For one row inserts, you can use SCOPE_IDENTITY() function (http://msdn.microsoft.com/en-us/library/ms190315.aspx) to retrieve the identity value of your last inserted row. However, since we could have multiple rows inserted in a trigger, we will use the OUTPUT clause (http://msdn.microsoft.com/en-us/library/ms177564.aspx) to get back a list of the inserted IdAlarme values for each idRegisto.
I'm assuming that alarmes.IdAlarme and sensores_em_alerta.id_sensores_em_alerta are the two identity fields in this trigger. If that is the case, then this should work:
CREATE TRIGGER Alert ON registos AFTER INSERT AS
BEGIN
DECLARE #comp decimal = 0
DECLARE #id_sensores_em_alerta decimal
DECLARE #tempmin decimal = 0
DECLARE #temp decimal = (SELECT s.lim_inf_temp from sensores s JOIN inserted i ON s.idSensor=i.idSensor )
DECLARE #tblIdAlarme TABLE (idRegisto int not null, IdAlarme int not null);
-- Insert into alarmes from the inserted rows if temperature less than tempmin
-- IdAlarme is identity field, so allow SQL Server to insert values automatically.
-- The new IdAlarme values are retrieved using the OUTPUT clause http://msdn.microsoft.com/en-us/library/ms177564.aspx
INSERT alarmes (descricao_alarme,data_criacao, idRegisto)
OUTPUT inserted.idRegisto, inserted.IdAlarme INTO #tblIdAlarme(idRegisto, IdAlarme)
SELECT descricao_alarme = 'temp Error', data_criacao = GETDATE(), i.idRegisto
FROM inserted AS i
WHERE i.Temperatura < #temp
;
--It looks like this table needs a PK on both idSensor and idAlarme fields, or else you will get an error here
-- if an alarm already exists for this idSensor.
INSERT INTO sensores_tem_alarmes(idSensor,idAlarme,dataAlarme)
SELECT i.idSensor, a.IdAlarme, dataAlarme = GETDATE()
FROM inserted i
INNER JOIN #tblIdAlarme a ON i.idRegisto = a.idRegisto
;
--not sure what this is doing?? Will always be 1.
SET #comp += 1;
--id_sensores_em_alerta is an identity field, so allow SQL Server to insert values automatically
INSERT INTO sensores_em_alerta(idSensor, idAlarme, data_registo, numerosensoresdisparados)
SELECT i.idSensor, a.IdAlarme, data_registo = GETDATE(), numerosensoresdisparados = #comp
FROM inserted i
INNER JOIN #tblIdAlarme a ON i.idRegisto = a.idRegisto
;
END
I have a scenario where i have to update record in database table from another database table based on recently updated record.
if record is new insert statement will fire
if record is updated Update statement will fire
here the problem is we don't know number of table return by query
as well as column name.
here is code
DECLARE #RowsToProcess int
DECLARE #CurrentRow int
declare #tablenames varchar(100)
DECLARE #sampleTable TABLE(RowID int not null primary key identity(1,1), tablename varchar(100),last_user_update datetime)
insert into #sampleTable SELECT [TableName] = OBJECT_NAME(object_id),last_user_update
FROM sys.dm_db_index_usage_stats
WHERE database_id = DB_ID('DATABASE')
select * from #sampleTable
SET #RowsToProcess=##ROWCOUNT
print #RowsToProcess
SET #CurrentRow=0
WHILE #CurrentRow<#RowsToProcess
BEGIN
SET #CurrentRow=#CurrentRow+1
SELECT #tablenames= tablename from #sampleTable
WHERE RowID=#CurrentRow
print #tablenames
EXEC('INSERT INTO '+ 'SM_' + #tablenames +' SELECT * FROM '+#tablenames + 'Where flag = NULL' )
END
In SQL Server, you can use triggers. SQL Server triggers can fire on insert, on update, on delete or instead of insert, etc.
You may get started using this lesson
i want get value of field after update,
for example i have two table
table1: ID Price UserID type
table2: IDLog ID(FK table1) OldPrice
and i update Price in table 1:
UPDATE table1
SET Price = '1111'
WHERE TYPE = 1
now i want befor every update get value ID table1 and insert into table2,
how i get value every field??
IMHO FOR UPDATE TRIGGER is the way to go. That way you can contain all logging logic inside your DB.
Better way to do it is using trigger on table1 (SQL Server side of course).
CREATE TRIGGER table1_update ON table1 FOR UPDATE
AS
BEGIN
INSERT INTO table2 (IDLog, OldPrice)
SELECT ID, Price
FROM deleted
INNER JOIN inserted ON
deleted.ID = inserted.ID
deleted.Price <> inserted.Price
END
You can use output clause:
update table1
output inserted.ID into table2
set Price='1111' where type=1
You can insert data to table2 before updating.
INSERT INTO table2
SELECT ID, Price from table1
WHERE TYPE = 1
--Update table1 after inserting
UPDATE table1
SET Price = '1111'
WHERE TYPE = 1
Other way to do is to create an update trigger for table1, which inserts the updated data to table2.
I have a table DEPT, which holds 2 columns - ID, NAME.
A search form is presented with the IDs from the DEPT table and the user can chose any number of IDs and submit the form, to get the related NAMEs.
Clarification/Inputs:
I don't want to build a dynamic query - its not manageable.
I prefer a stored procedure using table-valued parameters
Any other solutions to proceed?
NOTE:
This example is simple with 1 table - in real life, I have to deal with more than 6 tables!
Thanks for any suggestions
CREATE TYPE dbo.DeptList
AS TABLE
(
ID INT
);
GO
CREATE PROCEDURE dbo.RetrieveDepartments
#dept_list AS dbo.DeptList READONLY
AS
BEGIN
SET NOCOUNT ON;
SELECT Name FROM dbo.table1 WHERE ID IN (SELECT ID FROM #dept)
UNION ALL
SELECT Name FROM dbo.table2 WHERE ID IN (SELECT ID FROM #dept)
-- ...
END
GO
Now in your C# code, create a DataTable, fill it in with the IDs, and pass it in to the stored procedure. Assuming you already have a list called tempList and the IDs are stored in id:
DataTable tvp = new DataTable();
tvp.Columns.Add(new DataColumn("ID"));
foreach(var item in tempList)
{
tvp.Rows.Add(item.id);
}
using (connObject)
{
SqlCommand cmd = new SqlCommand("StoredProcedure", connObject);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvparam = cmd.Parameters.AddWithValue("#dept_list", tvp);
tvparam.SqlDbType = SqlDbType.Structured;
...
}
You can also use a split function. Many exist, this is the one I like if you can guarantee that the input is safe (no <, >, & etc.):
CREATE FUNCTION dbo.SplitInts_XML
(
#List VARCHAR(MAX),
#Delimiter CHAR(1)
)
RETURNS TABLE
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'int')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>') + '</i>').query('.')
) AS a
CROSS APPLY x.nodes('i') AS y(i)
);
GO
Now your procedure can be:
CREATE PROCEDURE dbo.RetrieveDepartments
#dept_list VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
;WITH d AS (SELECT ID = Item FROM dbo.SplitInts(#dept_list, ','))
SELECT Name FROM dbo.table1 WHERE ID IN (SELECT ID FROM d)
UNION ALL
SELECT Name FROM dbo.table2 WHERE ID IN (SELECT ID FROM d)
-- ...
END
GO
I need to turn this query into an update statement. I will have to update the values from fields. Everything is already in place but the update statement.
Here is the select version of the query:
SELECT i.GoLiveDate, i.FirstBonusRun, i.TechFName, i.TechLName, i.TechEmail, i.TechPhone, i.WebISPFName, i.WebISPLName,
i.WebISPEmail, i.WebISPPhone, i.FullFillFName, i.FullFillLName, i.FullFillEmail, i.FullFillPhone, d.FName,
d.LName, d.HomePhone, d.Email
FROM NC_Information i
INNER JOIN Distributor d
ON d.DistID = i.ClientID
WHERE clientID = #value
Is it possible to update two different tables from within the same query?
Here is the code I have so far:
public void Update (int ClientID)
{
using ( var conn = new SqlConnection( GeneralFunctions.GetConnectionString() ) )
using ( var cmd = conn.CreateCommand() )
{
conn.Open();
cmd.CommandText =
#"SELECT i.GoLiveDate, i.FirstBonusRun, i.TechFName, i.TechLName, i.TechEmail, i.TechPhone, i.WebISPFName, i.WebISPLName,
i.WebISPEmail, i.WebISPPhone, i.FullFillFName, i.FullFillLName, i.FullFillEmail, i.FullFillPhone, d.FName,
d.LName, d.HomePhone, d.Email
FROM NC_Information i
INNER JOIN Distributor d
ON d.DistID = i.ClientID
WHERE clientID = #value";
cmd.Parameters.AddWithValue( "#value", ClientID );
cmd.ExecuteNonQuery();
}
}
You can't update multiple tables in one statement, but you can use a transaction to make sure that the updates are contingent upon one another:
BEGIN TRANSACTION
UPDATE SomeTable
SET SomeColumn = 'Foo'
WHERE SomeID = 123
UPDATE AnotherTable
SET AnotherColumn = 'Bar'
WHERE AnotherID = 456
COMMIT
I think, you cannot directly do the update on two tables. But you can Optimize the query.
How?
OUTPUT keyword in Insert/Update/Delete Statement
The first Update Statement's Select Data(filtered data) can be reused using the below mentioned example.
CREATE TABLE #table1
(
id INT,
employee VARCHAR(32)
)
go
INSERT INTO #table1 VALUES
(1, 'name1')
,(2, 'name2')
,(3, 'name3')
,(4, 'name4');
GO
DECLARE #GuestTable TABLE
(
id INT,
employee VARCHAR(32)
);
update #table1
Set id = 33
OUTPUT inserted.* INTO #GuestTable
Where id = 3
The Data in the '#GuestTable' Table is filtered data and can be
reused.
select * from #GuestTable
drop table #table1
Alternatively, you can create a dataset with two datatables, and let the tableadaptermanager manage the updates.