Update multiple column and row using temp table - sql

I'm trying to update multiple column value on condition, but it's updating only single column. I'm not able to figure out why it's not updating all columns.
This is my SP.
CREATE PROCEDURE [dbo].[MIC_UpdateIdeaInline]
(
#UpdatedBy int,
#UpdatedOn Datetime,
#UpdateRecords [UpdateIdeaInline] READONLY
)
as
BEGIN
UPDATE MI
SET MI.IsPortalShare= CASE WHEN ColoumnName = 'IsPortalShare' THEN CAST(ur.ColValue as BIT) ELSE IsPortalShare END
,MI.Validity= CASE WHEN ColoumnName = 'Validity' THEN CAST(ur.ColValue as BIT) ELSE Validity END
,MI.DeadLine= CASE WHEN ColoumnName = 'DeadLine' THEN CAST(ur.ColValue as datetime) ELSE DeadLine END
,MI.UpdatedBy=#UpdatedBy, MI.UpdatedOn=#UpdatedOn
from [MIC_Idea] MI
Join #UpdateRecords ur ON MI.Id=ur.IdeaId
SELECT 1
END
These are my parameter while calling SP.
declare #p3 dbo.UpdateIdeaInline
insert into #p3 values(N'15',N'Validity',N'1')
insert into #p3 values(N'15',N'DeadLine',N'15-Jun-2017')
insert into #p3 values(N'14',N'Validity',N'0')
insert into #p3 values(N'14',N'DeadLine',N'15-Jun-2017')
exec MIC_UpdateIdeaInline #UpdatedBy=1,#UpdatedOn='2017-06-06 21:45:19.863',#UpdateRecords=#p3
go
UpdateIdeaInline is table type. It's first column contain
Id
ColumnName
ColumnValue
As You can see I want to update Column (validity and DeadLine) for same ids 14 and 15. But it's only updating validity column.

That's because your update is in single atomic transaction. Update statement updates the table twice, because ID is duplicated in UpdateRecords table. So on the second update it cannot read the value updated by the first update.
Example:
You have values 10 and 15.
Now you issue a single UPDATE joining with UpdateRecord table which has two identical IDs, but each ID for different column.
E.g. UpdateRecord has
'Col1', 30
'Col2', 40
After first update:
10-->30 (pending)
15-->15 (pending)
After second update:
10-->10 (pending)
15-->40 (pending)
After transaction is committed:
10-->10
15-->40

Related

Microsoft SQL Server - default value provided by stored procedure

