Iterate through values of a table variable in a stored procedure - sql

I am writing a stored proc as follows:
CREATE PROCEDURE ListByOrderRequestId
#EntityId int,
#EntityTypeId varchar(8)
AS
BEGIN
SET NOCOUNT ON;
Declare #IDS table(OrderRequestId int)
INSERT INTO #IDS
SELECT OrderRequestTaskId
FROM OrderRequestTask ORT WITH (NOLOCK)
WHERE ORT.OrderRequestId = #EntityId
SELECT N.EntityNoteId AS Id,
N.UpdateDate AS DateStamp,
N.EntityNoteText,
N.EntityId,
N.EntityNoteTypeId,
N.EntityTypeId
FROM EntityNote N
WHERE (N.EntityId = #EntityId AND N.EntityTypeId ='ORDREQ')
*OR(N.EntityId = #IDS VAL1 AND N.EntityTypeId ='TASK')
OR(N.EntityId = #IDS VAL2 AND N.EntityTypeId ='TASK')*
END
The table #IDS can have 0 or 1 or more values in it. I want to loop through the values in #TDS and create the where clause above accordingly. Please help me.

As opposed to looping through the table, you could just use it in your where clause like this:
Select * From {Your Table} Where ID in (Select OrderRequestId From IDS)
This is much faster than looping.

Related

How to pass multiple values for a column in sql Stored Procedure?

i have two tables, such as
Queue
QueueID
LogParameters
QueueParameters
QueueParametersID
QueueID
LogParametersKey
LogParametersValue
I have to write SP inorder to make an entry in both the tables,
LogParameterKey and LogParameterValue may contains multiple values but the QueueID for each values should be same and QueueParameterID could be different.
**QueueID** **LogParameters**
1 AA
**QueueParametersID** **QueueID** **LogParametersKey** **LogParametersValue**
1 1 FirstName Mohammad
2 1 LastName Salman
3 1 Age 17
How do i pass multiple values for LogParameterKey and LogParameterValue?.. Someone suggested me to use Array for this... Is there's any other way?
CREATE Procedure AddQueue
#LogParameters NVARCHAR(255)
#AuditParameters AS AuditParameter READONLY,-- UserDefinedTable
AS
SET NOCOUNT ON;
BEGIN
DECLARE #QueueID BIGINT
EXECUTE dbo.procInsertQueue
#LogParameters = #LogParameters,
#QueueID = #QueueID OUTPUT
DECLARE #GetQueueID BIGINT = (SELECT QueuesID FROM Queues WHERE LogParameters= #LogParameters
DECLARE #AuditQueueParametersID BIGINT
DECLARE #TempTable TABLE(
ParameterKey NVARCHAR(255),
ParameterValue NVARCHAR(255),
AuditQueuesID BIGINT)
INSERT INTO #TempTable(ParameterKey,ParameterValue,QueuesID)
SELECT ParameterKey,ParameterValue,#GetQueueID FROM #AuditParameters
DECLARE #LogParameterKey NVARCHAR(255) = (SELECT ParameterKey FROM #TempTable WHERE QueuesID = #GetQueueID)
DECLARE #LogParameterValue NVARCHAR(255) = (SELECT ParameterValue FROM #TempTable WHERE QueuesID = #GetQueueID)
EXECUTE dbo.procAddQueueParameters
#AuditQueueID = #GetQueueID
#LogParametersKey = #LogParametersKey,
#LogParametersValue = #LogParametersValue,
#QueueParametersID = #QueueParametersID OUTPUT
END
END
1. Use User-Defined Table Types
https://technet.microsoft.com/en-us/library/bb522526(v=sql.105).aspx
2. Generate xml string and parse in SP
3.Use temp table
CREATE TABLE #Input
(
QueueParametersID ..
QueueID ..
LogParametersKey ..
LogParametersValue ..
)
--INSERT VALUES
EXEC dbo.YouSP
IN SP use table #Input

Update a column with the result-dataset-count of a stored procedure

I have a table #data which has the columns Id and Count. In addition I have a stored procedure MyProc which accepts a parameter #id (equals the Id column) and returns a dataset (the count equals the Count column).
My goal is to assign the Count column from Id with MyProc without a cursor.
I know, something like this does not work:
UPDATE d
SET Count = (SELECT COUNT(*) FROM (EXEC MyProc d.Id))
FROM #data AS d
Is there a syntax I do not know or is a cursor the only option to achieve this?
PS: It is a code quality and performance problem for me. Calling the stored procedure would be the easiest way without repeating 50 lines of SQL but a cursor slows it down.
I believe you can make use of the below query :
IF OBJECT_ID('dbo.data') IS NOT NULL DROP TABLE data;
IF OBJECT_ID('dbo.MyFunct') IS NOT NULL DROP FUNCTION dbo.MyFunct;
GO
CREATE TABLE data
(
ID int,
[Count] int
);
INSERT data VALUES (1,5), (1,10), (2,3), (4,6);
GO
UPDATE d
SET d.[Count] = f.CNT
FROM
(SELECT ID,COUNT(id) AS CNT FROM data GROUP BY ID) f
INNER JOIN data d ON f.ID = d.ID
I couldn't find a way to use Stored procedure. Needed you can use Table valued function:
CREATE FUNCTION dbo.MyFunct(#id INT)
RETURNS #i TABLE
(ID INT , CNT INT)
AS
BEGIN
INSERT INTO #i
SELECT ID,COUNT(id) AS CNT FROM data GROUP BY ID
RETURN
END;
GO
UPDATE d
SET d.[Count] = f.CNT
FROM dbo.MyFunct(1) f INNER JOIN data d ON f.ID = d.ID
To do what you say, you need a function, not a procedure.
CREATE FUNCTION dbo.myFunc (#Id INT)
RETURNS INT
AS
BEGIN
UPDATE someTable
SET someCol = 'someValue'
WHERE id = #Id;
RETURN ##ROWCOUNT;
END
GO
Then call the function in your update statement;
UPDATE d
SET d.Count = dbo.myFunc(d.Id)
FROM #data AS d;
However, row-based operations is bad practice. You should always strive to perform set-based operations, but as I don't know what your procedure does, I cannot provide more than a wild guess to what you should do (not using a procedure at all):
DECLARE #data TABLE (Id INT);
UPDATE x
SET x.someCol = 'SomeVal'
OUTPUT INSERTED.id INTO #data
FROM someTable AS x
INNER JOIN #data AS d
ON d.Id = x.Id;
WITH cte (Id, myCount) AS (
SELECT d.Id
,COUNT(d.Id) AS myCount
FROM #data AS d
GROUP BY d.Id
)
UPDATE d
SET d.[Count] = c.myCount
FROM #data AS d
INNER JOIN cte AS c
ON c.Id = d.Id;
I don't fully understand what you're trying to do but I think your solution will involve ##ROWCOUNT; Observe:
-- Sample data and proc...
----------------------------------------------------------------------
IF OBJECT_ID('tempdb..#data') IS NOT NULL DROP TABLE #data;
IF OBJECT_ID('dbo.MyProc') IS NOT NULL DROP PROC dbo.MyProc;
GO
CREATE TABLE #data
(
id int,
[Count] int
);
INSERT #data VALUES (1,5), (1,10), (2,3), (4,6);
GO
CREATE PROC dbo.MyProc(#id int)
AS
BEGIN
SELECT 'some value'
FROM #data
WHERE #id = id;
END;
GO
Data BEFORE:
id Count
----------- -----------
1 5
1 10
2 3
4 6
A routine that uses ##ROWCOUNT
DECLARE #someid int = 1; -- the value you're passing to your proc
EXEC dbo.MyProc 1;
DECLARE #rows int = ##ROWCOUNT; -- this is what you need.
UPDATE #data
SET [Count] = #rows
WHERE id = #someid;
Data AFTER
id Count
----------- -----------
1 2
1 2
2 3
4 6

Insert Query to insert multiple rows in a table via select and output clause. SQL Server 2008

I have a created a stored procedure (please ignore syntax errors)
alter proc usp_newServerDetails
(#appid int, #envid int, #serType varchar(20), #servName varchar(20))
as
declare #oTbl_sd table (ID int)
declare #outID1
declare #oTbl_cd table (ID int)
declare #outID2
begin Transaction
insert into server_details(envid, servertype, servername)
output inserted.serverid into #oTbl_sd(ID)
values(#envid, #serType, #servName)
select #outID1 = ID from #oTbl_sd
insert into configdetails(serverid, servertype, configpath, configtype)
output inserted.configid into #oTbl_cd(ID)
(select #outID1, cm.servertype, cm.configpath, cm.configtype
from configpthmaster cm
where cm.appid = #appid )
select #outID2 = ID from #oTbl_cd
insert into configkeydetails(confiid, keyname)
output inserted.Keyid into #oTbl_ckd(ID)
(select #outID2, cm.key
from configpthmaster cm
where cm.appid = #appid)
begin
commit
end
server_details table has an identity column ID with is auto-generated ie. #outID1 and first insert query inserts only 1 row.
configpthmaster table is not related to any other table directly and has 2 unique data rows, which I want to fetch to insert data into other tables, one by one during insertion.
The second insert query fetch data from configpthmaster table
and insert 2 rows in configdetails while generating (auto-generated) ID ie. #outID2.
It also has a FK mapped to server_details.
The problem is "#outID2" giving last inserted ID only (ie. if two id generated 100,101 i am getting 101) which eventually on 3rd insertion, inserting 2 rows with same id 101 only but i want the insertion should be linear. i.e one for 100 and other for 101.
If zero rows affected while insertion how to rollback the transaction?
How can I achieve these requirements? Please help.
Change your procedure like below,and try again.
ALTER PROCEDURE usp_newServerDetails(#appid int, #envid int,#serType varchar(20),#servName varchar(20))
AS
BEGIN
BEGIN TRY
DECLARE #Output TABLE (ID int,TableName VARCHAR(50),cmKey VARCHAR(50)) --table variable for keeping Inserted ID's
BEGIN TRAN
IF EXISTS ( SELECT 1 FROM configpthmaster cm WHERE cm.appid = #appid )
AND ( SELECT 1 FROM configkeydetails ck WHERE ck.appid = #appid ) --add a conditon to satisfy the valid insertions
BEGIN
INSERT INTO server_detials(envid,servertype,servername)
OUTPUT inserted.serverid,'server_detials',NULL INTO #Output(ID,TableName,cmKey )
VALUES(#envid ,#serType ,#servName)
INSERT INTO configdetails(serverid,servertype,configpath,configtype)
OUTPUT inserted.configid,'configdetails',cm.Key INTO #Output(ID,TableName,cmKey )
SELECT t.ID,cm.servertype,cm.configpath,cm.configtype
FROM configpthmaster cm
CROSS APPLY (SELECT ID FROM #Output WHERE TableName='server_detials')t
WHERE cm.appid = #appid
INSERT INTO configkeydetails(configId,keyname)
SELECT ID,cmKey FROM #Output
WHERE TableName='configdetails'
END
COMMIT TRAN
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK
END CATCH
END
Could you try this solution?
alter proc usp_newServerDetails(#appid int, #envid int,#serType varchar(20),#servName varchar(20))
as
declare #oTbl_sd table (ID int)
declare #outID1
declare #oTbl_cd table (ID int)
declare #outID2
begin Transaction
insert into server_detials(envid,servertype,servername)
output inserted.serverid into #oTbl_sd(ID)
values(#envid ,#serType ,#servName)
select #outID1 = ID from #oTbl_sd
insert into configdetails(serverid,servertype,configpath,configtype)
output inserted.configid into #oTbl_cd(ID)
(select #outID1 ,cm.servertype,cm.configpath,cm.configtype from configpthmaster cm where cm.appid = #appid )
select #outID2 = ID from #oTbl_cd
insert into configkeydetails(confiid,keyname)
output inserted.Keyid into #oTbl_ckd(ID)
(select isnull(replace(stuff((SELECT inserted.configid FOR xml path('')), 1, 1, ''), '&', '&'), '') ,cm.key, from configpthmaster cm where cm.appid = #appid )
begin
commit
end
I just added STUFF in your code.
The STUFF function inserts a string into another string.
Do take note that using STUFF drastically slows the processing time of the code.
for more information about STUFF

Adding column to a resultset in stored procedure

I'm working on SP, I want to add a column to a resultset. Normally this would not be a proble, but here I'm using an Exec to fill one temp-table. To that temp-table I want to add one column.
Some prestuff that puts data in one of the temp-tables with some conditions
declare #RowCount int
set #RowCount = 1
create table #Temp_HS (row int IDENTITY (1, 1) NOT NULL, h varchar(30))
Create table #tmpS (K varchar(100),
U varchar(100), Counter int, H varchar(100))
--Puts data in one temp_table with employees
insert into #Temp_HS (h)
select Login from database.dbo.Users
where Old <> 1
and TC in ('A_1', 'A_2')
and Login not in ('Steve', 'Peter', 'Gabs')
--Declaring my counter here, it sets the MaxRow which is 19 in this case
declare #Counter int
set #Counter = (select Max(row) from #Temp_HS)
select * from #Temp_HS
-- Looping, That my RowCount must be less or Equal to Counter which is 19.
while #RowCount <= #Counter
begin
Set User which was originally from the Database Login which is declared as H in the temp table.
declare #user varchar(30)
select #user = h from #Temp_HS where row = #RowCount
Here comes the tricky part, this is the Stored procedure that inserts 3 columns into a temp
table, here I want to add one colum which in this case is h from Temp_HS to the resultset.
INSERT INTO #tmpS
EXEC Database.dbo.getListCount #user,
param,
param,
param,
'something',
param
set #RowCount = #RowCount +1
end
drop table #Temp_HS
If you need any further information just ask! :)
Basically I want to add one more column to the results of my Exec SP that inserts the result into a temp_table
INSERT INTO .. EXEC requires that the table you are inserting into already exists, e.g.
-- Given this preexisting proc
CREATE PROC dbo.getListCount #user INT, -- other params
AS
SELECT #User as Col1,
'SomeVarChar' as Col2
FROM [SomeTable];
-- In your code, create the temp table to hold the data
CREATE TABLE #tmpS
(
Col1 INT,
Col2 NVARCHAR(100),
NewColumnH VARCHAR(30) -- Add the additional column up front
-- etc.
);
This is called as
INSERT INTO #tmpS(Col1, Col2)
EXEC dbo.getListCount, #User;
If you then need to do do further processing on your temp table, do this after the PROC call:
UPDATE ts
SET NewColumnH = t.h
FROM #tmpS ts INNER JOIN #Temp_HS th on th.row = #RowCount;
Actually inner join doesnt work as desireed on temp tables that is why I used this solution. Since I already had #User in a variable I choose to do this update instead.
UPDATE ts
SET NewColumnH = #User
FROM #tmpS ts
where ts.Column is null

sql: my data repeats itself

When I execute my code it works but my data repeats itself. The print is just to see what it gets.
DECLARE #Variable1 NVARCHAR(MAX)
DECLARE #Variable2 NVARCHAR(MAX)
DECLARE #Variable3 NVARCHAR(MAX)
CREATE TABLE #Temp1 (MAI_ID BIGINT, FUN_ID BIGINT)
CREATE TABLE #tmp2 (MAI_ID BIGINT, Variable1 NVARCHAR(MAX),Variable2 NVARCHAR(MAX), Variable3 NVARCHAR(MAX))
INSERT INTO #Temp1
SELECT TOP 10 ISD_MainID, ISNULL(ISD_FUNID,0)
FROM [dev_SAB_EM].[dbo].[SiteDetails]
ORDER BY ISD_ID DESC
DECLARE #MAI_ID BIGINT
DECLARE #FUN_ID BIGINT
WHILE (SELECT COUNT(MAI_ID) FROM #Temp1) <> 0
BEGIN
SELECT TOP 1 #MAI_ID = MAI_ID, #FUN_ID = FUN_ID FROM #Temp1
PRINT #MAI_ID
PRINT #FUN_ID
SELECT #Variable1 = ISNULL(FUN_Name,'') FROM [dev_SAB_Man].[dbo].[fx_GetFUNStructureCTE_Asc] (#FUN_ID) WHERE FUN_Level = 1
SELECT #Variable2 = ISNULL(FUN_Name,'') FROM [dev_SAB_Man].[dbo].[fx_GetFUNStructureCTE_Asc] (#FUN_ID) WHERE FUN_Level = 2
SELECT #Variable3 = ISNULL(FUN_Name,'') FROM [dev_SAB_Man].[dbo].[fx_GetFUNStructureCTE_Asc] (#FUN_ID) WHERE FUN_Level = 3
INSERT INTO #tmp2(MAI_ID, Variable1, Variable2, Variable3)
SELECT #MAI_ID, #Variable1, #Variable2, #Variable3
DELETE FROM #Temp1 WHERE MAI_ID = #MAI_ID AND FUN_ID = #FUN_ID
END
SELECT * FROM #tmp2
DROP TABLE #Temp1
DROP TABLE #tmp2
fx_GetFUNStructureCTE_Asc
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fx_GetFUNStructureCTE_Asc] (#param_FUNID int)
RETURNS #FUN_Names table
(
[Level_Label] nvarchar(255),
[FUN_Name] nvarchar(255),
[FUN_Level] int,
[FUN_ID] int
)
AS
BEGIN
with cte([Level_Label],[FUN_Name],[FUN_Level],[FUN_ID],[FUN_FUNID]) as
(
select ful1.FUL_Name,fu1.FUN_Name,fu1.FUN_Level,fu1.FUN_ID,fu1.FUN_FUNID
from FunctionalUnits fu1
inner join FunctionalUnitLevels ful1 on ful1.FUL_Level=fu1.FUN_Level
where fu1.FUN_ID=#param_FUNID
union all
select ful2.FUL_Name,fu2.FUN_Name,fu2.FUN_Level,fu2.FUN_ID,fu2.FUN_FUNID
from FunctionalUnits fu2
inner join FunctionalUnitLevels ful2 on ful2.FUL_Level=fu2.FUN_Level
inner join CTE a on a.FUN_FUNID=fu2.FUN_ID
)
insert into #FUN_Names
([Level_Label],[FUN_Name],[FUN_Level],[FUN_ID])
(select [Level_Label],[FUN_Name],[FUN_Level],[FUN_ID] from cte
where exists (select FUA_isActive from FunctionalUnitsActive where FUA_isActive=1))
return
RETURN
END
GO
Any suggestions or anything that can hep me?
Ok I've added fx_GetFUNStructureCTE_Asc
Considering the informations you gave, besides what #Lamak said, it also may depend on what the the field ISD_FUNID values has on [dev_SAB_EM].[dbo].[SiteDetails] table. If they are all the same on every record then there's no problem with your code...
But, it's a basic assumption...
And, assuming what you said on your comment as the value of ISD_FUNID being NULL, what may be happening is this: when all the value of the field FUN_ID are 0 on table #Temp1 what will happen when you execute the query on the function [dev_SAB_Man].[dbo].[fx_GetFUNStructureCTE_Asc] is that all rows will loop while the assignment occurs, setting the variables values to the last one returned by the function.
It'll make all the variables values be the same for all #tmp2 rows. You may need to improve the function call to return just one value.