SQL Server query with list parameter - sql-server

I am using SQL Server and in a stored procedure I want to execute a query with a list parameter something like this:
select * from table where type in #list_types
Is it possible to make this? Or must I use temporary tables?

You could use table-valued parameters. For example:
-- A table valued parameter must have a type.
-- This command creates the type.
create type YourType as table (type varchar(50))
go
create procedure dbo.YourStoredProcedure(
#types YourType readonly)
as
select *
from YourTable
where type in (select type from #types)
go
You can invoke the stored procedure like this:
declare #types YourType
insert #types (type) values ('Type1'), ('Type2')
exec dbo.YourStoredProcedure #types
ADO.NET supports passing a DataTable as a table-valued parameter.

Try this one -
DECLARE #temp TABLE
(
[type] INT
, name NVARCHAR(50)
)
INSERT INTO #temp ([type], name)
VALUES
(1, '1'),
(2, '2')
DECLARE #list_types VARCHAR(30)
SELECT #list_types = '1,3,4,5'
;WITH cte AS
(
SELECT [type] = p.value('(./s)[1]', 'INT')
FROM (
SELECT field = CAST('<r><s>' + REPLACE(#list_types, ',', '</s></r><r><s>') + '</s></r>' AS XML)
) d
CROSS APPLY field.nodes('/r') t(p)
)
SELECT *
FROM #temp
WHERE [type] IN (SELECT [type] FROM cte)

Related

Issue with splitting values and passing to a stored procedure

Iam getting the below input parameter values in one of the stored procedure.
#DocKey1, #DocValue1,
#DocKey2, #DocValue2,
#DocKey3, #DocValue3,
#DocKey4, #DocValue4,
#DocKey5, #DocValue5
From this procedure iam calling another procedure to insert each pair of values.
Right now am calling the InsertDocValues stored procedure multiple times to insert each pair.
exec InsertDocValues #DocKey1, #DocValue1
exec InsertDocValues #DocKey2, #DocValue2
exec InsertDocValues #DocKey3, #DocValue3
exec InsertDocValues #DocKey4, #DocValue4
exec InsertDocValues #DocKey5, #DocValue5
Is there anyway i can pass the complete set of values to another procedure as below and then split each pair and insert
eg: #DocKey1, #DocValue1 and #DocKey2, #DocValue2 etc
#DocKey1, #DocValue1, #DocKey2, #DocValue2, #DocKey3, #DocValue3, #DocKey4, #DocValue4, #DocKey5, #DocValue5
Below is the procedure am using now to insert
Create PROCEDURE [dbo].[InsertDocValues]
(
#DocKey varchar(20),
#DocValue nvarchar(20)
)
AS
SET NOCOUNT ON;
BEGIN
INSERT INTO dbo.DocValues(
DocKey,
DocValue
)
VALUES(
#DocKey,
#DocValue
)
End
Please suggest
May be the below code would work for you.
Using user defined table type variable.
CREATE TYPE DocTable AS TABLE
(
DocKey int,
DocValue nvarchar(50)
);
GO
And then use this type to create required variable in first SP and pass the same to your second SP.
DECLARE #DocTable AS DocTable;
INSERT INTO #DocTable
SELECT #DocKey1, #DocValue1 UNION ALL
SELECT #DocKey2, #DocValue2 UNION ALL
SELECT #DocKey3, #DocValue3 UNION ALL
SELECT #DocKey4, #DocValue4 UNION ALL
SELECT #DocKey5, #DocValue5
You can create the above insert query dynamically also. There are so many ways to populate a table. So, use any one as you are getting output from your first SP.
And then call your Second SP.
EXEC [dbo].[InsertDocValues] #DocTable
Changes in second SP would be look like this.
Create PROCEDURE [dbo].[InsertDocValues]
(
#DocTable DocTable READONLY
)
AS
SET NOCOUNT ON;
BEGIN
INSERT INTO dbo.DocValues(
DocKey,
DocValue
)
SELECT
DocKey,
DocValue
FROM #DocTable
END
I'm getting the sense you have a string of pairs (key,value). Perhaps something like this:
Example
Declare #List varchar(max) = 'Key1:Value1,Key2:Value2'
Insert Into dbo.DocValues(DocKey,DocValue )
Select DocKey = left(RetVal,charindex(':',RetVal+':')-1)
,DocVal = stuff(RetVal,1,charindex(':',RetVal+':'),'')
From (
Select RetSeq = row_number() over (Order By (Select null))
,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(#List,',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
) A
The Data Inserted would be
DocKey DocVal
Key1 Value1
Key2 Value2

Take results from one stored procedure and send them to another stored procedure

declare #temp table
(
ItemID varchar(100),
)
INSERT INTO #temp (ItemID, Qt)
EXEC A 'LA'
I want to then take the temp table results in field1 (will show field1 and field2) and loop those results using stored procedure B.
Figured I'd provide an example (I was 99% sure my comment was correct but thought I'd double-check.
CREATE PROC dbo.A #x varchar(10) AS SELECT #x FROM (VALUES (1),(1),(1))x(x);
CREATE PROC dbo.B AS SELECT * FROM ##xx;
IF object_id('tempdb..##xx') IS NOT NULL DROP TABLE ##xx;
CREATE TABLE ##xx (col1 varchar(10));
INSERT ##xx EXEC dbo.A 'hi';
EXEC dbo.B;
Results:
col1
------
hi
hi
hi
You could create a User-Defined Table Type, declare a variable as that type (instead of declaring a table variable) and send that over to a procedure which is expecting that type - as a READONLY.
For example:
CREATE TYPE SomeTableType AS TABLE(
[Id] INT,
[Val] VARCHAR(10)
)
Create a procedure that takes this type as a READONLY parameter:
CREATE PROCEDURE p_some_procedure_name
#table SomeTableType READONLY
AS
SELECT * FROM #table;
Now you can declare an instance of your type anywhere (say another procedure), populate it with data and call p_some_procedure_name with it:
DECLARE #temp_table SomeTableType;
INSERT #temp_table(Id, Val) VALUES (1, 'First'), (2, 'Second');
EXEC p_some_procedure_name #temp_table;
If possible (which is often the case), avoid looping.

TSQL Select Clause with Case Statement

I have a basic select statement that is getting me a list of types that are stored in the database:
SELECT teType
FROM BS_TrainingEvent_Types
WHERE source = #source
FOR XML PATH ('options'), TYPE, ELEMENTS, ROOT ('types')
My table contains a type column and a source column.
There is a record in that table where I need to include it for two separate sources but I can't create a separate record for it.
**Table Data**
type | source
test users
test2 members
test3 admins
I need a case statement to be able to say IF source = admins also give me the type test2.
Does this make sense and is it possible to do with a basic select?
Update
I came up with this temp solution but I still think there is a better way to handle this.:
DECLARE #tmp AS TABLE (
QID VARCHAR (10));
INSERT INTO #tmp (QID)
SELECT DISTINCT qid
FROM tfs_adhocpermissions;
SELECT t.QID,
emp.FirstName,
emp.LastName,
emp.NTID,
(SELECT accessKey
FROM TFS_AdhocPermissions AS p
WHERE p.QID = t.QID
FOR XML PATH ('key'), TYPE, ELEMENTS, ROOT ('keys'))
FROM #tmp AS t
LEFT OUTER JOIN
dbo.EmployeeTable AS emp
ON t.QID = emp.QID
FOR XML PATH ('data'), TYPE, ELEMENTS, ROOT ('root');
try this
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--create temp table for testing
IF OBJECT_ID('Tempdb..#BS_TrainingEvent_Types') IS NOT NULL
DROP TABLE #BS_TrainingEvent_Types
SELECT [type] ,
[source]
INTO #BS_TrainingEvent_Types
FROM ( VALUES ( 'test', 'users'), ( 'test2', 'members'),
( 'test3', 'admins') ) t ( [type], [source] )
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--final query
DECLARE #Source VARCHAR(10) = 'users'
IF #Source = 'admins'
BEGIN
SELECT [Type]
FROM #BS_TrainingEvent_Types
WHERE source = #source
OR [type] = 'test2'
FOR XML PATH('options') ,
TYPE ,
ELEMENTS ,
ROOT('types')
END
ELSE
BEGIN
SELECT [Type]
FROM #BS_TrainingEvent_Types
WHERE source = #source
FOR XML PATH('options') ,
TYPE ,
ELEMENTS ,
ROOT('types')
END
select sq.teType
from (
SELECT t.teType
FROM BS_TrainingEvent_Types t
WHERE t.source = #source
union all
SELECT t.teType
FROM BS_TrainingEvent_Types t
WHERE #source = 'admins' and t.source = 'members'
) sq
FOR XML PATH ('options'), TYPE, ELEMENTS, ROOT ('types');
Though normally it would be better to introduce an additional table that would store these relationships, so that the whole idea would be more expandable.

how to pass multiple values in single parameter and how to convert varchar value into integers

CREATE TABLE students
( id INT,
NAME varchar(20)
)
INSERT INTO students(id,name)VALUES(1,'Danny')
INSERT INTO students(id,name)VALUES(2,'Dave')
INSERT INTO students(id,name)VALUES(3,'Sue')
INSERT INTO students(id,name)VALUES(4,'Jack')
INSERT INTO students(id,name)VALUES(5,'Rita')
INSERT INTO students(id,name)VALUES(6,'Sarah')
This is my stored procedure
alter PROCEDURE emp_sp
(
#std_id as VARCHAR(500),
#std_name as varchar(500)
)
AS
begin
SELECT *FROM Students s
WHERE s.id IN(convert(INT,#std_id) ,',')
AND
s.NAME IN(#std_name)
END
GO
Here I execute it manually
EXEC dbo.emp_sp #std_id='1,2,3', #std_name='"Danny","Dave","Sue"'
but I get this error:
Msg 245, Level 16, State 1, Procedure emp_sp, Line 8
Conversion failed when converting the varchar value ',' to data type int.
Anyone can guide me.
To get your current approach working, you will need to use Dynamic Sql, which will be incredibly fragile and prone to Sql Injection attacks. Example of this Here
The better way to do this is through Table Valued Parameters:
CREATE TYPE ttStudentIDs AS TABLE
(
ID INT
);
GO
CREATE TYPE ttStudentNames AS TABLE
(
Name VARCHAR(20)
);
GO
CREATE PROCEDURE dbo.emp_sp
(
#stdIds ttStudentIDs READONLY,
#stdNames ttStudentNames READONLY
)
AS
begin
SELECT s.ID, s.Name
FROM Students s
INNER JOIN #stdIds si
ON s.ID = si.ID
UNION
SELECT s.ID, s.Name
FROM Students s
INNER JOIN #stdNames sn
ON s.Name = sn.Name;
END
GO
And called like so:
DECLARE #Ids AS ttStudentIDs;
DECLARE #Names AS ttStudentNames;
INSERT INTO #Ids VALUES (1),(2),(3);
INSERT INTO #Names VALUES ('Danny'),('Dave'),('Sue');
EXEC dbo.emp_sp #Ids, #Names;
SqlFiddle here

Table variable error: Must declare the scalar variable "#temp"

I am trying to achieve:
declare #TEMP table (ID int, Name varchar(max))
insert into #temp SELECT ID, Name FROM Table
SELECT * FROM #TEMP
WHERE #TEMP.ID = 1 <--- ERROR AT #TEMP.ID
But I'm getting the following error:
Must declare the scalar variable "#temp".
What am I doing wrong?
A table alias cannot start with a #. So, give #Temp another alias (or leave out the two-part naming altogether):
SELECT *
FROM #TEMP t
WHERE t.ID = 1;
Also, a single equals sign is traditionally used in SQL for a comparison.
Either use an Allias in the table like T and use T.ID, or use just the column name.
declare #TEMP table (ID int, Name varchar(max))
insert into #temp SELECT ID, Name FROM Table
SELECT * FROM #TEMP
WHERE ID = 1
There is one another method of temp table
create table #TempTable (
ID int,
name varchar(max)
)
insert into #TempTable (ID,name)
Select ID,Name
from Table
SELECT *
FROM #TempTable
WHERE ID = 1
Make Sure You are selecting the right database.
If you bracket the # you can use it directly
declare #TEMP table (ID int, Name varchar(max))
insert into #temp values (1,'one'), (2,'two')
SELECT * FROM #TEMP
WHERE [#TEMP].[ID] = 1
You should use hash (#) tables, That you actually looking for because variables value will remain till that execution only.
e.g. -
declare #TEMP table (ID int, Name varchar(max))
insert into #temp SELECT ID, Name FROM Table
When above two and below two statements execute separately.
SELECT * FROM #TEMP
WHERE #TEMP.ID = 1
The error will show because the value of variable lost when you execute the batch of query second time.
It definitely gives o/p when you run an entire block of code.
The hash table is the best possible option for storing and retrieving the temporary value. It last long till the parent session is alive.
try the following query:
SELECT ID,
Name
INTO #tempTable
FROM Table
SELECT *
FROM #tempTable
WHERE ID = 1
It doesn't need to declare table.
You could stil use #TEMP if you quote the identifier "#TEMP":
declare #TEMP table (ID int, Name varchar(max));
insert into #temp SELECT 1 AS ID, 'a' Name;
SELECT * FROM #TEMP WHERE "#TEMP".ID = 1 ;
db<>fiddle demo
You've declared #TEMP but in your insert statement used #temp. Case sensitive variable names.
Change #temp to #TEMP

Resources