Updating multiple columns in a case statement - sql-server-2005

I want to check, if a sponsor has a user with a TotalBV >= 50001 then the sponsor's Rank, DP, Leadership_Bonus will be updated with specific values
If there sponsor has 1 user whose TotalBV >= 50001, then update his records with the values in the first case statement.
If there sponsor has 2 users whose TotalBV >= 50001, then update his records with the values in the second case statement.. and so on
This is what I have done so far but I am getting errors in the update statement:
declare #UserId varchar(50),#myInt int,#SponsorId varchar(50),#Rank varchar(50),#dp int,#LB int
declare c1 cursor READ_ONLY
for
set #myInt = (select COUNT(User_Id) from UserTransaction as count where #SponsorId='RL9058' and TotalBV>=50001)
open c1
fetch next from c1
into #SponsorId,#UserId,#Rank
while ##FETCH_STATUS=0
BEGIN
update UserTransaction set Rank,DP,Leadership_Bonus=(case
when (#myInt=1 and TotalGBV=25000 and TotalPBV=200) then (Rank='executive' and DP=(0.309*BV) and Leadership_Bonus=(0.07*BV))
when (#myInt=2 and TotalGBV=20000 and TotalPBV=200) then (rank='star executive' and dp=(0.318*BV) and leadership_bonus=(0.03*BV))
when (#myInt=3 and TotalGBV=20000 and TotalPBV=300) then (rank='Organizer' and dp=(0.327*BV) and leadership_bonus=(0.02*BV))
when (#myInt=4 and TotalGBV=15000 and TotalPBV=300) then (rank='Star Organizer' and dp=(0.336*BV) and leadership_bonus=(0.01*BV))
when (#myInt=5 and TotalGBV=15000 and TotalPBV=500) then (rank='Co-Ordinater' and dp=(0.345*BV) and leadership_bonus=(0.01*BV))
when (#myInt=6 and TotalGBV=10000 and TotalPBV=500) then (rank='Star Co-Ordinater' and dp=(0.354*BV) and leadership_bonus=(0.01*BV))
when (#myInt=7 and TotalGBV=10000 and TotalPBV=1000) then (rank='7Star Co-Ordinater' and dp=(0.360*BV) and leadership_bonus=(0.01*BV))
else null end)
where #SponsorId='RL9058'
FETCH NEXT FROM c1
into #UserId,#SponsorId,#Rank,#dp,#LB
END
close c1
DEALLOCATE c1

Related

Count the amount of Cases and set Status on CaseStatus table if every counted amount is the statusCode 601 in the Cursor

Hello I made a cursor that check every row and check the status of the Caseinventory and then sets the status on the caseStatus. Problem is if I set the last counted row to 601 and it changes the code to 3 (shown in the code) it will not check if the rest is 601 and then just set the status to 3 even though rest is 600 or 599.
How can I solve this? should I count the amount on the CaseInventory and then check the status on every counted row and then update if the value is 601? and how do you do this? first time using cursor.
ALTER PROCEDURE [dbo].[SetsStatusOnCaseStatusByCaseInventoryStatus]
#StatusID INT,
#ID int,
#CaseInventoryID int
AS
BEGIN
--find caseID on CaseInventoryID
declare #CaseID int = (SELECT CaseID from [dbo].[factCaseInventory] where ID=#ID)
--CaseStatus
declare #CaseIkkeStartet int =1
declare #CaseIgangStatus int = 2
declare #CaseDoneStatus int = 3
--CaseInventoryStatus
DECLARE #NotStarted int = 599
DECLARE #Nocode int = 600
declare #YesCode int = 601
--Cursor
declare CaseInventoryCursor cursor for
Select ID, StatusID, CaseID from [dbo].[factCaseInventory]
open CaseInventoryCursor
fetch next from CaseInventoryCursor into #ID, #StatusID, #CaseID
while(##FETCH_STATUS = 0)
begin
SELECT #StatusID =StatusID from [dbo].[factCaseInventory] where CaseID=#CaseID
if(#StatusID = #Nocode)
begin
update [dbo].[factCase] set CaseStatusID=#CaseDoneStatus where CaseId=#CaseID
end
else if (#StatusID =#YesCode)
begin
update [dbo].[factCase] set CaseStatusID=#CaseIgangStatus where CaseId=#CaseID
end
else if (#StatusID =#NotStarted)
begin
update [dbo].[factCase] set CaseStatusID=#CaseIkkeStartet where CaseId=#CaseID
end
fetch next from CaseInventoryCursor into #ID, #StatusID, #CaseID
end
close CaseInventoryCursor
deallocate CaseInventoryCursor
END
It's unclear to me why you're passing parameters to your stored procedure when you then either don't use them, or overwrite them with new values before you use them.
However, if what you're trying to do is update each factCase record with a new CaseStatusID value based upon the related factCaseInventory record's StatusID value, you can just do a simple UPDATE with a join:
update fc set CaseStatusID =
case fci.StatusID
when 600 then 3
when 601 then 2
when 599 then 1
end
from factCaseInventory fci
left join factCase fc on fvi.CaseID = fc.CaseID

Why my cursor isn't returning the first row values?

I have a cursor in order to separate rows based on a required quantity for each item, this works kind of fine, with the exception that it doesn't return the first rows and instead, if the row for example has a value of quantity 3, it adds it to the last row. My code is the following:
DECLARE curCURSOR CURSOR
FOR
SELECT ITEM, CITY, OPEN_QUANTITY, MODEL, PROMISE , SALES_ORDER , LINE_NUMBER, DESCRIPTION, CARRIER FROM T_tmpShipReporCommAssy
WHERE [DESCRIPTION] like 'COM%ASSY%' AND CITY = #pSite
AND FG_AVAILABLE > 0
ORDER BY PROMISE, SALES_ORDER, LINE_NUMBER
OPEN curCURSOR
FETCH curCURSOR INTO #ITEM, #CITY, #required_quantity, #MODEL, #PROMISE, #SALES_ORDER, #LINE_NUMBER, #DESCRIPTION, #CARRIER
IF EXISTS(SELECT 1 FROM AvailToShipPalletsSN)
BEGIN
DELETE FROM AvailToShipPalletsSN
DBCC CHECKIDENT ('[AvailToShipPalletsSN]', RESEED, 0);
END
DECLARE #e INT
SET #e = 0
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH FROM curCURSOR INTO #ITEM, #CITY, #required_quantity, #MODEL, #PROMISE, #SALES_ORDER, #LINE_NUMBER, #DESCRIPTION, #CARRIER
WHILE (#e < #required_quantity)
BEGIN
INSERT INTO AvailToShipPalletsSN (item, city, required_quantity, MODEL, PROMISE, SALES_ORDER, LINE_NUMBER, DESCRIPTION, CARRIER) values
(#ITEM, #CITY, #required_quantity, #MODEL, #PROMISE, #SALES_ORDER, #LINE_NUMBER, #DESCRIPTION, #CARRIER)
SET #e = #e + 1
END
SET #e = 0
END
CLOSE curCURSOR
DEALLOCATE curCURSOR
Now, when I run a select count to the original table and the generated one:
SELECT MODEL, SUM(OPEN_QUANTITY) FROM T_tmpShipReporCommAssy
WHERE [DESCRIPTION] like 'COM%ASSY%' AND CITY = #psite
AND FG_AVAILABLE > 0
AND PROMISE <= #pdate
GROUP BY MODEL
SELECT model, COUNT(required_quantity) FROM AvailToShipPalletsSN
group by model
It returns me the following results:
(Table with correct quantities)
CMF200M 10
CMF010M 2
CMF200A 1
H200F 2
(Table generated by my cursor)
CMF200M 8
CMF010M 2
CMF200A 1
H200F 4
I don't really know how to fix this behavior, I'd appreciate a little help on this topic
Cursors are very slow and inefficient, they can also be cumbersome to code against.
You can completely obviate the need for this slow and incorrect cursor, by using an inline tally table.
This is all the code you need:
IF EXISTS(SELECT 1 FROM AvailToShipPalletsSN)
BEGIN
TRUNCATE AvailToShipPalletsSN;
DBCC CHECKIDENT ('[AvailToShipPalletsSN]', RESEED, 0);
END;
WITH
L0 AS ( SELECT 1 AS c
FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),
(1),(1),(1),(1),(1),(1),(1),(1)) AS D(c) ),
L1 AS ( SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B ),
L2 AS ( SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B )
-- add more cross-joins if you need more than 65536 rows
INSERT INTO AvailToShipPalletsSN
(item, city, required_quantity, MODEL, PROMISE, SALES_ORDER, LINE_NUMBER, DESCRIPTION, CARRIER)
SELECT
ITEM, CITY, OPEN_QUANTITY, MODEL, PROMISE, SALES_ORDER, LINE_NUMBER, DESCRIPTION, CARRIER
FROM T_tmpShipReporCommAssy t
CROSS APPLY (
SELECT TOP (t.OPEN_QUANTITY) *
FROM L2
) nums
WHERE [DESCRIPTION] like 'COM%ASSY%' AND CITY = #pSite
AND FG_AVAILABLE > 0;
Essentially, what this does is, for every row in the base table, apply a bunch of rows to it. The number of rows added is equal to OPEN_QUANTITY, and the rows are constructed using cross-joined VALUES clauses.
The problem is that you fetch a row just after you open the cursor, but don't do anything with the fetched values. So you end up missing the first row. To correct that, reorganize your code this way:
-- first delete the other table
if exists(select ....)
begin
delete ...
end
-- then, declare variables, open the cursor, etc.
declare curCURSOR cursor for ...
declare #e int = 0
open curCURSOR
-- then start fetching. use the following pattern:
fetch from curCURSOR into #...
while ##FETCH_STATUS = 0
begin
-- do your thing:
while #e < #required_quantity
...
-- then, after you did your thing
-- and just before the end of the while ##fetch_status block,
-- fetch again
fetch from curCURSOR into #...
end
-- finally close, deallocate, etc.
close ...
deallocate ...
That takes care of missing the first row.
The reason of your second problem might be that you added a condition to the query that isn't in the cursor: PROMISE <= #pdate.
That is, there might be some rows with promise after #pdate that got inserted into the second table, but don't show when you query the first table with that condition.

after trigger update statement take long time

I created a trigger as below
alter trigger sale_Trigger_Update on sale
after update
as
begin
Declare #old_value varchar(50)
Declare #new_value varchar(50)
Declare #sale_id UNIQUEIDENTIFIER
DECLARE new_cur CURSOR FORWARD_ONLY READ_ONLY LOCAL FOR
SELECT saleid
FROM INSERTED
open new_cur
Fetch Next from new_cur into #sale_id
while ##FETCH_STATUS = 0
Begin
set #old_value = (select enddate from deleted where SaleID = #sale_id)
set #new_value = (select enddate from inserted where SaleID = #sale_id)
insert into zzz (old_value,new_value) values(#old_value,#new_value)
end
CLOSE new_cur
DEALLOCATE new_cur
end
Then I do an update statement as below
update sale
set enddate = null
Sale table contain only 2 rows
and the execution is continuing unlimited.
I tried
update sale
set enddate = null
where saleid = 10
same problem.
Then I forcefully stopped the execution. Then checked the sale table and zzz table. No changes happened.
I am sure there is some issue in cursor. Can somebody show some light on it.
****Edited****
Actually I need to check enddate in deleted is null and enddate in inserted is not null
open new_cur
Fetch Next from new_cur into #sale_id
while ##FETCH_STATUS = 0
Begin
set #old_value = (select enddate from deleted where SaleID = #sale_id)
set #new_value = (select enddate from inserted where SaleID = #sale_id)
if #old_value = null and #new_value != null
begin
SELECT approval.*,
(select diag.*
from diag diag
where approval.id =diag.id
FOR XML PATH('diag'), TYPE
),
(select ser.*
from ser ser
where approval.id =ser.id
FOR XML PATH('ser'), TYPE
)
FROM approval approval,
where approval.id = 1
and approval.saleid =#saleid
FOR XML PATH, ELEMENTS,
root('Head')
end if
end
CLOSE new_cur
DEALLOCATE new_cur
Regarding the cursor.
Could you replace your trigger with?
alter trigger sale_Trigger_Update on sale
after update
as
begin
insert into zzz (old_value,new_value)
select
--i.SalesID,
d.enddate,
i.enddate
from inserted i
inner join deleted d on
i.SaleID = d.SaleID
where
d.enddate is null and
i.enddate is not null
end

Update fails because Subquery returned more than 1 value

I Get the following error when i try to update my table although there's n't any sub query :
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
MY QUERY :
UPDATE t1
SET t1.modified = 2
FROM TransActions AS t1
INNER JOIN Ruser R
ON t1.USERID = r.USERID
WHERE r.dep_code = 54 and r.dep_year =2014
and YEAR(t1.checktime) =2016 and MONTH(t1.checktime) =1 and t1.modified = 0
The data selected like this :
USERID empNum
3090 25
3090 25
2074 464
According to the comments my update trigger :
after update
as
declare #userid int , #date date
if (select userid from inserted)<>(select userid from deleted )
raiserror ('YOU ARE NOT ALLOWED TO PERFORME THIS ACTION',10 , 1)
ELSE
begin
set nocount on;
set #userid = (select userid from inserted)
set #date = (select convert(date , checktime) from inserted)
exec calc_atten #date , #userid
end
Triggers are executed per statement, not per row, that's the source of your error.
Your trigger assumes that the inserted and deleted tables will only ever have one row, however that is simply wrong.
The number of rows in the inserted / deleted tables is the number of rows effected by the DML statement (update/insert/delete).
I don't know what the procedure calc_atten does, but you need to find a way to execute it's logic on a set level and not on scalar variables as it does now.
Your condition at the beginning of the trigger should be changed to fit a multi-row update.
One way to do it is this: (I could probably write it shorter and better if I would have known the table's structure)
IF EXISTS (
SELECT 1
FROM deleted d
INNER JOIN inserted i
ON d.[unique row identifier] = i.[unique row identifier]
WHERE i.userId <> d.UserId
)
*[unique row identifier] stands for any column or column combination that is unique per row in that table. If the unique row identifier contains the UserId column then this will not work properly.
Your query is ok. The problem is the trigger. inserted and deleted are tables (well, really views but that is irrelevant), so they can contain multiple rows.
Assuming that transactions has a primary key, you can check the update by doing
declare #userid int , #date date ;
if (exists (select 1
from inserted i
where not exists (select 1
from deleted d
where d.transactionid = i.transactionid and
d.userid <> i.userid
)
)
)
begin
raiserror ('Changing user ids is not permitted', 10 , 1);
end;
else begin
set nocount on;
declare icursor cursor for select userid, checktime from inserted;
open icursor;
fetch next from icursor into #userid, #date;
while not ##FETCH_STATUS = 0
begin
exec calc_atten #date, #userid
fetch next from icursor into #userid, #date;
end;
close icursor; deallocate icursor;
end;
Cursors are not my favorite SQL construct. But, if you need to loop through a table and call a stored procedure, then they are appropriate. If you can rewrite the code to be set-based, then you can get rid of the cursor.
Try using distinct like this:
UPDATE t1
SET t1.modified = 2
FROM TransActions AS t1
INNER JOIN (select distinct userid from Ruser
where r.dep_code = 54 and r.dep_year = 2014 ) R
ON t1.USERID = r.USERID
WHERE YEAR(t1.checktime) =2016 and MONTH(t1.checktime) =1 and t1.modified = 0
BTW - I don't see any subquery here, so its weird thats the error you get, I have a feeling the error doesn't occurs because of that part of the code.
You can use distinct to return unique userid's:
UPDATE TransActions
SET modified = 2
WHERE YEAR(checktime) = 2016
AND MONTH(checktime = 1
AND modified = 0
AND userid IN ( SELECT DISTINCT userid FROM Ruser r WHERE r.dep_code = 54 and r.dep_year =2014 );

SQL: Insert new records from 1 table to another

I have two tables with students (using Microsoft SQL Server 2008 R2 Standard edition). I Need to write a procedure, so that if 1st table has new students, the second one gets updated as well
this doesnt work and I dont know why:
CREATE PROCEDURE [dbo].[CHECK_NEW]
AS
begin transaction
declare #tempId int
declare #tempName varchar
DECLARE c1 CURSOR FOR
SELECT kId, kName
FROM table1
OPEN c1
FETCH NEXT FROM c1
INTO #tempId, #tempName
WHILE ##FETCH_STATUS = 0
BEGIN
if (SELECT sId FROM table2) NOT IN(#tempId)
insert into table(sId, name) values(#tempId, #tempName)
END
commit
Thanks in advance
Try like this....
CREATE PROCEDURE [dbo].[CHECK_NEW]
AS
Begin Try
begin transaction
Insert into Table2(ulid,Id,Name)
Select newid() as ulid, Id,name from ( Select Row_Number() over(Partition by a.id order by a.id) as row, a.Id,a.name from Table1 a where
not exists(Select * from Table2b where a.Id=b.Id)) t where row =1
Commit
End Try
Begin Catch
RollBack
End Catch