How to use WITH table AS result within cursor loop to run stored procedure - tsql

How to get result in WITH table AS into CURSOR loop? I have previously asked about how to get recursive results from my table
How to read all records recursively and show by level depth TSQL
;with C as
(
definition ...
)
I have created CURSOR loop where I want to run specific stored procedure for all results in table
declare #id int, #parent int
declare cur cursor local fast_forward
for
select id, parent from C
open cur
fetch next from cur into #id, #parent
while ##fetch_status = 0
begin
exec storedProcedure #id=#id, #parent=#parent
fetch next from cur into #id, #parent
end
close cur
deallocate cur
Problem is that CURSOR doesnt know table from WITH AS result.
Invalid object name 'C'.

You can create a temp table or a table variable to hold the rows returned by you CTE query and then you use that table as the source for your cursor.
declare #T table
(
id int,
parent int
)
;with C as
(
select 1 as id, 2 as parent
)
insert into #T
select id, parent
from C
declare cur cursor for select id, parent from #T

Related

Select / Delete of Three self referencing many to many relationships SQL Query

I have a table ProjectLayerContent designed as following:
ProjectLayerContentID [INT]
ProjectLayerContentName [NVARCHAR(200)]
ProjectLayerContentParentID [INT]
ScopeIsProjectLayerContent [BIT]
ScopeIsProjectLayerContentID [INT]
DataTypeIsContentOfContent [BIT]
ContentOfContentID [INT]
The project layer content might have a parent, and might not, also the same for the children.
The project layer content scope might include another project layer content.
The project layer content data type might be a type of another content.
What I am trying to do is in the delete process, I want to show a list includes the count of what's is going to be deleted if you will delete this project layer content.
Pretty much this is what I got into, but I know those results isn't right
DECLARE #ProjectLayerContentID INT = 1;
DECLARE #resTable TABLE (
ProjectLayerContentIDP int,
ProjLContentType nvarchar(100));
DECLARE #ProjectLayerContentIDRecursionParam int;
DECLARE #Type NVARCHAR(MAX);
DECLARE #resultString NVARCHAR(MAX) = '';
-- SELECT Project layer content children with recursion
-- SELECT the count of the result from the recursion of the children of the project layer content id passed with the sql parameter in the query
DECLARE ProjectLayerContentChildren_Cursor CURSOR FOR
SELECT ProjectLayerContentID, 'Child(ren)'
FROM ProjectLayerContent
WHERE ProjectLayerContentParentID = #ProjectLayerContentID
OPEN ProjectLayerContentChildren_Cursor
FETCH NEXT FROM ProjectLayerContentChildren_Cursor INTO #ProjectLayerContentIDRecursionParam, #Type
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #resTable SELECT #ProjectLayerContentIDRecursionParam, #Type;
;WITH ProjectLayerContentTotalScopeChildren AS(
SELECT ProjectLayerContentID,CAST('Content(s) of Child(ren)' as varchar(259)) AS ProjLContentType
FROM ProjectLayerContent
WHERE ContentOfContentID = #ProjectLayerContentIDRecursionParam
UNION ALL
SELECT Scopechildren.ProjectLayerContentID, CAST('Children Content Of Content of Child(ren)' as varchar(259)) AS ProjLContentType
FROM ProjectLayerContent Scopechildren INNER JOIN
ProjectLayerContentTotalScopeChildren projLContents ON Scopechildren.ContentOfContentID = projLContents.ProjectLayerContentID
UNION ALL
SELECT children.ProjectLayerContentID, CAST('Child(ren) of Child(ren) of Child(ren)' as varchar(259)) AS ProjLContentType
FROM ProjectLayerContent children INNER JOIN
ProjectLayerContentTotalScopeChildren projLContents ON children.ProjectLayerContentParentID = projLContents.ProjectLayerContentID
)
INSERT INTO #resTable SELECT ProjectLayerContentID, ProjLContentType from ProjectLayerContentTotalScopeChildren
FETCH NEXT FROM ProjectLayerContentChildren_Cursor INTO #ProjectLayerContentIDRecursionParam, #Type
END
-- close the cursor
CLOSE ProjectLayerContentChildren_Cursor
DEALLOCATE ProjectLayerContentChildren_Cursor
-----------------------------------------------------------------------------------------------------------
-- SELECT Project layer content Scope children with recursion
DECLARE ProjectLayerContent_Cursor CURSOR FOR
SELECT ProjectLayerContentID, 'Content Of Content'
FROM ProjectLayerContent
WHERE ContentOfContentID = #ProjectLayerContentID
OPEN ProjectLayerContent_Cursor
FETCH NEXT FROM ProjectLayerContent_Cursor INTO #ProjectLayerContentIDRecursionParam, #Type
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #resTable SELECT #ProjectLayerContentIDRecursionParam, #Type;
;WITH ProjectLayerContentTotalScopeContentOfContent AS(
SELECT ProjectLayerContentID,CAST('Children Content Of Content' as varchar(259)) AS ProjLContentType
FROM ProjectLayerContent
WHERE ContentOfContentID = #ProjectLayerContentIDRecursionParam
UNION ALL
SELECT Scopechildren.ProjectLayerContentID, CAST('Children Content Of Content of Children Content Of Content' as varchar(259)) AS ProjLContentType
FROM ProjectLayerContent Scopechildren INNER JOIN
ProjectLayerContentTotalScopeContentOfContent projLContents ON Scopechildren.ContentOfContentID = projLContents.ProjectLayerContentID
UNION ALL
SELECT children.ProjectLayerContentID, CAST('Children of Children Content Of Content' as varchar(259)) AS ProjLContentType
FROM ProjectLayerContent children INNER JOIN
ProjectLayerContentTotalScopeContentOfContent projLContents ON children.ProjectLayerContentParentID = projLContents.ProjectLayerContentID
)
INSERT INTO #resTable SELECT ProjectLayerContentID, ProjLContentType from ProjectLayerContentTotalScopeContentOfContent
FETCH NEXT FROM ProjectLayerContent_Cursor INTO #ProjectLayerContentIDRecursionParam, #Type
END
-- close the cursor
CLOSE ProjectLayerContent_Cursor
DEALLOCATE ProjectLayerContent_Cursor
--select the result to present it.
SELECT * FROM #resTable;
Thanks in advance.
I found that this solution to get the needed functionality as needed.
I created the stored procedure to get all children for this project layer first, and created a table to add the result in. Because one of the first error to apply this solution was INSERT INTO EXEC wouldn't work if you have a chain of stored procedures calling each other. It only works for the first time, but the other times will show an error.
DECLARE #ProjectLayerContentID INT = 1;
DECLARE #ProjectLayerContentIDRecursionParam INT;
DECLARE #Type NVARCHAR(MAX);
DECLARE #resultString NVARCHAR(MAX) = '';
-------Create temp table to insert the results into it
CREATE TABLE #ResTable(
ProjectLayerContentIDP int,
ProjLContentType nvarchar(100));
Then I created a cursor for the select statement of all children who have that relationship of being child of this project layer, or being content of it.
-- SELECT Project layer content children with recursion
-- SELECT the count of the result from the recursion of the children of the project layer content id passed with the sql parameter in the query
DECLARE ProjectLayerContent_Cursor CURSOR FOR
SELECT ProjectLayerContentID, CASE WHEN ProjectLayerContentParentID = #ProjectLayerContentID THEN 'Child(ren)' ELSE 'Content(s) of Content(s)' END
FROM ProjectLayerContent
WHERE ProjectLayerContentParentID = #ProjectLayerContentID
OR ContentOfContentID = #ProjectLayerContentID
OPEN ProjectLayerContent_Cursor
FETCH NEXT FROM ProjectLayerContent_Cursor INTO #ProjectLayerContentIDRecursionParam, #Type
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #ResTable SELECT #ProjectLayerContentIDRecursionParam, #Type;
Then I will call the recursion stored procedure to get each of the current project layer content chlidren, and content of the children.
Exec DeleteCheck_ProjectLayerContentChildren #ProjectLayerContentIDRecursionParam;
FETCH NEXT FROM ProjectLayerContent_Cursor INTO #ProjectLayerContentIDRecursionParam, #Type
END
-- close the cursor
CLOSE ProjectLayerContent_Cursor
DEALLOCATE ProjectLayerContent_Cursor
At this part here, we will select the results, and then drop the temp table from the database server.
--select the result to present it.
SELECT #resultString = #resultString + '<br/><u>' + CONVERT(NVARCHAR(MAX), Count(ProjectLayerContentIDP)) + '</u> ' + ProjLContentType
FROM #ResTable
GROUP BY ProjLContentType;
SELECT #resultString;
DROP TABLE #ResTable
Here is the recursion stored procedure that we called already in the previous query
CREATE PROCEDURE [dbo].[DeleteCheck_ProjectLayerContentChildren]
#ProjectLayerContentID INT
AS
BEGIN
DECLARE #ProjectLayerContentIDRecursionParam INT;
DECLARE #Type NVARCHAR(MAX);
-- SELECT Project layer content children with recursion
-- SELECT the count of the result from the recursion of the children of the project layer content id passed with the sql parameter in the query.
Notice here we added Local into the deceleration of the cursor, because it will show an error of creating the cursor with the same name
DECLARE ProjectLayerContentChildren_Cursor CURSOR LOCAL FOR
SELECT ProjectLayerContentID, CASE WHEN ProjectLayerContentParentID = #ProjectLayerContentID THEN 'Child(ren) of Child(ren)' ELSE 'Child(ren) Content(s) of Content(s)' END
FROM ProjectLayerContent
WHERE ProjectLayerContentParentID = #ProjectLayerContentID
OR ContentOfContentID = #ProjectLayerContentID
Pretty much most of this query is the same, as the previous one, but this is for the project layer content children of children counts, and we don't create the result table again because it will be already created, then we just add the result, and we have the needed functionality, and you can apply it to more than two or three self relationships.
OPEN ProjectLayerContentChildren_Cursor
FETCH NEXT FROM ProjectLayerContentChildren_Cursor INTO #ProjectLayerContentIDRecursionParam, #Type
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #ResTable SELECT #ProjectLayerContentIDRecursionParam, #Type;
Exec DeleteCheck_ProjectLayerContentChildren #ProjectLayerContentIDRecursionParam
FETCH NEXT FROM ProjectLayerContentChildren_Cursor INTO #ProjectLayerContentIDRecursionParam, #Type
END
-- close the cursor
CLOSE ProjectLayerContentChildren_Cursor
DEALLOCATE ProjectLayerContentChildren_Cursor
END

