Loop over SQL stored procedure - sql-server-2008

I have a stored procedure In which insert query fire on two table.
masters_table,child_table as you see here #Value1,#Value2,#Value3,#Value4 having parameter. I have written insert statement for each block, can I make use loop here to avoid multiple insert write for each block, suppose I have nth value then i have to write nth time block wise insert query, any better way to achieve this task
Create proc sp_insert_master_child
(
#Details_Data custom_tb READONLY,
#Value1 nvarchar(500),
#Value2 nvarchar(500),
#Value3 nvarchar(500),
#Value4 nvarchar(500),
#Value5 nvarchar(500),
#Value6 nvarchar(500),
#Value7 nvarchar(500)
)
as begin
declare #id bigint
------- block 1
if #Value1 is not null
begin
insert into masters_table (col1,col2,col3))
select Substring(#Value1, 1,Charindex(',', #Value1)-1) as col_value_1,
Substring(#Value1, Charindex(',', #Value1)+1, LEN(#Value1)) as col_value_2
select #id = ##IDENTITY
insert into child_table (col1,col2,col3)
SELECT #id,col_val_2,col_val_3 FROM #Details_Data WHERE blockType='blk_1';
end
------ block 2
if #Value2 is not null
begin
insert into masters_table (col1,col2,col3))
select Substring(#Value2, 1,Charindex(',', #Value2)-1) as col_value_1,
Substring(#Value2, Charindex(',', #Value2)+1, LEN(#Value2)) as col_value_2
select #id = ##IDENTITY
insert into child_table (col1,col2,col3)
SELECT #id,col_val_2,col_val_3 FROM #Details_Data WHERE blockType='blk_2';
end
------ block 3
if #Value3 is not null
begin
insert into masters_table (col1,col2,col3))
select Substring(#Value3, 1,Charindex(',', #Value3)-1) as col_value_1,
Substring(#Value3, Charindex(',', #Value2)+1, LEN(#Value3)) as col_value_2
select #id = ##IDENTITY
insert into child_table (col1,col2,col3)
SELECT #id,col_val_2,col_val_3 FROM #Details_Data WHERE blockType='blk_3';
end
------ block 4
.......
------ block 5
.......

You can insert all parameters into a table .Use while loop and read one by one row (parameter) from table .
Ex:
declare #x int
set #x= 1
declare #tmp table ( val int )
while (#x < noofrows)
begin
***********
Use Top #x value to get row(parameter in your case) from table
perform your operation
*************
increment x(set #X=#x+1)
end

Related

How to set data to a variable from temporary table?

I have declared a temporary table
DECLARE #Table Table
(
ID INT IDENTITY(1,1),
TableColumn VARCHAR(MAX)
)
DECLARE #Temp VARCHAR(MAX)
SET #Temp='SELECT * FROM '+'#Table'+''
SELECT #Temp
EXEC (#Temp)
I want to set all data of #Table to a variable #Temp. The above I tried practice is correct? Presently it shows some error.
Msg 1087, Level 15, State 2, Line 1
Must declare the table variable "#Table".
I tried in the above methode then it shows error like
Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'AS'.
Msg 1087, Level 15, State 2, Line 9
Must declare the table variable "#Table". Msg 139, Level 15, State 1,
Line 0
Cannot assign a default value to a local variable.
Msg 137, Level 15, State 2, Line 17
Must declare the scalar variable "#Temp".
This is to show the difference between a table variable and a temp table. You can't do what you are trying to do. Also, #temp is just a variable to contain the SQL you want to execute. If you want the results in another variable, another will have to be declared.
DECLARE #Table TABLE (
ID INT IDENTITY(1, 1)
,TableColumn VARCHAR(MAX)
)
INSERT INTO #Table (TableColumn)
VALUES ('testing 1,2,3')
SELECT *
FROM #table --with table variables, you can only select in the scope
DECLARE #Temp VARCHAR(MAX)
SET #Temp = 'SELECT * FROM #Table'
BEGIN TRY
--SELECT #Temp
EXEC (#Temp) --fails, because #table is not in scope
END TRY
BEGIN CATCH
SELECT 'Table variable dynamic execution failed'
END CATCH
GO
CREATE TABLE #table (
ID INT IDENTITY(1, 1)
,TableColumn VARCHAR(MAX)
)
INSERT INTO #Table (TableColumn)
VALUES ('testing 1,2,3')
DECLARE #Temp VARCHAR(MAX)
SET #Temp = 'SELECT * FROM #Table' --you can select out of a temp table with dynamic sql, because it will remain in scope for called procedures
--SELECT #Temp
EXEC (#Temp)
DROP TABLE #table
EXEC() creates new context, variables are not visible there so you need to pass them as argument. But temp table and normal tables are visible. This is why you get
Must declare the table variable "#Table".
If you can change temp variables to temp tables.
SqlFiddleDemo
CREATE TABLE #Table
( ID INT IDENTITY(1,1),
TableColumn VARCHAR(MAX));
INSERT INTO #Table
VALUES ('aaa'), ('bbb');
DECLARE #Temp NVARCHAR(MAX) ='SELECT * FROM <placeholder>';
SET #Temp = REPLACE(#Temp, '<placeholder>', '#Table');
-- SELECT #Temp;
EXEC [dbo].[sp_executesql]
#Temp;
If you want to query temp variables you need to create table type and pass to dynamic sql as argument like:
Demo
CREATE TYPE MyTable AS TABLE
(
ID INT IDENTITY(1,1),
TableColumn VARCHAR(MAX)
);
DECLARE #Table AS MyTable;
INSERT INTO #Table
VALUES ('aaa'), ('bbb');
DECLARE #Temp NVARCHAR(MAX) ='SELECT * FROM '+'#Table'+'';
-- SELECT #Temp;
EXEC [dbo].[sp_executesql]
#Temp
,N'#Table MyTable READONLY'
,#Table;

count number of hierarchical childrens in sql

I have a table that stores parent and left child and right child information. How do i count number of children belongs that parent?
for example my table structure is:
parent left right
--------------------
1 2 3
3 4 5
4 8 9
5 10 11
2 6 7
9 12 null
How do I count number of sub nodes for any parent. For example 4 contains following hierarchical child nodes - 8,9,12 so number of children are 3.
3 contains following sub nodes -> 4,5,10,11,8,9,12 so total number of children 7.
How do I achieve this using SQL query?
create table mytable
( parent int not null,
cleft int null,
cright int null
)
insert into mytable (parent,cleft,cright) values (1,2,3);
insert into mytable (parent,cleft,cright) values (2,6,7);
insert into mytable (parent,cleft,cright) values (3,4,5);
insert into mytable (parent,cleft,cright) values (4,8,9);
insert into mytable (parent,cleft,cright) values (5,10,11);
insert into mytable (parent,cleft,cright) values (6,null,null);
insert into mytable (parent,cleft,cright) values (7,null,null);
insert into mytable (parent,cleft,cright) values (8,13,null);
insert into mytable (parent,cleft,cright) values (9,12,null);
insert into mytable (parent,cleft,cright) values (10,null,null);
insert into mytable (parent,cleft,cright) values (12,null,null);
insert into mytable (parent,cleft,cright) values (13,null,17);
insert into mytable (parent,cleft,cright) values (17,null,null);
DELIMITER $$
CREATE procedure GetChildCount (IN parentID INT)
DETERMINISTIC
BEGIN
declare ch int;
declare this_left int;
declare this_right int;
declare bContinue boolean;
declare count_needs_scan int;
create temporary table asdf999 (node_id int,processed int);
-- insert into asdf999 (node_id,processed) values (1,0);
-- update asdf999 set processed=1;
SET ch = parentID;
set bContinue=true;
while bContinue DO
-- at this point you are sitting at a ch (anywhere in hierarchy)
-- as you are looping and getting/using children
-- save non-null children references: -----------------------------
select cleft into this_left from mytable where parent=ch;
if !isnull(this_left) then
insert asdf999 (node_id,processed) select this_left,0;
end if;
select cright into this_right from mytable where parent=ch;
if !isnull(this_right) then
insert asdf999 (node_id,processed) select this_right,0;
end if;
-- -----------------------------------------------------------------
select count(*) into count_needs_scan from asdf999 where processed=0;
if count_needs_scan=0 then
set bContinue=false;
else
select node_id into ch from asdf999 where processed=0 limit 1;
update asdf999 set processed=1 where node_id=ch;
-- well, it is about to be processed
end if;
END WHILE;
select count(*) as the_count from asdf999;
drop table asdf999;
END $$
DELIMITER ;
call GetChildCount(2); -- answer is 2
call GetChildCount(4); -- answer is 5
I could supply a version that creates a dynamically named table (or temp table) and clobbers it at end if you want . "dynamic sql / prepare statment" inside of a procedure. that way users won't step on each other with shared use of the work table asdf999. so this is not production ready. but the above gives you an idea of the concept

Getting summary of results from another stored procedure

I have one complex stored procedure that returns some rows with some calculated values
SELECT CalculatedField1 ,
CalculatedField2 ,
...
FROM ...
WHERE CONDITION
this sproc (lets call it procA) returns variable number of rows, depending on the WHERE condition. This works fine. What I need to do now is to write a stored procedure that will get the summary of these returned rows.
-- procB
SELECT SUM(CalculatedField1),
SELECT SUM(CalculatedField2),
...
FROM (EXEC procA params)
Is this possible?
Edit: creating a temp table did the job, however I have problems with passing output pareters.
CREATE PROCEDURE [dbo].[sprocB] (#prm INT = NULL OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
SET #prm = 1
SELECT Id FROM dbo.AnyTable
END
CREATE PROCEDURE [dbo].[sprocA] (#prm INT = NULL OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
CREATE TABLE #temp (Id INT)
INSERT INTO #temp
EXEC sprocB #prm
SELECT Id FROM #temp
END
To execute:
USE [MyDatabase]
GO
DECLARE #return_value int,
#prm int
EXEC #return_value = [dbo].[sprocA]
#prm = #prm OUTPUT
SELECT #prm as N'#prm'
SELECT 'Return Value' = #return_value
GO
The results from temp table are ok, resultset is retrieved correctly, however #pem value is still NULL.
It is possible but you need an auxiliary table:
CREATE PROCEDURE procB
AS
declare #table table (CalculatedField1 int, CalculatedField12 int)
insert into #table
EXEC sp_a
select SUM(CalculatedField1), SUM(CalculatedField2)
from #table
GO
This might do what you want:
create table #scratch (CalculatedField1 int, CalculatedField2 int,...)
insert into #scratch (exec procA params)
select sum(CalculatedField1), sum(CalculatedField2),... from #scratch
drop table #scratch

How to update/Edit table through CSVs?

I stored 2 contact numbers in a table corresponding to one companyID in companycontactno. table. I did that using extracting values from CSV in Stored procedure.
If I want to edit those contact numbers Corresponding to company ID how am I going to do that?
This is the storedProcedure I will use for editing contact numbers .. I am having difficulty in updating it .. please help
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
CREATE PROCEDURE dbo.EditCompanyDetails
(
#OldCompanyName varchar(max),
#NewCompanyName varchar(max),
#newAddress varchar(max),
#newMailID varchar(max),
#Temp varchar(8000)
)
AS
BEGIN
SET NOCOUNT ON;
declare #compID int
DECLARE #c int, #a varchar(max), #id int, #variable varchar(8000), #max int
DECLARE #Temp_Table table (serial_no int Identity(1,1), value varchar(max))
--PROCEDURE--
--Editing Company Table--
set #compID=(Select Company.CompanyID from Company where Company.CompanyName=#OldCompanyName)
update Company
set CompanyName=#NewCompanyName, [Address]=#newAddress, Email=#newMailID
where Company.CompanyID=#compID
--For CONTACT NUMBERS
--Using Table to store CSV seperately in each row--
select #c = CHARINDEX(',', #Temp)
while #c > 0
BEGIN
insert into #Temp_Table
select LEFT(#Temp, #c - 1)
select #Temp = right(#Temp, LEN(#Temp) - #c)
select #c = CHARINDEX(',', #Temp)
END
--Update Table CompanyContactNo
--CompanyContactNo have following Columns:
--CNoID (PK)
--CompanyID (references PK in Company table
--ContactNumber
set #max= (select MAX(serial_no) from #Temp_Table)
while #max > 0
BEGIN
set #variable = (select value from #Temp_Table where serial_no=#max)
update CompanyContactNo
set ContactNumber=#variable
where CompanyID=#compID
set #max = #max-1
END
End
GO
Assuming you will only have 2 rows, and you know that there are 2 contact rows in the CompanyContactNo table, you could execute 2 Update statements that would each affect a different row:
UPDATE CompanyContactNo
Set ContactNumber=
(SELECT value FROM #Temp_Table WHERE serial_no = (SELECT MAX(serial_no) FROM #Temp_Table))
WHERE
CompanyID=#compID
AND (CNoId = select MAX(CNoId) FROM CompanyContactNo WHERE CompanyID = #compID)
and then for second contact number:
UPDATE CompanyContactNo
SET ContactNumber=
(SELECT value FROM #Temp_Table WHERE serial_no = (SELECT MIN(serial_no) FROM #Temp_Table))
WHERE
CompanyID=#compID
AND (CNoId = select MIN(CNoId) FROM CompanyContactNo WHERE CompanyID = #compID)

Dynamic insert into variable table statement SQL Server

I have a variable table:
DECLARE #A_Table TABLE(ID INT, att1 VARCHAR(100), att2 nvarchar(200))
I want to make dynamic sql, so I insert into this table some data (all inside a loop):
WHILE (#i <= 100) BEGIN
SELECT #other_att = NAME FROM #other_Table where ID = #i;
SET #sql = 'INSERT ' + #A_Table+ '(ID,att1,att2) SELECT '+CAST(#i AS VARCHAR)+' , '''+ #other_att+''', SUM('+ #other_att') FROM '+ #EVEN_OTHER_Table;
EXEC (#sql);
END
sql every time would look like:
INSERT INTO #A_Table SELECT 1 , 'subject', SUM(subject)
INSERT INTO #A_Table SELECT 2 , 'age', SUM(age)
INSERT INTO #A_Table SELECT 3 , 'sex', SUM(sex)....
AND after executing this :
SO I will get:
#A_Table:
id att1 att2
1 subject 4.3
2 age 4.5
3 sex 4.1
but I get an error:
Msg 137, Level 16, State 1, Line 48
Must declare the scalar variable "#A_Table".
SO what is it the syntax to insert dynamically into a variable table?
Ok I have understood it.
You could use the INSERT ... EXEC syntax to insert the data returned by the dynamic SELECT. Of course, you would then need to remove the INSERT part from the dynamic statement.
WHILE (#i <= 100) BEGIN
SELECT #other_att = NAME FROM #other_Table where ID = #i;
SET #sql = 'SELECT '+CAST(#i AS VARCHAR)+' , ''' + #other_att+''', SUM('+ #other_att + ') FROM '+ #EVEN_OTHER_Table;
INSERT INTO #A_Table (ID,att1,att2)
EXEC (#sql);
END
You have a table variable, not a variable that contains the table name.
So you would need the following.
WHILE (#i <= 100) BEGIN
SELECT #other_att = NAME FROM #other_Table where ID = #i;
SET #sql = 'INSERT INTO #A_Table (ID,att1,att2) SELECT '+CAST(#i AS VARCHAR)+' , '''+ #other_att+''', SUM('+ #other_att') FROM #EVEN_OTHER_Table';
EXEC (#sql);
END
You would also need to declare the table variable as a statement inside the #sql variable, and execute your declare table and inserts together, or use a local/global temporary table.
With a local temporary table (stored in the tempdb) you could do something like this.
CREATE TABLE #testtbl (ID INT);
EXEC ('INSERT INTO #testtbl VALUES (1)');
SELECT * FROM #testtbl
DROP TABLE #testtbl
Some good info about temporary tables in BOL
http://msdn.microsoft.com/en-us/library/ms174979.aspx - quite far down the page
And the table type.
http://msdn.microsoft.com/en-us/library/ms175010.aspx
Your EXEC statement occurs in a different context and is therefore unaware of any variables created in your original context.
To create dynamic insert query it is really a task, I also struggle to find it ,finally I have tried in the following way and it's successfully working. Please find the code below.
CREATE PROCEDURE [dbo].[InsertTodaysData] (#tbl varchar(50),#Days int,
#MDate varchar(50), #EValue varchar(50), #Speed varchar(50),
#Totalreturn varchar(50),#Closingv varchar(50), #TotalReturnV varchar(50))
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #SQLQuery varchar(2000)
-- Insert statements for procedure here
set #SQLQuery = 'INSERT INTO '+#tbl+' (ID,MDate,EValue,Speed,TotalReturnRatio,ClosingValue,
TotalReturnValue) VALUES ('+#Days+','''+#MDate+''', '+#EValue+', '+#Speed+',
'+#Totalreturn+', '+#Closingv+', '+#TotalReturnV+')'
EXECUTE(#SQLQuery)
END
Hope this will help you..