Using SQL variable in like statement - sql

I have done much research on this but just cannot get it right. I am trying to query an audit trail using the below:
declare #batchid char (30)
select #batchid='13857584' --enter batch id here
declare #occurred int
select #occurred='5'
print 'Batch is in system, check MRN and encounter. User also noted below'
select a.encounter, a.mrn, a.facility, c.fullname, t.action_desc, a.occurred, a.remark
from audit..audit_trail a (nolock)
join cabinet..users c (nolock)
on a.userinstanceid=c.userinstanceid
join audit..action_table t (nolock)
on a.action=t.action
where a.REMARK like '%' + #batchid + '%'
and OCCURRED > GETDATE()-#occurred
order by a.occurred
for some reason it will never return the results i want (no results). But when i run it specifically for the batch id like below (instead of #batchid)
declare #batchid char (30)
select #batchid='13857584' --enter batch id here
declare #occurred int
select #occurred='5'
print 'Batch is in system, check MRN and encounter. User also noted below'
select a.encounter, a.mrn, a.facility, c.fullname, t.action_desc, a.occurred, a.remark
from audit..audit_trail a (nolock)
join cabinet..users c (nolock)
on a.userinstanceid=c.userinstanceid
join audit..action_table t (nolock)
on a.action=t.action
where a.REMARK like '%' + '13857584' + '%'
and OCCURRED > GETDATE()-#occurred
order by a.occurred
it works perfectly. I tried adding quotes after and before percentage signs but i just cant get it right. Any help appreciated. SQL 2008

You care declaring batchid as a char:
declare #batchid char (30)
select #batchid='13857584' --enter batch id here
In fact, the batchid is being set to something like:
'13857584______________________'
The underscores are intended to show the space character, not an actual underscore.
Try changing it to varchar():
declare #batchid varchar(30);
select #batchid = '13857584'; --enter batch id here

Related

The identifier that starts with (query) Maximum length is 128

Problem: I am using a sp on sql server where I took parameter which modify the query and then run the full query in the server. While I am passing that parameter to sp then it says: "The identifier that starts with 'WHERE d.LastModified<1676270281779 AND (p.ProductName LIKE '%2004%' OR p.ProductBarcode LIKE '%2004%') AND d.SupplierId='SUP-001' is too long. Maximum length is 128."
THE QUERY:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[get_SupComProducts] #whereClause NVARCHAR(max)
AS
BEGIN
DECLARE #query NVARCHAR(max)
, #status VARCHAR(25);
SET #status = 'IN'
SET #query = 'SELECT DISTINCT
p.ProductId,
p.CompanyId,
p.ProductName,
p.ProductGrossWeight,
p.ProductNetWeight,
p.ProductUnit,
p.CategoryId,
p.BrandId,
p.ProductBarcode,
p.MinShelfLife,
p.ProductMargin,
p.IsWeighted,
p.PVAT,
p.ProductMargin,
p.AFSProduct,
ISNULL(sp.ProductBarcode, 0) AS Barcode,
ISNULL(sp.CostPrice, 0) AS CostPrice,
ISNULL(sp.TradePrice, 0) AS TradePrice,
ISNULL(sp.MRP, 0) AS MRP,
ISNULL(sp.SellingPrice, 0) AS SellingPrice,
ISNULL(sp.VAT, 0) AS VAT,
ISNULL((
SELECT SUM(ProductQty) AS ProductQty
FROM StockDetails
WHERE ProductId = p.ProductId AND [Status]= ''' + #status + '''' +
'),0) AS CurrentStock
FROM Supplier d
JOIN Product p
ON p.CompanyId = d.CompanyId
LEFT JOIN StockDetails sd
ON sd.ProductId = p.ProductId
LEFT JOIN SupplierProduct sp
ON sp.ProductId = p.ProductId ' + #whereClause
EXEC (#query)
END
GO
Please if there are any resolve you guys know already, it will be much appreciable. Thanks in advance.
SP EXEC:
EXEC [dbo].[get_SupComProducts] #whereClause="WHERE d.LastModified<1676270281779 AND (p.ProductName LIKE '%2004%' OR p.ProductBarcode LIKE '%2004%') AND d.SupplierId='SUP-00123'"
If I remove any of the AND query then it works, but the full query says the error.
Msg 103, Level 15, State 4, Line 1
The identifier that starts with 'WHERE d.LastModified<1676270281779 AND (p.ProductName LIKE '%2004%' OR p.ProductBarcode LIKE '%2004%') AND d.SupplierId='SUP-001' is too long. Maximum length is 128.
While there might be issues with your procedure, this particular one comes from the way you call it. Double quotes in SQL, by default, designate object names, and in MS SQL Server, maximum length for any object name is 128 characters. That's where you are getting this error, I suspect.
So, in your sp call, you need to replace your double quotes with single ones, and appropriately escape all single quotes inside it. Something like this:
EXEC [dbo].[get_SupComProducts] #whereClause = '
WHERE
d.LastModified<1676270281779 AND (
p.ProductName LIKE ''%2004%''
OR p.ProductBarcode LIKE ''%2004%''
) AND d.SupplierId=''SUP-00123''
';

SQL 2005 Carriage Return in Select Statement resulting in data wrap

Here is my query.
select
a.LoanNumber,
u.Comments,
From
LoanApp as a
LEFT JOIN Summary as u on a.id = u.loanapp_id
inner join temploannumber as t on a.LoanNumber = t.loannumber
order by a.LoanNumber
My issue is Comments field is a text field which contains carriage returns. Query results looks like this:
12345 This is a test
Test failed for this loan.
23456 This is a test. Test was successful.
34567 This is a test.
Test failed for this loan.
Test failed again for this loan.
How can I remove the carriage return just in the select statement to look like the following without data wrap? I do not want to affect the data stored in the database.
12345 This is a test. Test failed for this loan.
23456 This is a test. Test was successful.
34567 This is a test. Test failed for this loan. Test failed again for this loan.
I also have a function that you could use that removes all control characters, but you may not have rights to create functions. I don't remember where I found this code, but I'm sure you could find it somewhere.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[RemoveNonDisplayChars]
(#pString VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN
--===== Declare Local variables
DECLARE #IncorrectCharLoc SMALLINT, --Position of bad character
#Pattern CHAR(37) --Bad characters to look for
SELECT #Pattern = '%['
+ CHAR(0)+CHAR(1)+CHAR(2)+CHAR(3)+CHAR(4)
+ CHAR(5)+CHAR(6)+CHAR(7)+CHAR(8)+CHAR(9)
+ CHAR(10)+CHAR(11)+CHAR(12)+CHAR(13)+CHAR(14)
+ CHAR(15)+CHAR(16)+CHAR(17)+CHAR(18)+CHAR(19)
+ CHAR(20)+CHAR(21)+CHAR(22)+CHAR(23)+CHAR(24)
+ CHAR(25)+CHAR(26)+CHAR(27)+CHAR(28)+CHAR(29)
+ CHAR(30)+CHAR(31)+CHAR(127)
+ ']%',
#IncorrectCharLoc = PATINDEX(#Pattern, #pString)
WHILE #IncorrectCharLoc > 0
SELECT #pString = STUFF(#pString, #IncorrectCharLoc, 1, ''),
#IncorrectCharLoc = PATINDEX(#Pattern, #pString)
RETURN #pString
END
Then just execute the function against it.
select a.LoanNumber, RemoveNonDisplayChars(u.Comments)
From LoanApp as a
LEFT JOIN Summary as u on a.id = u.loanapp_id
inner join temploannumber as t on a.LoanNumber = t.loannumber
order by a.LoanNumber
Good luck!
Try this. It replaces newlines and carriage returns with an empty string.
select a.LoanNumber, REPLACE(REPLACE(u.Comments, char(13), ''), char(10), '')
From LoanApp as a
LEFT JOIN Summary as u on a.id = u.loanapp_id
inner join temploannumber as t on a.LoanNumber = t.loannumber
order by a.LoanNumber

SQL Server Free Text search: search words from a phrase in two tables

I have a table with companies and one with categories. I'm using SQL Server Free Text search, and searching companies (by name and description) works fine. But now I also want to include the category table.
I want to search for something like: ABC 24 Supermarket.
Now, ABC 24 should make a match with the Name column in the company table, and Supermarket is the name of the category this company is connected to.
Right now I have something like this:
DECLARE #SearchString VARCHAR(100) = '"ABC 24 Supermarket"'
SELECT * FROM Company CO
INNER JOIN Category CA
ON CA.CategoryId = CO.CategoryId
WHERE CONTAINS((CO.[Description], CO.[Name]), #SearchString)
AND CONTAINS(CA.[Description], #SearchString)
But this of course, gives me nothing, because my search string cannot be found in either the company or the category table. Does anyone have an idea on how to do a combined search on my company and category table?
The idea of splitting strings, as suggested in Lobo's answer below, is not really an option. Because i don't know which part will be the one that should match a category and which part should be used for matching company names/descriptions. Users might just as well type in "Supermarket ABC 24".
Imho the right way to do this is to create an indexed view containing the primary key of the main table ('company' in your example) and a second column containing all the stuff you're actually want to search, i.e.
create View View_FreeTextHelper with schemabinding as
select CO.PrimaryKey, -- or whatever your PK is named
CO.description +' '+CA.description +' '+CO.whatever as Searchtext
from dbo.company CO join
dbo.category CA on CA.CategoryId = CO.CategoryId
Note the two-part form of your tables. A few restrictions arise from this, e.g. all involved tables must be in the same table space and as far as I remember, no TEXT columns are allowed in this kind of concatenation (you may cast them though).
Now create a unique index on the PrimaryKey column
create unique clustered index [View_Index]
on View_FreeTextHelper (PrimaryKey ASC)
Finally create the fulltext index on the view using the 'Searchtext' column as the only column to index. Of course, you may add more columns, if you e.g. wish to distinguish in searching for company name and location and, the names of the managers (you would just concatenate them in a second column).
Retrieving your data is now easy:
select tbl.RANK,
co.*
from freetextTable(View_FreeTextHelper,Search,'Your searchtext here') tbl
join company co on tbl.key=co.PrimaryKey
order by tbl.RANK desc
You may also limit the output using select top 50 as the freetexttable clause will eventually return quite a lot of close and not so close results.
And finally, don't get confused if you cannot find thing like 'off the shelf inc.' Beware of the stop lists. These are list of words which are very common, have no semantic use (like the) and are therefore removed from the text to be indexed. In order to include them, you have to switch of the stoplist feature.
A last tipp: full text is very powerful but has a lot of features, tricks and caveats. It takes quite a bit to fully understand the techniques and get the best results you want.
Have fun.
If we assume that the name of columns are unique per row, then you can use below query. The following example returns all rows that contain either the phrase "ABC", "24" or "Supermarket" in each of the columns
DECLARE #SearchString nvarchar(100) = N'ABC 24 Supermarket'
SET #SearchString = REPLACE(LTRIM(RTRIM(#SearchString)), ' ', '|')
SELECT *
FROM Company CO JOIN Category CA ON CA.CategoryId = CO.CategoryId
WHERE CONTAINS(CO.[Name], #SearchString)
AND CONTAINS(CO.[Description], #SearchString)
AND CONTAINS(CA.[Description], #SearchString)
First of all you need to prepare a search value for the CONTAINS predicate used in the WHERE clause. In this case I replaced spaces between the words on the "|" logic operator(the bar symbol (|) may be used instead of the OR keyword to represent the OR operator.)
It occurs to me that while the answer I wrote previously should work fine and be reasonably efficient, processing the search items one-at-a-time and only searching within the existing search result for items after the first, that it would be faster to do it all at once, using dynamic sql.
So here is another potential solution to your problem, which I enter as a separate answer as it is unrelated to the solution I've already posted:
DECLARE #SearchString VARCHAR(100) = '"ABC 24 Supermarket"'
DECLARE #AllItems table (
SearchItem varchar(100)
),
#x int,
#cmd varchar(1000),
#wc varchar(8000),
#this varchar(100);
-- break up #SearchString into component search items:
select #x = charindex(' ', #SearchString);
while #x > 0 begin
insert #AllItems (SearchItem) values (substring(#SearchString, 1, #x - 1));
select #SearchString = substring(#searchstring, #x + 1);
select #x = charindex(' ', #Searchstring);
end;
-- add the last item
insert #AllItems (SearchItem) values (#SearchString)
select #cmd = 'select CO.* from Company CO inner join Category CA on CO.CategoryId = CA.CategoryId WHERE';
--now process search items one-at-a-time building up a where clause to plug into #cmd:
while (select count(*) from #AllItems) > 0 begin
select #this = min(SearchItem) from #AllItems;
delete #AllItems where SearchItem = #this;
select #wc = #wc +
'AND (contains ((CO.[Description], [CO.[Name]) ''' + #this + ''') or contains (CA.[Description], ''' + #this + ''') '
end;
--ready to go:
exec (#cmd + substring(#wc, 4)); --substring removes first AND
I dont know whether this will constitute a GREAT answer (I tend to doubt it) but I wanted a problem to work on and I happed to pick yours, so here's my solution:
DECLARE #SearchString VARCHAR(100) = '"ABC 24 Supermarket"'
DECLARE #AllItems table (
SearchItem varchar(100)
),
#x int;
-- break up #SearchString into component search items:
select #x = charindex(' ', #SearchString);
while #x > 0 begin
insert #AllItems (SearchItem) values (substring(#SearchString, 1, #x - 1));
select #SearchString = substring(#searchstring, #x + 1);
select #x = charindex(' ', #Searchstring);
end;
-- add the last item
insert #AllItems (SearchItem) values (#SearchString)
DECLARE #this varchar(100), -- = current search item
#found table ( -- table to contain rows matching the current search item
ID int
),
#usable table ( -- table to contain rows matching all search items
ID int -- already tested
);
--now process search items one-at-a-time
while (select count(*) from #AllItems) > 0 begin
select #this = min(SearchItem) from #AllItems;
delete #AllItems where SearchItem = #this;
if (select count(*) from #usable) = 0 begin --first search item
--for the first item, just find the companies matching this item, in either the
--company name or description or category description columns:
insert #found (ID)
select CO.CompanyID
from Company CO inner join Category CA on CO.CategoryID = CA.CategoryID
where contains ((CO.[Description], [CO.[Name]) #this)
or contains (CA.[Description], #this)
end
else begin --other search items
-- for subsequent items, its got to match with the company name or description
-- or category description as above - BUT it's also got to be a company we
-- already identified when processing the previous term
insert #found (ID)
select CO.CompanyID
from Company CO inner join Category CA on CO.CategoryID = CA.CategoryID inner join #usable U on CO.CompanyID = U.ID
where contains ((CO.[Description], [CO.[Name]) #this)
or contains (CA.[Description], #this)
end
--now clear out and re-populate the usable companies table ready for processing the
--next search item
delete #usable;
insert #usable (ID)
select ID
from #found;
--and clear out the current matches table, ready for the next search item
delete #found;
end;
--whatever is in #usable now, is a match with all the component search items, so:
select CO.*
from Company CO inner join Category CA on CO.CategoryId = CA.CategoryId inner join #usable U on CO.CompanyID = U.ID;
The idea here is that we are going to parse the string into different variables then search the other variables for a match.
DECLARE #SearchString VARCHAR(100) = '"ABC 24 Supermarket"', #A varchar(100), #B varchar(100), #C varchar(100),#index int
set #A = Substring(#searchString, 1, PATINDEX('% %', #searchString) -1)
set #index = PATINDEX('% %', #searchString) + 1
set #B = Substring(#searchString, #index, PATINDEX('% %', #substring(#searchstring, #index, 100)) -1)
Set #index = PATINDEX('% %', #substring(#searchstring, #index, 100)) + 1
set #C = Substring(#searchString, #index, PATINDEX('% %', #substring(#searchstring, #index, 100)) -1)
SELECT * FROM Company CO
INNER JOIN Category CA
ON CA.CategoryId = CO.CategoryId
WHERE CO.[Description] like #A
or CO.[Description] like #B
or CO.[Description] like #c
or CO.[Name] like #A
or CO.[Name] like #B
or CO.[Name] like #C
or CA.[Description] like #A
or CA.[Description] like #B
or CA.[Description] like #C
This code looks ugly to me but it should accomplish the requirements for the user entering up to 3 items to search on. Anyone have suggestions on cleaning it up?
this should work.
DECLARE #SearchString VARCHAR(100) = '"ABC 24 Supermarket"'
set #SearchString = replace(#SearchString,' ','" or "')
SELECT * FROM Company CO
INNER JOIN Category CA
ON CA.CategoryId = CO.CategoryId
WHERE CONTAINS((CO.[Description], CO.[Name]), #SearchString)
AND CONTAINS(CA.[Description], #SearchString)
hope helps a bit
Why don't you just reverse your logic? Your example was trying to find the search string within your field values, but what you really want to do is find your field values within your search string, no?
DECLARE #SearchString VARCHAR(100) = '"ABC 24 Supermarket"'
SELECT * FROM Company CO
INNER JOIN Category CA
ON CA.CategoryId = CO.CategoryId
WHERE (CONTAINS(#SearchString, CO.[Description]) OR CONTAINS(#SearchString, CO.[Name]))
AND CONTAINS(#SearchString, CA.[Description])
( I don't have sql-server installation to try CONTAINS. You can replace the column LIKE '%string%' with CONTAINS(column, 'string') and try.)
See all queries here.
Another update - After reading the other answers and the manual, it seems that you don't need parenthesized values in the contains string unlike I expected. So this should work too - (you may even try ' | ' instead of ' OR '
SELECT CO.name, CA.description FROM company CO
INNER JOIN category CA
ON CA.CategoryId = CO.CategoryId
WHERE CONTAINS((CO.name,CO.description), REPLACE('ABC 25 SuperMarket', ' ', ' OR '))
AND
CONTAINS(CA.description, REPLACE('ABC 25 SuperMarket', ' ', ' OR '))
If it complains about syntax error near replace, you can create a search string DECLARE #SearchString varchar(MAX) = REPLACE('ABC 25 SuperMarket',' ', ' OR ') and then use it in place of replace(......) as second argument.
Update as per your modified question -
Firstly, you should be moving the logic to application level if possible. I think, it is too much to handle it here. I have come up with this query, but note that this will split each word and search for it in both name and description so you will end up getting a few more results than what you might think. For e.g. this will return all Supermarket which have either ABC or 24 in their name compared to returning only one Supermarket with name ABC 24 in my previous query. This should actually help you out because, as per you, user might just type "ABC Supermarket 24" or "24 ABC Supermarket" or ...
DECLARE #SearchString varchar(MAX) = 'ABC 24 SuperMarket'
DECLARE #separator varchar(MAX) = ' '
DECLARE #Like1 varchar(MAX) = 'CO.name LIKE'
DECLARE #Like2 varchar(MAX) = 'CA.description LIKE'
DECLARE #WHERE1 varchar(MAX) = '( ' + #Like1 + ' ''%' +
REPLACE(#SearchString,#separator,'%'' OR ' + #Like1 + ' ''%')+'%'')'
DECLARE #WHERE2 varchar(MAX) = '( ' + #Like2 + ' ''%' +
REPLACE(#SearchString,#separator,'%'' OR ' + #Like2 + ' ''%')+'%'')'
DECLARE #QueryString varchar(MAX) =
CONCAT('SELECT CO.name, CA.description FROM company CO
INNER JOIN category CA
ON CA.CategoryId = CO.CategoryId
WHERE ', #WHERE1, ' AND ', #WHERE2)
exec(#QueryString);
If you output #WHERE1 you should see
( CO.name LIKE '%ABC%' OR CO.name LIKE '%25%' OR CO.name LIKE '%SuperMarket%')
As I said before you might want to try using CONTAINS with parenthesized values like
DECLARE #SearchString varchar(MAX) = 'ABC 25 SuperMarket'
DECLARE #separator varchar(MAX) = ' '
DECLARE #WHEREString varchar(MAX) = '''"' +
REPLACE(#SearchString, #separator, '" OR "')+'"'''
SELECT CO.name, CA.description FROM company CO
INNER JOIN category CA
ON CA.CategoryId = CO.CategoryId
WHERE CONTAINS((CO.name,CO.description), #WHEREString)
AND
CONTAINS(CA.description, #WHEREString)
If you output #WHEREString you should see
'"ABC" OR "25" OR "SuperMarket"'
Previous answer:
This will assumes that the word after the last space is the description and rest is the `name.
You can split the search string and use them as shown below. This query is using like as I don't have a sql-server installation.
DECLARE #SearchString VARCHAR(100) = 'ABC 24 Supermarket'
DECLARE #searchLength int = len(#SearchString)
DECLARE #searchReverse VARCHAR(100) = reverse(#SearchString)
SELECT CO.name, CA.description FROM company CO
INNER JOIN category CA
ON CA.CategoryId = CO.CategoryId
WHERE CO.name LIKE concat( '%', SUBSTRING(#SearchString,0,#searchLength-charindex(' ',#searchReverse)+1), '%')
AND
CA.description LIKE concat( '%', SUBSTRING(#SearchString,#searchLength-charindex(' ',#searchReverse)+2,#searchLength), '%')
This should work. Please note that the where clause is using AND instead of OR.
DECLARE #SearchString VARCHAR(100) = 'ABC 24 Supermarket'
DECLARE #searchLength int = len(#SearchString)
DECLARE #searchReverse VARCHAR(100) = reverse(#SearchString)
DECLARE #company VARCHAR(100) = SUBSTRING(#SearchString,0,#searchLength-charindex(' ',#searchReverse)+1)
DECLARE #category VARCHAR(100) = SUBSTRING(#SearchString,#searchLength-charindex(' ',#searchReverse)+2,#searchLength)
SELECT CO.name, CA.description FROM company CO
INNER JOIN category CA
ON CA.CategoryId = CO.CategoryId
WHERE CONTAINS((CO.name, CO.description), #company)
AND
CONTAINS(CA.description , #category)
you can use FREETEXT instead of CONTAIN.
DECLARE #SearchString VARCHAR(100) = '"ABC 24 Supermarket"'
SELECT * FROM Company CO
INNER JOIN Category CA
ON CA.CategoryId = CO.CategoryId
WHERE FREETEXT((CO.[Description], CO.[Name]), #SearchString)
OR FREETEXT(CA.[Description], #SearchString)

Like operator on input parameters in stored procedure

I've just begun to add writing stored procedures to my SQL repertoire and I'm sure this is a noob question. Can someone point me in the right direction about how to use the like operator instead of the = operator in this scenario? The object of this is to find the first 3 common numbers out of a potential 5 digit number
stored procedure:
create proc dbo.MultipleDrugs (#condition varchar(50))
as
SELECT *, 100.0 * round(SUM(numwithanxiety) OVER (partition BY sex) / cast(TotalSexCounts AS float), 4) overAllPercentByGender
FROM (SELECT x.sex, injurylevel, SUM(sexandlevelcounts) OVER (partition BY x.sex) numByInjury, sum(sexandlevelcounts) AS numWithAnxiety,
100.0 * round(cast(sexandlevelcounts AS float) / SUM(sexandlevelcounts) OVER (partition BY x.sex), 4) AS percentWith, y.TotalSexCounts
FROM (SELECT sex, injurylevel, COUNT(*) AS sexAndLevelCounts
FROM (SELECT DISTINCT m.patid, m.sex, m.injurylevel
FROM members AS m INNER JOIN
icdClm AS ic ON ic.patid = m.PATID
--*****when I leave this operator as like and use
--*****equals in the exec statement it works
WHERE ic.icd LIKE #condition) t
GROUP BY sex, injurylevel) x INNER JOIN
(SELECT m.sex, COUNT(DISTINCT patid) TotalSexCounts
FROM members m
GROUP BY m.sex) y ON y.sex = x.sex
GROUP BY x.sex, x.injuryLevel, x.sexAndLevelCounts, y.TotalSexCounts) rr
go
This runs, but I cannot use the like operator
exec dbo.MultipleDrugs N'70700'
This is what I'd like to do
exec dbo.MultipleDrugs like '707%'
exec dbo.MultipleDrugs N'707%'
You don't need to provide the LIKE operator in your exec call - you've already got like in your SPROC. Consider instead a simpler case:
create proc FindObjects #Name NVARCHAR(50)
as
select *
from sys.objects
where name like #Name
And then calling this:
exec FindObjects 'sys%'
returns
sysrscols
sysrowsets
sysallocunits
sysfiles1
syspriorities
sysfgfrag
etc.
Change your SP so that the following occurs:
LIKE '%' + #condition + '%'
You Can also use like this in the procedure .
set #SearchString='%'+ #SearchString + '%'

TSQL Number of reads significantly different after query and stored procedure execution

After query optimization I got results that are ok and I wanted to alter stored procedure, but got much worst results after SP execution, than it was after query execution!
Firstly, I think at number of reads. What can be reason for so different results?
Query is identical like in SP, only difference is that in query I declared parameter, but in SP that was input parameter. Value that is set to parameter is also same. To avoid 'recorded data' first I recompiled SP and after that done DROP and CREATE, but results were also much different.
Query is like this (table and column names are changed because of simplification, and number of columns is reduced):
DECLARE #Var1 varchar(20)
SET #Var1 = #Var1 + '%'
DECLARE #Var2 TIMESTAMP
SELECT #Var2 = CONVERT(TIMESTAMP, ID, 0)
FROM
X_TIMESTAMPS (NOLOCK)
WHERE
TABLE = 'T1'
declare #Var3 varbinary(8)
SELECT #Var3 = max(IdTimeStamps)
FROM
T1 (NOLOCK)
SELECT o.c1
, o.c2
, o.c3
, v.c4
, v.c5
, p.c6
, p.c7
, va.c8
, isnull(s.c9, '') AS c9
, CASE o.c10
WHEN 1 THEN
0
ELSE
1
END c10
, o.c11
FROM
T1 o (NOLOCK)
JOIN T2 p (NOLOCK)
ON o.c1 = p.c12
JOIN T3 i (NOLOCK)
ON (o.c13 = i.c14)
JOIN T4 v (NOLOCK)
ON (v.c4 = i.c15)
LEFT JOIN T5 s (NOLOCK)
ON (o.c16 = s.c17)
JOIN T6 va (NOLOCK)
ON o.c11 = va.c18
WHERE
o.c1 LIKE #Var1
AND o.c2 > #Var2
And procedure is like this:
CREATE PROCEDURE [dbo].[SP1] #Var1 varchar(20) =''
WITH RECOMPILE
AS
BEGIN
PREVIOUS QUERY WITHOUT DECLARATION FOR #Var1
END
TnX in advance!
Nemanja
It's because different execution plans are used for query with constants and sp with parameeters. You can try a few tricks
Create inline table function and try it
create function sf_test
(
#param1 int
)
returns table
as
return
your query using #in_param1
or
declare additional parameters in your procedure like this
create procedure sp_test
(
#param1 int
)
as
begin
declare #in_param1 int
select #in_param1 = #param1
your query using #in_param1
end
you can also try using option with recompile in your procedure, or use dynamic SQL
This is almost certainly a parameter sniffing issue. Personally, I liked the dummy variable option to work around this issue and (only when I run into this problem) create variable(s) that are set to the value of the incoming parameter(s).