Pass 'IN' list in SQL Procedure - sql

In a SQL procedure I need to pass an 'IN' list like below example
CREATE PROCEDURE [dbo].[In_List]
( #dept float
)
AS
BEGIN
select * from My_Table
where departmentId in (#dept)
;
END
exec In_List 100 --Work fine
exec In_List 102,100 --Problem is passing in list
Can someone please help me how to pass IN list thru SQL procedure. Also I need to pass another variable which is varchar. These procedure will be used for SSRS reports.

Just in case you want to go dynamic:
CREATE PROCEDURE [dbo].[In_List]
( #dept float
)
AS
declare v_sql varchar(2000)
BEGIN
set v_sql = 'select * from My_Table where departmentId in (' + #dept + ');'
;
END
Then, in SSRS:
#dept = join(Parameters!dept.value, ",")
Or, if varchar:
#dept = join(Parameters!dept.value,"','")

Related

Stored procedure table-valued variable without aliases in query string must declare scalar variable

I will pass a table-valued input parameter into a stored procedure, and also a variable that contains query string, so I made my sproc like this.
CREATE PROCEDURE [dbo].[SP_SelectData_View]
(
#Sort VARCHAR(MAX),
#CONDITION VARCHAR(MAX) = ''
#Values dbo.FlowStatus READONLY
)
AS
BEGIN
DECLARE #STRQUERY NVARCHAR(MAX)
IF #CONDITION IS NOT NULL AND #CONDITION != ''
BEGIN
SET #CONDITION = 'WHERE ' + #CONDITION
END
ELSE
BEGIN
SET #CONDITION = ''
END
IF #Sort IS NULL OR #Sort = ''
BEGIN
SET #Sort = 'Id Desc'
END
BEGIN
SET #STRQUERY = 'SELECT A.*
FROM ' + #Values + ' as FlowStatus'
JOIN Tbl_A as A
ON A.status = FlowStatus.StatusNowId AND B.flow = FlowStatus.FlowNowId
' + #CONDITION + '
Order By ' + #Sort
EXEC(#STRQUERY)
END
END
But in the code above, I got an error
must declare scalar variable #Values
I've searched for it and I think it is because the aliases is not detected because it's inside a string. But if I didn't put it in a string query, the #condition and #sort variable will be error. Is there a solution where I can do both calling the table-valued variable and query string variable together?
There are several things wrong with the approach you currently have, as I and others have commented, Brent Ozar has a good reference on dynamic SQL https://www.brentozar.com/sql/dynamic/
I would say don't pass in some SQL, construct it in the stored proc; passing in parameters such as name which is used in the where, hence I have put a full working example. This also shows how to pass the user defined table type into the stored proc and then also pass it into the dynamic SQL.
I hope this is a good enough example of the techniques, I had a bit of time so thought I would try and help as much as possible :)
/*
--------------------------------------------
Create a test table to run the stored proc against
*/
IF (NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'MyTestTable'))
BEGIN
PRINT 'Creating table MyTestTable'
CREATE TABLE [dbo].[MyTestTable](
Id BIGINT NOT NULL IDENTITY(1,1) PRIMARY KEY,
[Name] NVARCHAR(50) NOT NULL
)
INSERT INTO dbo.MyTestTable ([Name])
VALUES ('Andrew'),
('Bob'),
('john')
-- SELECT * FROM MyTestTable
END
GO
/*
--------------------------------------------
Create the table type that we pass into the store proc
*/
IF NOT EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = 'FlowStatus')
BEGIN
PRINT 'Creating type [dbo].[FlowStatus]'
CREATE TYPE [dbo].FlowStatus AS TABLE (
MyId BIGINT PRIMARY KEY,
SomeText NVARCHAR(200)
)
END
GO
/*
--------------------------------------------
Create the stored proc with the User Defined table type
*/
CREATE OR ALTER PROCEDURE [dbo].[MyStoredProc]
(
#SortBy VARCHAR(50),
#SearchName VARCHAR(50),
#Values dbo.FlowStatus READONLY
)
AS
BEGIN
-- As your SQL gets more complex it is an idea to create seperate parts of the SQL
DECLARE #SqlToExecute NVARCHAR(MAX)
-- The primary data you want to get
SET #SqlToExecute = N'
SELECT T.Id, T.[Name], V.SomeText
FROM MyTestTable AS T
LEFT JOIN #Values AS V ON V.MyId = T.Id
WHERE 1 = 1' -- We do this so that we can have many AND statements which could be expanded upon
IF #SearchName IS NOT NULL
BEGIN
SET #SqlToExecute = #SqlToExecute + N'
AND T.[Name] LIKE ''%' + #SearchName + ''''
END
IF #SortBy IS NOT NULL
BEGIN
SET #SqlToExecute = #SqlToExecute + N'
ORDER BY ' +
CASE WHEN #SortBy LIKE 'Name%' THEN N'T.[Name]'
ELSE N'T.[Id]'
END
END
-- Print out the script that will be run, useful for debugging you code
PRINT #SqlToExecute
EXEC sp_executesql #SqlToExecute,
N'#Values dbo.FlowStatus READONLY', #Values
END
GO
/*
--------------------------------------------
Now lets test it
-- Test Andrew
*/
DECLARE #flowStatusType AS dbo.FlowStatus
INSERT INTO #flowStatusType(MyId, SomeText)
VALUES(1, 'Test1'),
(2, 'Test2')
EXEC [dbo].[MyStoredProc] #SearchName = 'Andrew', #SortBy = 'Name', #Values = #flowStatusType
GO
-- Test Bob
DECLARE #flowStatusType AS dbo.FlowStatus
INSERT INTO #flowStatusType(MyId, SomeText)
VALUES(1, 'Test1'),
(2, 'Test2')
EXEC [dbo].[MyStoredProc] #SearchName = 'Bob', #SortBy = 'Name', #Values = #flowStatusType
GO
Its also worth noting that if you can just join on the #Values without needing dynamic SQL then that is sure to be less work.

Converting a Static SQL Query into Dynamic SQL on a Stored Procedure

I have written a Stored Procedure like this,
Alter PROCEDURE sp_bestReviewer_report
(
#StartingLetter AS VARCHAR(1),
#CountsReq AS DECIMAL(3),
#ReqRev AS INT
#RequiredColumn AS SYSNAME
)
AS
BEGIN
SELECT TOP(#ReqRev) #RequiredColumn, Count(Reviewer) AS Total FROM [reviews_not_sent] WHERE LEFT(Reviewer,1) = #StartingLetter
GROUP BY (Reviewer)
HAVING (Count(Reviewer) > #CountsReq OR Count(Reviewer) < #CountsReq)
ORDER BY
Total DESC;
END;
I am trying to pass #RequiredColumn (the required column) dynamically as a parameter to the stored procedure.
How Can I do this.
You need dynamic SQL to pass in a column name:
BEGIN
DECLARE #sql NVARCHAR(MAX);
SET #sql = '
SELECT TOP (#ReqRev) [RequiredColumn], Count(Reviewer) AS Total
FROM [reviews_not_sent]
WHERE LEFT(Reviewer, 1) = #StartingLetter
GROUP BY Reviewer
HAVING Count(Reviewer) <> #CountsReq
ORDER BY Total DESC
';
SET #sql = REPLACE(#sql, '[RequiredColumn]', QUOTENAME(#RequiredColumn));
EXEC sp_executesql #sql,
N'#ReqRev int, #StartingLetter VARCHAR(1), #CountsReq DECIMAL(3)',
#ReqRev=#ReqRev, #StartingLetter=#StartingLetter, #CountsReq=#CountsReq;
END;

SQL Server - Convert SQL to Stored Procedure

Suppose I have the following structure to a set of tables in my SQL Server (2012) DB:
StartDate: Col1: Col2: .... Coln:
And, the way the DBA set up the database (have no control over that - I only have query access), all the tables with this structure that I'd want to query have, say, names beginning with MyTbl....
So, I would like to create a query that queries ALL these tables at once to get data for a specific StartDate and I've done it using the following SQL:
declare #t table(tablename varchar(50))
declare #sql varchar(max)
set #sql = ''
insert into #t
SELECT t.name AS table_name FROM sys.tables AS t
WHERE t.name LIKE 'MyTbl%'
select #sql = #sql + 'Select ''' + tablename + ''' as Table_Name, t.* From ' + tablename +
' t where StartDate = ''2015-01-01'' +
' union ' from #t
Select #sql = substring(#sql, 1, len(#sql) - 6)
exec(#sql)
In other words:
Find all tables in my DB with names beginning with MyTbl
Query each table for any data with StartDate = '2015-01-01`
Union all those queries together to get one big dataset result
The SQL works perfectly, but I'm getting quite stuck in creating a stored procedure from this query that can take in a parameter for StartDate and I don't know enough about stored procedures to do this correctly.
How could I convert this into a stored procedure that takes a date in for StartDate (to replace the ''2015-01-01'' in the query)?
Any help / guidance would be GREATLY appreciated!!!
THANKS!!!
I noticed you were not looping through each table .. here is something I had put together
CREATE PROCEDURE get_tabledata (#date DATE)
AS
BEGIN
DECLARE #t TABLE (
id INT IDENTITY(1, 1)
,tablename VARCHAR(50)
)
DECLARE #id INT
DECLARE #tablename VARCHAR(max)
DECLARE #sql VARCHAR(max)
SET #sql = ''
INSERT INTO #t
SELECT t.NAME AS table_name
FROM sys.tables AS t
WHERE t.NAME LIKE 'MyTbl%'
SET #id = ##ROWCOUNT
IF (#id > 0)
BEGIN
WHILE (#id > 0)
BEGIN
SET #tablename = (
SELECT tablename
FROM #t
WHERE id = #id
)
SELECT #sql = #sql + 'Select ' + #tablename + ''' as Table_Name, t.* From ' + #tablename + ' t where StartDate = ' + '' + convert(VARCHAR, #date) + ''
SET #sql = #sql + ' union'
Set #id = #id -1;
END
SELECT #sql = substring(#sql, 1, len(#sql) - 6)
END
EXEC (#sql)
END
While it can be a little dense if you're not used to the styling Microsoft uses on these pages, the best place to start would be the Create Procedure documentation on MSDN
https://msdn.microsoft.com/en-us/library/ms187926.aspx
That said, creating a stored procedure is pretty straight forward. Here's a really simple procedure that takes a #startDate parameter and then just returns it back. This is just to illustrate how and where you define your parameters
create procedure dbo.MyProcedure
-- put your input parameters here
#StartDate date
as
--put the body of your procedure (i.e. everything you've written in your OP) here
select #StartDate
go
YOu'll notice however that if you run this twice in a row, you get an error, because it tries to build the same procedure again. Another thing which can come in handy is adding some code before your procedure which will basically check to see if it already exists, and if it does, alter the procedure rather than just blindly re-create it.
This is a snippet from a template I use quite often which handles all of that logic for you. The simplest way to use this is press CTRL-SHIFT-M, which brings up a dialogue to replace all those tags with values you provide.
use [<Database Name, sysname,>]
go
if not exists (select 1
from sys.procedures with(nolock)
where name = '<Procedure Name, sysname,>'
and [schema_id] = schema_id('<Schema, sysname,dbo>')
and type = 'P'
)
exec ('create procedure [<Schema, sysname,dbo>].[<Procedure Name, sysname,>]
as
select ''Procedure not defined.'' as ErrorDescription
return')
--Executed as dynamic SQL since SQL Server Management Studio considures the straight SQL code a syntax error for some reason on the create procedure statement
GO
alter procedure [<Schema, sysname,dbo>].[<Procedure Name, sysname,>]
<Parm 1 Name, sysname,include [#]> <Parm 1 Datatype, sysname,><Parm 1 Default, sql_variant,include [=] if used>,
<Parm 2 Name, sysname,include [#]> <Parm 2 Datatype, sysname,><Parm 2 Default, sql_variant,include [=] if used>
as
/*******************************************************************************************************
********************************************************************************************************/
---------------------------------------------
-- declare variables
---------------------------------------------
---------------------------------------------
-- create temp tables
---------------------------------------------
---------------------------------------------
-- set session variables
---------------------------------------------
set nocount on
---------------------------------------------
-- body of stored procedure
---------------------------------------------
return

SQL: How to make table name in stored procedure dynamic

I am pretty new to SQL Server and hope someone here can help me with this (I'm using QL Server 2008).
The following is a small procedure that works as intended.
Now I would like to use the same procedure to update multiple tables as all these tables have exactly the same column names and column formatting, the only difference is the 2nd part of the table name for which I added XXX below.
Can someone tell me how this could be made dynamic and also provide me some explanations on this ?
I cannot provide much more here as I wasn't sure about how to approach this - other than probably declaring #sql nvarchar(max) and wrapping the whole query in SET #sql = N'...' before executing it.
My stored procedure:
CREATE PROCEDURE [dbo].[Cal_UpdateTeam]
#team nvarchar(100),
#teamID int,
#notes nvarchar(1000),
#log nvarchar(100),
#admin varchar(50)
AS
BEGIN
SET NOCOUNT ON;
BEGIN
IF NOT EXISTS
(
SELECT *
FROM Cal_XXX
WHERE teamID = #teamID
)
INSERT INTO Cal_XXX
(
team,
teamID,
notes,
log,
admin
)
SELECT #team,
#teamID,
#notes,
#log,
#admin
ELSE
UPDATE Cal_XXX
SET team = #team,
teamID = #teamID,
notes = #notes,
log = #log,
admin = #admin
WHERE teamID = #teamID
END
END
Many thanks for any tips and advise on this, Mike.
you should wrap your sql query in an nvarchar and then execute that query as in the below example :
declare #sql nvarchar(max)
declare #TableName nvarchar(max)
set #TableName = 'mytable'
set #sql = 'Select * from ' + #TableName
Exec sp_executesql #sql
in SP you can use Temporary Tables fro example:
CREATE PROCEDURE SELECT_TABLE
#REQUEST_ID INT
AS
BEGIN
/*************************************
** Temporary table **
*************************************/
CREATE TABLE #SOURCE (
ID INT
, ID_PARENT INT
, NAME VARCHAR(200)
, SORT INT
..
..
)
IF #REQUEST_ID = 'YES' BEGIN
INSERT INTO #SOURCE SELECT * FROM SOURCE_A
END
ELSE BEGIN
INSERT INTO #SOURCE SELECT * FROM SOURCE_B
END
SELECT * FROM #SOURCE
.....
END
GO
in SP you can encapsulate other SPs with different table names like parameter:
CREATE PROCEDURE SELECT_FROM_TABLE_A
AS
BEGIN
SELECT * FROM SOURCE_A
END
GO
CREATE PROCEDURE SELECT_FROM_TABLE_B
AS
BEGIN
SELECT * FROM SOURCE_B
END
GO
CREATE PROCEDURE SELECT_TABLE
#REQUEST_ID INT
AS
BEGIN
/**********************************************
** Subrequest select **
**********************************************/
IF #REQUEST_ID = 'YES' BEGIN
-- Request SP fro Source A
EXEC SELECT_FROM_TABLE_A
END
ELSE
BEGIN
-- Request SP fro Source B
EXEC SELECT_FROM_TABLE_B
END
END
GO

Make a normal query from a stored procedure

Using VB6 and SQL Server 2000
I want to convert a stored procedure to normal query
Stored procedure:
Alter PROC [dbo].[proc_New]
#CCODE VARCHAR(100),
#EmpCode VARCHAR(100)
AS
BEGIN
DECLARE #ID VARCHAR (5)
DECLARE #Des VARCHAR(10)
DECLARE #SQL VARCHAR(1000)
DECLARE #Flag INT
SELECT #Flag=0
SELECT #SQL = 'SELECT PERSONID FROM T_PERSON WHERE '
IF #CCODE<>'All'
BEGIN
IF #Flag=1
BEGIN
SELECT #SQL = #SQL+' AND (CCODE IN ('''+#CCODE+'''))'
END
ELSE
BEGIN
SELECT #SQL = #SQL+' (CCODE IN ('''+#CCODE+'''))'
SELECT #Flag=1
END
END
IF #EMPCODE<>'All'
BEGIN
IF #Flag=1
BEGIN
SELECT #SQL = #SQL+' AND (EMPCODE IN ('''+#EMPCODE+'''))'
END
ELSE
BEGIN
SELECT #SQL = #SQL+' (EMPCODE IN ('''+#EMPCODE+'''))'
SELECT #Flag=1
END
END
IF #SQL = 'SELECT EmpCode FROM EMPMST WHERE ' SELECT #SQL = 'SELECT EmpCode FROM EMPMST'
INSERT INTO table EXEC(#SQL)
GO
Procedure Explanation...
I am passing 2 parameter values like emp_code or All and company_code or All.
In the 1st parameter (Emp_Code): if the value is "All" means then query return the all the emp_code or If the values is "001" then query return the "001" emp_code only
In the 2nd Parameter (Company_Code): if the value is "All" means then query return the all the emp_code for all the company (ex: IBM, SoftTech, etc) or If the value is "IBM" means then query return all the emp_code for that company (IBM)
Above stored procedure is working fine, but I want to convert into normal query.
Can anybody help me
Need query help
Below is the simpler query, please try with this:
SELECT PERSONID FROM T_PERSON WHERE
CCODE = (
CASE WHEN #CCODE = 'ALL' THEN CCODE
ELSE #CCODE END
)
AND
EMPCODE = (
CASE WHEN #EMPCODE = 'ALL' THEN EMPCODE
ELSE #EMPCODE
END
)
You can't directly do this in SQL outside of a stored procedure, your stored procedure has several if/else statements, no structure exists in sql queries to do this, if you want to achieve this you will need to build in sripting logic from the language accessing it with (i.e. c#/php/coldfusion/etc) and then perform the individual queries.
What Language are you calling the stored procedure from, or is this directly from the SQL server?
Edit: I have not used VB6 in a while so I don't remember how to write this in VB but you would basically be copying the logic from the stored procedure to build the query and then sending the query directly from VB not letting the stored procedure do it.
e.g.
Dim sql As String
If CCODE <> 'All'
sql = 'SELECT PERSONID FROM T_PERSON WHERE AND (CCODE IN (' & CCODE & '));'
{send the query to sql server}
End If