Is it possible to have a non-null column where the value is generated at insert by calling a stored procedure the parameters of which are values passed to insert into the row?
For example, I have table User:
| username | name | surname | id |
Insert looks like this:
INSERT INTO USER (username, name, surname)
VALUES ('myusername', 'myname', 'mysurname');
The id column is populated with an (integer) value retrieved by calling stored procedure mystoredproc with parameters myusername, myname, mysurname.
A further question is, would this stored procedure be called on each row, or can it be called in a grouped fashion. For example, I'd like my stored procedure to take the name and append a random integer to it so that that if I insert 100 users with the name 'David', they will get the same id and the stored procedure will be called only once. A bit of a bad example on the second point.
Good day,
Is it possible to have a non-null column where the value is generated at insert by calling a stored procedure
Option 1: please check if this work for you
Specify Default Value for the Column and use "NOT NULL"
create trigger on the table AFTER INSERT
Inside the trigger, you can use the virtual table "inserted" in order to get the inserted values.
Using these values (using the inserted table) you can update the column using the logic you need for all the rows at once
** there is no need to use external SP probably, but you can execute SP from trigger if needed
** All executed by a trigger is in the same transaction as the original query.
would this stored procedure be called on each row
NO! The trigger will be executed once for all rows you insert in the same statement. The inserted table includes all the rows which were inserted. In your update section (step 4) you can update all the rows which were inserted in once and no need to execute something for each row
** If you do use external SP which is executed from the trigger then you can pass it all the inserted table as one using Table-Valued Parameter
------------------- update ---------------
Here is a full example of using this logic:
drop table if exists T;
CREATE TABLE T (id int identity(2,2), c int NOT NULL default 1)
GO
CREATE TRIGGER tr ON T AFTER INSERT
AS BEGIN
SET NOCOUNT ON;
UPDATE T SET T.c = T2.C + 1
FROM inserted T2
INNER JOIN T T1 ON T1.id = T2.id
END
INSERT T(c) values (1) -- I insert the value 1 but the trigger will change it to 1+1=2
select * from T
GO
-- test multiple rows:
INSERT T(c) values (10),(20),(30),(40)
select * from T
GO
DECLARE #rc INT = 0,
#UserID INT = ABS(CHECKSUM(NEWID())) % 1000000 + 1;
WHILE #rc = 0
BEGIN
IF NOT EXISTS (SELECT 1 FROM dbo.Users WHERE UserId= #UserId)
BEGIN
INSERT dbo.Users(UserId) WHERE Username = #UserName SELECT #UserId;
SET #rc = 1;
END
ELSE
BEGIN
SELECT #UserId = ABS(CHECKSUM(NEWID())) % 1000000 + 1,
#rc = 0;
END
END

FIM - SQL Triggers for updating records in Delta table

I'm writing a DML trigger when change (update or Insert) happens in one table (Master table), I want to write the whole row into another table (Delta table).
The Master and Delta tables contains the same column with same datatype, except that Delta table contains an additional column called 'change_type', which should say either 'INSERT' OR 'MODIFY', depending on which trigger is updating the delta table.
The difficulty I'm having is I want to use the inserted table to update the Delta table row but its giving me errors.
CREATE TRIGGER [dbo].[TR_Update]
ON [dbo].[People_Master]
AFTER Update
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare #RowCount int
Declare #ID int
Declare #Email nvarchar(50)
Declare #ct nvarchar(10)
select #ID = ID from inserted
Select #RowCount=COUNT(*) from People_Delta where People_Delta.ID = #ID and People_Delta.change_type = 'Modify';
if(#RowCount = 0)
Begin
Insert into People_Delta (ID,Email,uac,Department,FirstName,change_type)
values (iserted.ID,inserted.Email,inserted.uac,inserted.Department,inserted.Firstname'Modify');
END
END
GO
My table has 5 columns.
ID (primary key)
Email
Firstname
uac
Department
You are missing a , in your INSERT statement.
And because the number of columns you have specified does not match with the number of values you are inserting, you get an error.
inserted.Firstname , 'Modify'
Insert into People_Delta (ID,Email,uac,Department,FirstName,change_type)
values (iserted.ID,inserted.Email,inserted.uac,inserted.Department,inserted.Firstname,'Modify');

SQL Trigger Conditional Insert - number of supplied values error

I've cobbled together a trigger based on some answers I found here that I think is close, but is returning a supplied value error that I'm not sure how to fix. In short I have a ParticipationStatus table that I want to add a record to that will include the UserID of the inserted and a status of 'Pending' whenever a user RoleID of '19' is inserted in the UserRole table.
The Participation_Status table has a few other fields, but the only one that is required is an auto_id column. Here is what I have so far that is throwing a "Column name or number of supplied values does not match table definition." Any suggestions would be greatly appreciated.
CREATE TRIGGER [dbo].[trg_insert_status_participation] ON [dbo].[UserRoles]
FOR INSERT AS
BEGIN
If (SELECT RoleID FROM INSERTED)=19
DECLARE #UserID int
DECLARE #Status nvarchar(50)
INSERT INTO ParticipationStatus
VALUES (#UserID, #Status)
SET #UserID = (select UserID from inserted)
SET #Status = 'Pending'
END
INSERTED can have more than one row. You need to code your trigger accordingly. It's actually much simpler this way.
CREATE TRIGGER [dbo].[trg_insert_status_participation] ON [dbo].[UserRoles]
FOR INSERT AS
BEGIN
INSERT INTO ParticipationStatus(UserID, Status)
SELECT UserID, 'Pending' FROM INSERTED
WHERE RoleID = 19
END

SQL insert statement from another table loop

I am trying to take values from a table and insert them into another table. However, there is one database column that needs to increase by 1 value each time. This value though is not an identity insert column, the value comes from another table. There is another db column that acts as a counter. I wrote a couple of things but it just isnt helping:
(121 documents)
declare #count int;
set #count=0
while #count<=121
begin
insert into cabinet..DOCUMENT_NAMES_ROBBY (TAG,TAGORDER,ACTIVE,QUEUE,REASON,FORM,DIRECT_VIEW,GLOBAL,FU_SIGN,
SIGN_X,SIGN_Y,SIGN_W,SIGN_H,ANNOTATE,doctype_id,CODE,DOC_TYPE,SET_ID,SUSPEND_DELAY,Text_Editing,Restrict_Viewing,Viewing_Expire,
Viewing_Period,DocHdrLength,DocFtrLength,DocRuleId,Outbound,SigQueue,SigReason) select TAG,TAGORDER,ACTIVE,QUEUE,REASON,FORM,
DIRECT_VIEW,GLOBAL,FU_SIGN,
SIGN_X,SIGN_Y,SIGN_W,SIGN_H,ANNOTATE,(select nextid from cabinet..Wfe_NextValue where Name='documents')+1, CODE,DOC_TYPE,'2',SUSPEND_DELAY,Text_Editing,Restrict_Viewing,Viewing_Expire,
Viewing_Period,DocHdrLength,DocFtrLength,DocRuleId,Outbound,SigQueue,SigReason from cabinet..document_names where SET_ID ='1'
update cabinet..Wfe_NextValue set NextID=NextID+1 where Name='documents'
set #count=#count+1
end
That database column is the doctype_id. Above obviously comes out wrong and puts like 14,000 rows in the table. Basically I want to take every single entry from document_names and put it in document_names_robby...except the doctype_id column should take the value from wfe_nextvalue +1, while at the same time increasing that number in that table by 1 BEFORE inserting the next document name into document_Names_Robby. Any help is appreciated
Many popular databases support sequences. For the sequence, there is a function nextval that returns the sequence value and increments the sequence counter and currval that returns the latest previously returned value, also you can set the initial value and increment. Sequences are thread safe when storing counters in the table column is not.
Rewrite your code using sequences.
Assuming that you are using SQL Server database. Use IDENTITY function
SELECT *, IDENTITY(int, 1,1) AS IDCol FROM Cabinet.DocumentNames INTO #Tab1 WHERE Set_Id = '1';
insert into cabinet..DOCUMENT_NAMES_ROBBY (TAG,TAGORDER,ACTIVE,QUEUE,REASON,FORM,DIRECT_VIEW,GLOBAL,FU_SIGN,
SIGN_X,SIGN_Y,SIGN_W,SIGN_H,ANNOTATE,doctype_id,CODE,DOC_TYPE,SET_ID,SUSPEND_DELAY,Text_Editing,Restrict_Viewing,Viewing_Expire,
Viewing_Period,DocHdrLength,DocFtrLength,DocRuleId,Outbound,SigQueue,SigReason)
SELECT * FROM #Tab1;
DROP TABLE #Tab1;
declare #count int;
set #count=0
declare #nextId int;
select #nextId= nextid from cabinet..Wfe_NextValue where Name='documents'
while #count<=121
begin
insert into cabinet..DOCUMENT_NAMES_ROBBY (TAG,TAGORDER,ACTIVE,QUEUE,REASON,FORM,DIRECT_VIEW,GLOBAL,FU_SIGN,
SIGN_X,SIGN_Y,SIGN_W,SIGN_H,ANNOTATE,doctype_id,CODE,DOC_TYPE,SET_ID,SUSPEND_DELAY,Text_Edi ting,Restrict_Viewing,Viewing_Expire,
Viewing_Period,DocHdrLength,DocFtrLength,DocRuleId,Outbound,SigQueue,SigReason) select TAG,TAGORDER,ACTIVE,QUEUE,REASON,FORM,
DIRECT_VIEW,GLOBAL,FU_SIGN,
SIGN_X,SIGN_Y,SIGN_W,SIGN_H,ANNOTATE,(select nextid from cabinet..Wfe_NextValue where Name='documents')+1, CODE,DOC_TYPE,'2',SUSPEND_DELAY,Text_Editing,Restrict_Viewing,Viewing_Expire,
Viewing_Period,DocHdrLength,DocFtrLength,DocRuleId,Outbound,SigQueue,SigReason from cabinet..document_names where SET_ID ='1'
set #count=#count+1
end
update cabinet..Wfe_NextValue set NextID=NextID+121 where Name='documents'

Sometimes SQL Server trigger is not firing

I created a trigger on my recharge table. It updates the balance of onaccountregistry table.
But sometimes when inserting rows into my recharge table it is not firing the trigger. Then values are mismatch. This recharge table insert rows every time.
I created the trigger as follows. This is not a replicated table. I'm using SQL Server 2008 Enterprise edition.
Please help me solve this matter
CREATE TRIGGER [dbo].[RechargeRefund]
ON [dbo].[ISRecharge]
FOR INSERT
AS
declare #tin char(9)
declare #depocd char(1)
declare #oldvalue money
declare #newvalue money
begin
select #tin = inserted.tin_subtin from inserted
select #depocd = inserted.updatetype from inserted
select #newvalue = inserted.DepositAmt from inserted
select #oldvalue = Totdeposit from ISOnAcctRegistry where tin_subtin = #tin
end
if #depocd ='1'
begin
update ISOnAcctRegistry
set Totdeposit = #oldvalue + #newvalue
where tin_subtin = #tin
end
if #depocd ='2'
begin
update ISOnAcctRegistry
set Totdeposit = #oldvalue - #newvalue
where tin_subtin = #tin
end
GO
As #marc points out, writing assuming a single row in inserted is bad - it can even be possible for your 3 selects from inserted to assign values to your 3 variables from 3 different (arbitrary) rows from inserted.
What you probably want is:
update i1
set Totdeposit = Totdesposit + t2.Total
from ISOnAcctRegistry i1
inner join
(select
tin_subtin,
SUM(CASE updatetype
WHEN 1 THEN DepositAmt
WHEN 2 THEN -DepositAmt
ELSE 0 END) as Total
from inserted
group by tin_subtin) t2
on
i1.tin_subtin = t2.tin_subtin
But you might be able to replace this work (and this column in ISOnAcctRegistry) with an indexed view built on ISRecharge - with some limitations, you can build a view that automatically performs a SUM across the rows in ISRecharge, and SQL Server would take responsibility for maintaining the value in the background for you.
Obviously, at present, your trigger doesn't account for any UPDATE or DELETE activity on ISRecharge. An indexed view would.
Well, of course it won't work - you're assuming that the trigger fires once per row inserted.
But that's NOT the case.
The trigger fires once per INSERT batch, and the pseudo-table Inserted might contain multiple rows!
If you did get an INSERT with more than one row - which row did your statements here select ?
select #tin = inserted.tin_subtin from inserted
select #depocd = inserted.updatetype from inserted
select #newvalue = inserted.DepositAmt from inserted
select #oldvalue = Totdeposit from ISOnAcctRegistry where tin_subtin = #tin
You need to rewrite your trigger so that it will handle multiple rows in Inserted - then it'll work every time.