Use LIKE in stored procedure with input parameter - sql

I have 2 input parameters and I want to search users where a part o the username is #Username and a part of the name is #Name that this users part of usernames is #Username and part of name is #Name
SELECT *
FROM tbl_answer
WHERE
an_del = 0
AND u_username = ISNULL(LIKE %#Username%, u_username) OR
u_name = ISNULL(LIKE #Name, u_name)
How I can use LIKE in this stored procedure?

CREATE PROC dbo.SearchAnswers
#Username nvarchar(20),
#Name nvarchar(20)
AS
SELECT *
FROM tbl_answer
WHERE an_del=0 and u_username LIKE '%' + ISNULL(#Username, u_username) + '%'
OR u_name LIKE ISNULL(#Name, u_name)
Example for a SQLServer2008

You need to use dynamic sql, for example sql server:
create procedure MyProc
(
#Username varchar(30),
#Name varchar(30)
)
as
begin
exec ('SELECT * from tbl_answer where an_del=0 and
u_username=isnull(like ''%'+#Username+'%'',u_username)
or u_name=isnull(like '''+#Name+''',u_name)')
end

Related

I want to make a vairable of table can i make it on Microsoft sql server management studio?

I want to make a variable of table in stored procedure to call the data from 3 diffrent tables like
i have the city name in textbox and a dropdown list with the values of tablenames,
I already make a stored procedure:
[dbo].[sp_Search]
#City nvarchar(50) = null
AS
SELECT * FROM PropertyForSale_TBL WHERE (City = #City OR #City IS NULL)
here this is the SP of only for the textbox not for the dropdownlist.
i want a procedure to make the tablename as a variable so when i select the dropdown it calls the data from that table.
like as i imagined its works like this maybe....
[dbo].[sp_Search]
#City nvarchar(50) = null,
#Tablename Table (maybe or maybe not i dont know it is not working)
AS
SELECT * FROM #Tablename WHERE (City = #City OR #City IS NULL)
how can i do this?????
You need to build a dynamic query as the table name can't be a variable. For this case you can use sp_executesql to run the dynamic query as shown below.
You can make it parameterized query using sp_executesql to avoid any SQL Injection threat.
create procedure [dbo].[sp_search]
#City nvarchar(50) = null,
#Tablename varchar(100)
as
begin
declare #sql nvarchar(max)
set #sql = N'SELECT * FROM ' + quotename(#Tablename)
+ ' WHERE (City = #City OR #City IS NULL)'
exec sp_executesql
#sql,
N'#City nvarchar(50)',
#City
end
You can build dynamic SQL and execute it
Here's a quick example (note there are multiple ways to execute dynamic SQL and each have their own benefits and draw-backs, do a little research)
DECLARE #City NVARCHAR(50) = 'New York'
, #TableName VARCHAR(100) = 'PropertyForSale_TBL'
DECLARE #SQL NVARCHAR(MAX) =
'SELECT * FROM ' + QUOTENAME(#Tablename) + ' WHERE [City] = ''' + #City + ''''
PRINT #SQL -- SELECT * FROM [PropertyForSale_TBL] WHERE [City] = 'New York'
EXEC (#SQL)
Edit: Also just a note dynamic code is usually not the best idea. The above opens yourself up to SQL injection and other headaches. Have a look at your database structure and see whether the data can be put in the same tables, IF statements and temp tables used, or multiple stored procedures.

Writing a Stored procedure to search for matching values in columns with optional Input parameters

Requirement: To write stored Procedure(s) such that the values passed in stored procedures are matched against the values in columns in the table and then arranged with highest to lowest matching number of attributes.Then are inserted in a dynamically created temporary table inside the stored procedure.
Problem:
I have say 15-20 attributes that are matched against to confirm the suggestions made in response to record search. Basically, There is a table that stores Patients information and multiple parameters may be passed into the stored procedure to search through so that a Temporary table is created that suggests records in decreasing order of matching attributes.
To frame the basic structure, I tried with 3 attributes and respective stored procedures to match them which in turn are collectively called from a calling procedure based on the input parameter list which in turn creates the required temporary table.
Here is the SQL code(Just to give the gist of what I have tried so far):
But as a matter of fact it is, I realize this is way too naive to be used in a real time application which may require 80-90% of accuracy.So, what exactly can replace this technique for better efficiency?
Create Procedure NameMatch
(
#Name nvarchar(20),
#PercentContribution nvarchar(4) OUT, #PatientName nvarchar(20) out
)
As
declare #temp int
DECLARE #Query nvarchar(500)
if Exists(select Name from dbo.PatientDetails where Name = #Name)
Begin
set #PatientName = #Name
set #query = 'select * from dbo.PatientDetails where Name =' + #Name
set #temp = 0.1*100
set #PercentContribution = #temp + '%'
Execute(#query)
Return
End
Create Procedure AgeMatch
(
#Name nvarchar(20),
#Age int,
#PercentContribution nvarchar(4) OUT, #PatientName nvarchar(20) out
)
As
declare #temp int
DECLARE #Query nvarchar(500)
if Exists(select Name from dbo.PatientDetails where Name =#Name and Age = + #Age)
Begin
set #PatientName = #Name
set #query = 'select * from dbo.PatientDetails where Name = ' + #Name + ' and Age = '+ #Age
set #temp = 0.2*100
set #PercentContribution = #temp + '%'
Execute(#query)
Return
End
Create Procedure Nationality
(
#Name nvarchar(20),
#Age int,
#Nation nvarchar(10),
#PercentContribution nvarchar(4) OUT, #PatientName nvarchar(20) out
)
As
declare #temp int
DECLARE #Query nvarchar(500)
if Exists(select Name from dbo.PatientDetails where Name = #Name and Age = #Age and Nationality = #Nation )
Begin
set #PatientName = #Name
set #query = 'select * from dbo.PatientDetails where Name = ' + #Name + ' and Age = '+ #Age + ' and Nationality = ' + #Nation
set #temp = 0.3*100
set #PercentContribution = #temp + '%'
Execute(#query)
Return
End
create procedure CallingProcedure
(
#Name nvarchar(20),
#Age int = null,
#Nation nvarchar(10)= null
)
As
declare #PercentMatch nvarchar(4)
Begin
create table #results(PatientName nvarchar(30), PercentMatch nvarchar(4))
if(#Nation IS NOT NULL)
Insert into #results exec Nationality #Nation, #Name output, #PercentMatch output
else if(#Age is not Null)
Insert into #results exec AgeMatch #Age, #Name output, #PercentMatch output
else
Insert into #results exec NameMatch #Name, #Name output, #PercentMatch output
End
Setting aside nuances of stored procedure syntax, given parameters 1-n that if not null should match columns 1-n and the results sorted by highest number of matches first, a dynamic query is not needed - plain SQL can do it.
select *
from patient
where #param1 is null or column1 = #param1
or #param2 is null or column2 = #param2
...
or #paramN is null or columnN = #paramN
order by if(column1 = #param1, 1, 0)
+ if(column2 = #param2, 1, 0)
...
+ if(columnN = #paramN, 1, 0) desc

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

Execute sp_executesql

Table called Emp contain id,name,lname,birthdate,address and salery .I want to select from emp.
Basic query : select * from emp
If pass the value for lname ,query : select * from emp where lname = 'fgfg' like this.
So I created following sp.
create Procedure Proc_selectEmp
(
#name varchar(10) = null,
#lname varchar(10) = null,
#id varchar(10) = null
)
as
begin
select * from Emp
where
(#name is null or name = #name)
and (#lname is null or lname = #lname)
and (#id is null or id = #id)
end
Like emp,there are 13 table having same column name.
So my tablenmae is also dynamic.That's why, I choose execute sp_executesql.Can I create like this
create Procedure Proc_selectEmp
(
#name varchar(10) = null,
#lname varchar(10) = null,
#id varchar(10) = null
#tableName varchar(30)
)
as
begin
declare #query nvarchar(1000)
set #query = #query +'select * from '+#tableName+'
where ('+#name+' is null or name = '+#name+')
and ('+#lname+' is null or lname = '+#lname+')
and ('+#id+' is null or id = '+#id+')
end'
execute sp_executesql #query
It will work, although is pretty smelly, given that it requires that it requires that table name is a variable and thus tables must have the same column definitions.
Also, rather than including the #param is null or column = #param, rather, leave out unnecessary filters entirely, which is easy to do since you are using dynamic sql. This will avoid the parameter sniffing problem.
Lastly, instead of appending the column filters into the string, rather use the parameterized overload of sp_executesql, which will protect your from SQL injection attacks, and handle the escaping of quotes etc for you. Unfortunately, #tablename can't be parameterized, but hopefully? this isn't a user or foreign-supplied variable (in which case you will need to do some more thinking about design and or validation techniques).
i.e.
declare #query nvarchar(max)
set #query = N'select * from ' + #tableName + N` where (1=1)`
if (#name is not null)
set #query = #query + N'and name = #name'
-- ... same for #id and #lname
exec sp_executesql #SQL,
N'#name varchar(10),
#lname varchar(10),
#id varchar(10)',
#name = #name,
#lname = #lname,
#id = #id
Edit
Re : securing un-parameterizable inputs like table or column names in dynamic sql - see this post here for ideas - use of QUOTENAME and white-listing column / table names are prominent.
Yes you can but you have to write
EXECUTE(#query)
Instead of
execute sp_executesql #query

script to dynamically fix ophaned users after db restore

After performing a database restore, I want to run a dynamic script to fix ophaned users. My script below loops through all users that are displayed after executing sp_change_users_login 'report' and applys an "alter user [username] with login = [username]" statement to fix SID conflicts. I'm getting an "incorrect syntax error on line 15" and can't figure out why...help..
DECLARE #Username varchar(100), #cmd varchar(100)
DECLARE userLogin_cursor CURSOR FAST_FORWARD
FOR
SELECT UserName = name FROM sysusers
WHERE issqluser = 1 and (sid IS NOT NULL AND sid <> 0×0)
AND suser_sname(sid) IS NULL
ORDER BY name
FOR READ ONLY
OPEN userLogin_cursor
FETCH NEXT FROM userLogin_cursor INTO #Username
WHILE ##fetch_status = 0
BEGIN
SET #cmd = ‘ALTER USER ‘+#username+‘ WITH LOGIN ‘+#username
EXECUTE(#cmd)
FETCH NEXT FROM userLogin_cursor INTO #Username
END
CLOSE userLogin_cursor
DEALLOCATE userLogin_cursor
Orphaned users can be fixed by using the [dbo].[sp_change_users_login] stored procedure.
Loop through all your users and execute the procedure
Good Luck
DECLARE #UserCount INT
DECLARE #UserCurr INT
DECLARE #userName VARCHAR(100)
DECLARE #vsql NVARCHAR(4000)
DECLARE #Users TABLE(
id INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
userName VARCHAR(100))
INSERT INTO #Users(UserName)
SELECT [name] FROM
--
master.[dbo].sysUsers -- SQL 2008 & SQL 2005
--master.dbo.sysxlogins -- SQL 2000
SELECT #UserCount = max([id]) FROM #Users
SET #UserCurr = 1
WHILE (#UserCurr <= #UserCount)
BEGIN
SELECT #userName=userName FROM #Users WHERE [id] =#UserCurr
SET #vsql = '[dbo].[sp_change_users_login] ''AUTO_FIX'',''' + #userName + ''''
-- EXEC(#vsql)
PRINT #vsql
SET #UserCurr = #UserCurr + 1
END
DECLARE #Username VARCHAR(100),
#cmd VARCHAR(100)
DECLARE userlogin_cursor CURSOR FAST_FORWARD FOR
SELECT username = name
FROM sysusers
WHERE issqluser = 1
AND (sid IS NOT NULL
AND sid <> 0x01)
AND Suser_sname(sid) IS NULL
ORDER BY name
FOR READ ONLY
OPEN userlogin_cursor
FETCH NEXT FROM userlogin_cursor INTO #Username
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd = 'ALTER USER [' + #username + '] WITH LOGIN = [' + #username + ']'
EXECUTE(#cmd)
FETCH NEXT FROM userlogin_cursor INTO #Username
END
CLOSE userlogin_cursor
DEALLOCATE userlogin_cursor
I've used a similar approach, wrapping the code in a stored procedure:
USE [master]
GO
CREATE PROCEDURE [sp_AutoFixAllUsers]
AS
BEGIN
DECLARE #AutoFixCommand NVARCHAR(MAX)
SET #AutoFixCommand = ''
SELECT --dp.[name], dp.[sid] AS [DatabaseSID], sp.[sid] AS [ServerSID],
#AutoFixCommand = #AutoFixCommand + ' '
+ 'EXEC sp_change_users_login ''Auto_Fix'', ''' + dp.[name] + ''';'-- AS [AutoFixCommand]
FROM sys.database_principals dp
INNER JOIN sys.server_principals sp
ON dp.[name] = sp.[name] COLLATE DATABASE_DEFAULT
WHERE dp.[type_desc] IN ('SQL_USER', 'WINDOWS_USER', 'WINDOWS_GROUP')
AND sp.[type_desc] IN ('SQL_LOGIN', 'WINDOWS_LOGIN', 'WINDOWS_GROUP')
AND dp.[sid] <> sp.[sid]
IF (#AutoFixCommand <> '')
BEGIN
PRINT 'Fixing users in database: ' + DB_NAME()
PRINT #AutoFixCommand
EXEC(#AutoFixCommand)
PRINT ''
END
END
GO
I then used the sys.sp_MS_marksystemobject stored procedure to make my stored procedure available in all user databases (allowing it to operate on local objects)
EXEC sys.sp_MS_marksystemobject 'sp_AutoFixAllUsers'
You can then run it as follows:
EXEC [MyDB].[dbo].[sp_AutoFixAllUsers]
Or for every database using sp_msforeachdb:
EXEC sp_msforeachdb '[?].[dbo].[sp_AutoFixAllUsers]'