SQL Stored Procedure: Conditional Return - sql

Hi I want to create a simple stored proecudre which does the following:
Psudocode
#tempSelect = "SELECT * FROM Table"
if (#Param is NULL) then
exec #tempSelect
else
exec #tempSelect + ' WHERE id = ' + #Param + '
Is this method efficent? Thank you.

Try
select *
from table
where id=isnull(#param, id)

Select * from Table
Where (ID = #Param or #Param is null)
Or
Select * from Table
Where ID=Coalesce(#Param, ID)
[And if you are aiming for efficiency, replace * with the specific field you want to return.]

Yes - I certainly see nothing wrong with it. You could make it even simpler though:
Set NOCOUNT On;
if (#Param is NULL)
Select * From Table;
else
Select * From Table Where (ID=#Param);
Note: I'd probably spell out the fields, though.

Depending on the case, I would probably use dynamic SQL.
However you need to remember about SQL injection in case #param originates from a user, thats why you should never add a parameter directly to your sql.
In t-sql it would look something like (out of my head and untested ;):
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = N'
SELECT ...
FROM table t
WHERE 1 = 1' (
IF(#param IS NOT NULL)
SET #SQL = #SQL + '
AND t.id = #id'
... possibly more things added to the query ...
EXEC sp_executesql
#SQL
, '#id AS INT'
, #id = #Param
By doing this, you will get an optimized query plan for each case (and by using sp_executesql, the query cache will be used as well)
I would especially avoid the OR solution, if you check the query plans generated with the OR compared to one without, you will understand why.

Try this code:
CREATE PROCEDURE [dbo].[ProcedureName]
#Param varchar(50)
AS
BEGIN
declare #tempSelect nvarchar(max)
SET NOCOUNT ON;
set #tempSelect = 'SELECT Col1, Col2 FROM Table where Col1 <> '' '
if #Param <> ''
begin
set #resultSet = #resultSet + ''' and Col1='''+#Param1
end
EXEC(#resultSet)
END

Related

Dynamically choose table

There are two tables with the same structure (same columns, same column names, etc).
How can I design a query so that a certain table is queried from, depending on a variable?
DECLARE #MYVAR SMALLINT = 0;
DECLARE #TABLENAME VARCHAR(MAX);
SET #TABLENAME = CASE WHEN #MYVAR = 1 THEN 'TABLE1' ELSE 'TABLE2' END
SELECT #TABLENAME
-- HOW TO DYNAMICALLY SELECT TABLE NAME HERE?
SELECT TOP 1 * FROM #TABLENAME
Technet docs hint at maybe using a table alias here, but the examples don't show anything related to this.
As you mentioned, you need to build query dynamically and execute it
DECLARE #MYVAR SMALLINT = 0;
DECLARE #TABLENAME VARCHAR(MAX);
SET #TABLENAME = CASE WHEN #MYVAR = 1 THEN 'TABLE1' ELSE 'TABLE2' END
declare #sql = 'SELECT TOP 1 * FROM '+ quotename(#TABLENAME)
Exec (#sql) -- To execute the query that is built dynamically
Beside the obvious solution with dynamic SQL (which you would need especially if your column lists might not be the same) you can go like this:
DECLARE #tblName VARCHAR(100)='tbl1';
SELECT Col1, Col2, Col3
FROM tbl1
WHERE #tblName='tbl1'
UNION ALL
SELECT Col1, Col2, Col3
FROM tbl2
WHERE #tblName='tbl2'
The biggest advantage was, that this approach is inlineable, can be used as VIEW or better as inline TVF.
If you want to keep it in plain SQL (without the procedural part) it can be done like this:
SELECT * FROM TABLE1 WHERE #MYVAR = 1
UNION ALL
SELECT * FROM TABLE2 WHERE #MYVAR = 0
SQL Server should be smart enough to evaluate one of the conditions as "always false" and skip reading the other table. Consult EXPLAIN to confirm that.

Conditionally add where to the statement

I'm writiting a store procedure.
This procedure is getting 4 arguments which will be used in where clause. Problem is that these parameters can be empty.
I'm trying to write something like this:
select * from Books
If(#param1 <> "")
add where title =#param1
to the clause
But I have no idea how to make it. Is it even possible?
This type of query is called catch-all-query. There are several ways to do this, one of which is using combinations ofAND and OR conditions:
SELECT *
FROM Books
WHERE
(#param1 = '' OR title = #param1)
Another way is to use dynamic sql:
DECLARE #sql NVARCHAR(MAX) = ''
SELECT #sql = 'SELECT * FROM Books WHERE 1 = 1'
IF #param1 <> '' BEGIN
SELECT #sql = #sql + ' AND title = #param1'
END
EXEC sp_executesql
#sql,
N'#param1 VARCHAR(10)',
#param1 = #param1
Additional reading:
Erland Sommarskog's article on dynamic search conditions.
You can try like this
Select * from Books where (Title=#title or #title='')
select *
from Books
where (title = #param or #param = '')
If you want handle null in your parameter and want to include records where there is a null in the title field you can use
select *
from Books
where ISNULL(title,#)=ISNULL(#param,#)

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 stored procedure single quotes

I have a stored procedure as below
create procedure TestTry
BEGIN
declare #query varchar(max)
SET NOCOUNT ON;
set #query = 'select * from table1 when RECORD_FLAG <> 't'
then Convert(Decimal(10,4),ISNULL(T.HISTORY_PCR ,0)) else '0'';
exec (#query)
end
Here after RECORD_FLAG <> I want to give it in single quotes and also give 0 in single quotes how to give that
The above shown is a sample in real time my query is big I have to give the query in #query only
Use '' (double) for ' (single)
set #query = 'select * from table1 when RECORD_FLAG <> ''t''
then Convert(Decimal(10,4),ISNULL(T.HISTORY_PCR ,0)) else ''0''';
create procedure TestTry
AS --<-- you'er also missing AS key word here
BEGIN
SET NOCOUNT ON;
declare #query varchar(max)
set #query = 'select * from table1 when RECORD_FLAG <> ''t''
then Convert(Decimal(10,4),ISNULL(T.HISTORY_PCR ,0)) else ''0''';
EXECUTE sp_executesql #query --<-- use this syntax to execute dynamic sql
end
Also you do not need to use dynamic sql for such a simple query,
dynamic sql is the devil of sql and you want to avoid using it
whenever possible.
Your Query
Also your query syntax isnt right you are trying to execute a query as follows
select *
from table1
when RECORD_FLAG <> 't' --<-- cant use WHEN without the CASE statement also you
--cannot use a Case statement here right after your table name

How to specify a table dynamically in a Stored Procedure

Thanks for the feedback, but I was hoping for help with an UPDATE command, not SELECT.
Can anyone help with the syntax for an UPDATE command?
I am passing a table name into a Stored Procedure but the SQL does not seem to recognize it.
DECLARE #userTable AS VARCHAR(200);
SET #userTable = #currTable
UPDATE #userTable
SET [lang_String] = #lang_String, [date_Changed] = #submitDate1
WHERE (ID = #ID)
#currTable is passed into the Stored Procedure. All tables names are built by design in code.
You can't, you need to build the entire SQL string and then execute it, like this for example:
DECLARE #sql nvarchar(4000)
SELECT #sql = ' SELECT col1, col2, col3 ' +
' FROM dbo.' + quotename(#tblname) +
' WHERE keycol = #key'
EXEC sp_executesql #sql, N'#key varchar(10)', #key
Got this to work quite easily....
#myTable varchar(150)
/* Comments:
*/
AS
SET NOCOUNT ON;
DECLARE #sql varchar(max);
SET #sql = 'SELECT [ID], [StringID], [GUID] FROM ' + #myTable + ' ORDER BY [GUID]';
print (#sql)
EXECUTE(#sql);
SET #langTable = Null;
FYI, the values available for myTable are stored in another table and are not available to users for edit. Table names are built dynamically in code based on a unique combination of values.