Cursor is not updating my column - sql-server-2008-r2

am using cursor to update my null column but it is not updating
Declare #Itemcode as varchar(30)
Declare #SLV as varchar(20)
declare cursor1 cursor for
Select Itemcode ,U_SLV from oitm_Clone where sapitem is null and u_slv is null
open cursor1
fetch next FROM cursor1 INTO #Itemcode ,#SLV
WHILE ##FETCH_STATUS = 0
begin
if #SLV is null
begin
declare #sql1 as varchar(max)
set #sql1 = 'Update [dbo].oitm_Clone set sapitem ='''+ #Itemcode +''' where ItemCode='''+ #Itemcode +''' and U_SLV ='''+ #SLV +''''
print #sql1
execute (#sql1)
end
FETCH NEXT FROM cursor1 INTO #Itemcode ,#SLV
end
CLOSE cursor1
DEALLOCATE cursor1

I think you don't need a cursor to do this update. Try this simple update which has the same logic of your cursor with much improved performance.
Update [dbo].oitm_Clone
Set sapitem = itemcode
Where sapitem is null and u_slv is null

try to use this
WHILE ##FETCH_STATUS <> -1
instead of
WHILE ##FETCH_STATUS = 0
hope it will help you
regards

Related

Trigger after update: How to execute query for every row updated

I wrote trigger to execute a query after the update of the column (retard) in my table, but sometimes there are many rows updated how to solve that?
CREATE OR ALTER TRIGGER notifRetard
ON Taches
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #value INT
IF UPDATE(retard)
-- How to make this for every row updated???
SELECT
#value = inserted.retard
FROM
inserted;
IF #value = 1
-- run SQL query
END
The solution if someone else need it is to use CURSOR.
CREATE or alter TRIGGER notifRetard
ON Taches
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF UPDATE(retard)
begin
DECLARE #RefTache varchar(50),#RefPhase numeric(4,0),#IDprojet varchar(50),#IDressource varchar(50) #retard bit;
DECLARE TrigTempUpdate_Cursor CURSOR FOR
SELECt RefTache,RefPhase,IDprojet,IDressource,retard
FROM
inserted;
begin
OPEN TrigTempUpdate_Cursor;
FETCH NEXT FROM TrigTempUpdate_Cursor INTO #RefTache, #RefPhase,#IDprojet,#IDressource,#retard
WHILE ##FETCH_STATUS = 0
BEGIN
if #retard=1
--DO QUERY HERE
FETCH NEXT FROM TrigTempUpdate_Cursor INTO #RefTache, #RefPhase,#IDprojet,#IDressource,#retard
END;
end;
CLOSE TrigTempUpdate_Cursor;
DEALLOCATE TrigTempUpdate_Cursor;
end;
end;

Stored Procedure returns int value rather than result set in Entity Framework

I have this stored procedure
create procedure [dbo].[sp_GetAllLesiureActivitiesNew]
(#ActivityLeaderID int = null)
as
begin
declare #TempLeisureActivites TABLE
([ActivityPlan_ID] [int] NULL,
[ActivityRecurrence_ID] [int] NULL,
[ActivityName] [nvarchar](50) NULL,
[Activity] [nvarchar](max) NULL,
[IsResponse] [bit] NULL,
[IsLOI] [bit] NULL,
[clientcount] [int] NULL,
[Location] [nvarchar](max) NULL,
[StartDateTime] [datetime] NULL,
[EndDatetime] [datetime] NULL)
insert into #TempLeisureActivites
select distinct
ap.ActivityPlan_ID, ap.ActivityRecurrence_ID,
ap.ActivityName, orgla.Activity, orgla.IsResponse,
orgla.IsLOI,
(select count(distinct cc.ID ) from Client cc join Activity_Clients acc on cc.ID=acc.Client_ID join ActivityPlan app on acc.ActivityRecurrence_ID=app.ActivityRecurrence_ID where app.ActivityRecurrence_ID=ap.ActivityRecurrence_ID and cc.Status=1) as clientcount,l.Location,ap.StartDateTime,ap.EndDatetime
from ActivityPlan ap
left outer join Location l on ap.ActivityLocationID =l.ID left join Activity_Clients ac on ap.ActivityRecurrence_ID=ac.ActivityRecurrence_ID
left outer join Client c on ac.Client_ID=c.ID
left outer join LeisureActivity orgla on ap.ActivityType=orgla.ID
where ap.ActivityLeaderID in(0,#ActivityLeaderID) and c.[Status]=1
if(#ActivityLeaderID is not null and #ActivityLeaderID>0)
begin
declare #Activities nvarchar(max)
declare #Locations nvarchar(max)
declare #CISelection nvarchar(50)
declare #IsAllLocs bit
declare #TempRecurID int
declare #TempAPID int
--BEGIN TRANSACTION T1
--BEGIN TRY
declare #RecurIDsCursor CURSOR
declare #RecurIDsRowsCount int
--print 'Before cursor logic starts'
set #RecurIDsCursor=CURSOR STATIC FOR
select ActivityPlan_ID,ActivityRecurrence_ID from #TempLeisureActivites
OPEN #RecurIDsCursor
set #RecurIDsRowsCount=(SELECT ##CURSOR_ROWS)
--print 'cursor rows count:'+cast(#RecurIDsRowsCount as nvarchar)
FETCH NEXT
FROM #RecurIDsCursor INTO #TempAPID,#TempRecurID
WHILE #RecurIDsRowsCount>0
BEGIN
--select #Activities=NULL,#Locations=NULL
--print 'looping started...'
select #Activities='',#Locations=''
select #CISelection=NULL,#IsAllLocs=0
--print 'Activity Plan ID'+cast(#TempAPID as nvarchar)+',Recur ID:'+ cast(#TempRecurID as nvarchar)
select #CISelection=[CommonInterestsSelection] from [dbo].[ActivityPlan] where ActivityPlan_ID=#TempAPID and [ActivityRecurrence_ID]=#TempRecurID
--print 'CI Selection:'+#CISelection
if(#CISelection='Specific')
begin
select #Activities+=(
case when la.Activity is not null then
ISNULL(la.Activity,'')+',' end) from [dbo].[ActivityPlan_Filters] apf
left outer join [dbo].[LeisureActivity] la on la.ID=apf.FilterID
where [ActivityRecurrence_ID]=#TempRecurID and apf.FilterType='Common_Interests'
if(LEN(#Activities)>0)
begin
select #Activities=LEFT(#Activities, LEN(#Activities) - 1)
end
end
else if(#CISelection='Top')
begin
select #Activities=[CommonInterestValue] from [dbo].[ActivityPlan] where ActivityPlan_ID=#TempAPID and [ActivityRecurrence_ID]=#TempRecurID
end
else if(#CISelection='NA')
begin
select #Activities='ALL'
end
--print 'Activities:'+#Activities
select #IsAllLocs=[IsAllLocations] from [dbo].[ActivityPlan] where ActivityPlan_ID=#TempAPID and [ActivityRecurrence_ID]=#TempRecurID
if(#IsAllLocs=1)
begin
select #Locations='ALL'
end
else if(#IsAllLocs=0)
begin
select #Locations+=(
case when loc.Location is not null then
ISNULL(loc.Location,'')+',' end) from [dbo].[ActivityPlan_Filters] apf
left outer join [dbo].[Location] loc on loc.ID=apf.FilterID
where [ActivityRecurrence_ID]=#TempRecurID and apf.FilterType='Locations'
if(LEN(#Locations)>0)
begin
select #Locations=LEFT(#Locations, LEN(#Locations) - 1)
end
end
--print 'Locations:'+#Locations
--print 'before updation'
update #TempLeisureActivites
set Activity=#Activities,Location=#Locations
where ActivityPlan_ID=#TempAPID and ActivityRecurrence_ID=#TempRecurID
--print 'after updation'
FETCH NEXT
FROM #RecurIDsCursor INTO #TempAPID,#TempRecurID
SET #RecurIDsRowsCount=#RecurIDsRowsCount-1
END
CLOSE #RecurIDsCursor
DEALLOCATE #RecurIDsCursor
end
select * from #TempLeisureActivites
end
It returns Result set while executing in SQL Server Management Studio but in Asp.net MVC using Entity Framework it returns an integer instead of Result Set like below.
public virtual int sp_GetAllLesiureActivitiesNew(Nullable<int> activityLeaderID)
{
var activityLeaderIDParameter = activityLeaderID.HasValue ?
new ObjectParameter("ActivityLeaderID", activityLeaderID) :
new ObjectParameter("ActivityLeaderID", typeof(int));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("sp_GetAllLesiureActivitiesNew", activityLeaderIDParameter);
}
I found one article but it does not help me(Stored procedure returns int instead of result set).
How Could i solve my problem?
The ExecuteFunction() Method returns the number of rows, which were affected as an integer.
If you want it to return ObjectResult<YourEntityType> instead.
Change it to:
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<YourEntityType>("sp_GetAllLesiureActivitiesNew", activityLeaderIDParameter);
But I think that the better way of doing it is now:
Dbcontext.Database.SqlQuery<YourEntityType>("storedProcedureName",params);
Here's an Article that shows an example.
You can run the "SQL Server Profiler" tool, where you can track the SP and how the EF ran it, so you can see if the SP returns an error.
I wrote about it here: https://stackoverflow.com/a/72162214/3374391

rollback a nested transaction in trigger

I have a following situation.
I have a table with trigger for insert.
When I insert a row in it, from this trigger I want to insert some rows into a second table.
For each of these rows I want to do it in it's own transaction in case something go wrong.
I want to have original row in first table and all rows (these withous errors) in the second.
A little code to reproduce:
create table test(id int primary key identity(1,1),name nvarchar(10))
create table test2(id int primary key identity(1,1),
state char(1) check (state in ('a','b')))
go
create trigger test_trigger on test for insert
as
begin
declare #char char(1)
declare curs cursor for (
select 'a'
union
select 'c'
union
select 'b')
open curs
fetch next from curs into #char
while ##FETCH_STATUS = 0
begin
begin try
begin transaction
insert into test2(state)
select #char
commit
end try
begin catch
print 'catch block'
rollback
end catch
fetch next from curs into #char
end
close curs
deallocate curs
end
go
insert into test(name) values('test')
select * from test
select * from test2
go
drop table test
drop table test2
So for the sample data from this snippet, I want to have a row with 'test' in test table and two rows in the test2 table ('a' and 'b').
How can I write a code for that?
Looks like finally I got it to work.
Corrected trigger code:
create trigger test_trigger on test for insert
as
begin
declare #char char(1)
set xact_abort off
declare curs cursor for (
select 'a'
union
select 'c'
union
select 'b')
open curs
fetch next from curs into #char
while ##FETCH_STATUS = 0
begin
save transaction t
begin try
insert into test2(state)
select #char
end try
begin catch
print 'catch block'
rollback transaction t
end catch
fetch next from curs into #char
end
close curs
deallocate curs
end

TSQL Cursor Infinite Loop without TOP xxx in SELECT Statement

I have a curious problem with an infinite loop in a TSQL cursor. The cursor loops infinitely when I do not add TOP 300 to the defining select statement of the cursor. The following is an example of the code: Any assistance to this issue is much appreciated.
DECLARE #Done BIT
SET #Done = 0
DECLARE cursOut CURSOR LOCAL FAST_FORWARD
FOR
SELECT
--TOP 300
FirstName FirstName
,LastName LastName
,MiddleName MiddleName
,Email Email
,Address1 Address1
,Address2 Address2
,City City
,[State] [State]
FROM StagedUsers
OPEN cursOut;
WHILE (#Done = 0)
BEGIN
--Fetch next row
FETCH NEXT
FROM cursOut
INTO ,#v_FirstName
,#v_LastName
,#v_MiddleName
,#v_Email
,#v_Address1
,#v_Address2
,#v_City
,#v_State
IF (##FETCH_STATUS <> 0)
BEGIN
SET #Done = 1
BREAK
END
--if #batch = 0
BEGIN TRANSACTION
--process statements
--updates or insert statements
--Commit transaction
COMMIT TRANSACTION
--End While
END
--CleanUp:
CLOSE cursOut
DEALLOCATE cursOut
Thanks,
Renegrin
First I think you do not need transaction here, I presume it is only one statement executed, so remove transaction from code.
Second do it without #done flag, it is confusing (it is probably not problem here).
DECLARE #v_FirstName VARCHAR(500),#v_LastName VARCHAR(500),#v_MiddleName VARCHAR(500),#v_Email VARCHAR(500),#v_Address1 VARCHAR(500),#v_Address2 VARCHAR(500),#v_City VARCHAR(500),#v_State VARCHAR(500)
DECLARE cursOut CURSOR FAST_FORWARD FOR
SELECT FirstName FirstName,LastName LastName,MiddleName MiddleName,Email Email,Address1 Address1,Address2 Address2,City City,[State] [State]
FROM StagedUsers
OPEN cursOut;
FETCH NEXT FROM cursOut INTO #v_FirstName,#v_LastName,#v_MiddleName,#v_Email,#v_Address1,#v_Address2,#v_City,#v_State
declare #i int = 1
WHILE ##FETCH_STATUS = 0
BEGIN
print cast(#i as varchar(10))
--> statement here
FETCH NEXT FROM cursOut INTO #v_FirstName,#v_LastName,#v_MiddleName,#v_Email,#v_Address1,#v_Address2,#v_City,#v_State
set #i = #i + 1
END
CLOSE cursOut
DEALLOCATE cursOut
Do you want to update current row where cursor point? If so, there is way to do it.
Is there any indexes on table? Can you post an update query?

T-SQL How To Count Of Records For Each Column

I have a table with over 120 columns and need to determine which column is used the least. I tried using sql queries to do this, but found T-SQL a bit simpler.
I tried the following but my count comes out as 0 for every column.
Declare data1 Cursor for select column_name
from information_schema.columns
where table_name = 'repository'
Declare #mField nvarchar(255)
Declare #count int
Open data1;
fetch next from data1 into #mField;
set #count = -1;
while ##fetch_status = 0
begin
select #count = count(#mField)
from repository where tablereference =
'central' and ( #mField!= null )
print #mField+' ' ;
print #count;
Fetch next from data1 into #mField;
end
close data1;
deallocate data1;
You can't count values like this because you are only testing if #mField is NULL. The column name isn't substituted.
COUNT ignores NULLs anyway so if you want to count non-null values, do this:
DECLARE #sql varchar(4000)
SET #sql = 'SELECT COUNT(*) AS Total '
SELECT #sql = #sql + ', COUNT(' + QUOTENAME(column_name) + ') AS ' + QUOTENAME(column_name)
from information_schema.columns
where table_name = 'repository'
SET #sql = #sql + ' FROM repository'
EXEC (#sql)
This queries the table once for all columns
You need to use some dynamic sql in the middle to acheive your aim here.
Declare data1 Cursor for select column_name
from information_schema.columns
where table_name = 'repository'
Declare #mField nvarchar(255)
Open data1;
fetch next from data1 into #mField;
while ##fetch_status = 0
begin
exec ('
declare #count int
select #count = count([' + #mField + '])
from repository where tablereference =
''central'' and ( [' + #mField + '] is not null)
if #count < 10
begin
print ''' + #mField + ' '' ;
print #count;
end
')
Fetch next from data1 into #mField;
end
close data1;
deallocate data1;
Your count(#mField) is a count of the litteral value that happens to be in #mField, its not resolving the field name into COUNT(fldBlah), you would need to use dynamic SQL for that.
Declare data1 Cursor FAST_FORWARD for select column_name
from information_schema.columns where table_name = 'repository'
Declare #mField nvarchar(255)
Declare #SQL varchar(1024)
Declare #results table (col_name varchar(128), non_nulls int)
Open data1;
fetch next from data1 into #mField;
while (##FETCH_STATUS = 0) begin
set #SQL = 'SELECT ''' + #mField + ''', count(' + #mField + ') from repository where tablereference = ''central'''
insert #results
exec(#SQL)
Fetch next from data1 into #mField;
end
close data1;
deallocate data1;
select * from #results
For an output like;
col_name non_nulls
[tablereference] 5
[another_col] 1
Where there are 5 non-null values in column tablereference etc
You need to use IS NOT NULL instead of != NULL