How to apply Nonclustered Index on all tables at once

I have 64 tables in sql server i want to apply nonclustered index in all the tables.Is it possible to apply nonclustered index in all the tables at once using query.Please le me know if there is any way we can apply index using single query
You can do it with cursor and dynamic query:
DECLARE #t NVARCHAR(MAX)
DECLARE #s NVARCHAR(MAX)
DECLARE cur CURSOR FAST_FORWARD READ_ONLY
FOR
SELECT name
FROM sys.tables
OPEN cur
FETCH NEXT FROM cur INTO #t
WHILE ##FETCH_STATUS = 0
BEGIN
SET #s = 'CREATE NONCLUSTERED INDEX IDX_' + #t + ' ON dbo.' + #t + '(id)'
EXEC (#s)
FETCH NEXT FROM cur INTO #t
END
CLOSE cur
DEALLOCATE cur
Of course you will need to adjust this to appropriate columns on which you are going to add indexes.

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

Union select statements within the while loop T-SQL

I'm trying to use cursors to dynamically produce a result set. following is the code
DECLARE # MilestoneName VARCHAR(100),
#MilestoneSts VARCHAR(100),
#ProjectPre VARCHAR(10),
#ProjectID VARCHAR(10),
#Center VARCHAR(20),
#CenterPre VARCHAR(20),
#Source VARCHAR(20),
#Actual INT;
SET #MilestoneName = null;
SET #MilestoneSts = null;
SET #ProjectPre = null;
SET #CenterPre = null;
DECLARE s_cursor CURSOR FOR
SELECT ProjectID, Center, Source, Actual
FROM #MILESTONE
OPEN s_cursor
FETCH NEXT FROM s_cursor INTO #ProjectID, #Center, #Source, #Actual
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT ##FETCH_STATUS sts, #ProjectID PID, #Center Center, #Source Source, #Actual Actual
FETCH NEXT FROM s_cursor INTO #ProjectID, #Center, #Source, #Actual
END
CLOSE s_cursor
DEALLOCATE s_cursor
However using that I'm able to produce 79 results of single rows but I want to union all those rows into one result.. any possible solution will be highly appreciated..
just checking, why are you using a cursor for this?
This sproc could be replaced by just saying
SELECT ProjectID, Center, Source, Actual
FROM #MILESTONE
But maybe I'm missing somehting here?
If there's logic you left out in your code look at this post: Multi-statement Table Valued Function vs Inline Table Valued Function
GJ

Loop in T-SQL, how get field value

In an SQL Server 2005 database, I have a stored procedure. I get some date in put them in a temp table. I'd like loop in this temp table and depending of the value of some fields change the value of others and make some check. I have to do this for each row.
How can I do this ?
thanks,
UPDATE1
BEGIN
SET NOCOUNT ON
--Create temp table
CREATE TABLE #MyTempTable(
id int IDENTITY(1, 1),
PriceMax int,
PriceMin int
)
-- Insert in temp table
INSERT INTO #tmpReconciliation (PriceMax, PriceMin)
SELECT PriceMax = PriceMaxProduct,
PriceMin = PriceMinProduct
FROM Products
DECLARE #RowNum int
SELECT #RowNum = Count(*) From #MyTempTable
WHILE #RowNum > 0
BEGIN
if(....)
PriceMin = 0
....
END
--Drop temp table
DROP TABLE #MyTempTable
END
I read MSDN documentation for WHILE loop and CURSOR.
For example, let's imagine your temp table is named Employee :
DECLARE #Emp_id int
DECLARE Employee_Cursor CURSOR FOR
SELECT EmployeeID
FROM Employee;
OPEN Employee_Cursor;
FETCH NEXT FROM Employee_Cursor INTO #Emp_id;
WHILE ##FETCH_STATUS = 0
BEGIN
-- Here your actions
PRINT #Emp_id
FETCH NEXT FROM Employee_Cursor INTO #Emp_id;
END;
CLOSE Employee_Cursor;
DEALLOCATE Employee_Cursor;
GO
Here I decided to print EmployeeId, but everything is possible.
Tell us what are your checks, and what your temp table looks like if you need more help.
Can't you just use a cursor and inside the cursor run an update statement??
Cursors: http://www.jackdonnell.com/articles/SQL_CURSOR.htm