I'm trying to pass an NVARCHAR parameter to my store procedure. The stored procedure is supposed to find all suppliers that match the specified criteria. The only problem I have is that I am trying to pass criteria that contains Hebrew.
ALTER PROCEDURE [dbo].[FindSupplier]
-- Add the parameters for the stored procedure here
#search_criteria nvarchar(100) = ''
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #hebrew as bit = 0
IF #search_criteria LIKE '%[אבגדהוזחטיחכךילמנפףערקשת]%'
BEGIN
SET #hebrew = 1
END
IF #hebrew = 0
BEGIN
SELECT comn020.t_suno 'Supplier Code'
, hebcom020.t_nama 'Supplier Name1'
, hebcom020.t_namb 'Supplier Name2'
FROM com020 WITH (NOLOCK)
INNER JOIN hebcom020 WITH (NOLOCK)
ON hebcom020.t_suno = com020.t_suno
WHERE (LTRIM(RTRIM(com020.t_suno)) LIKE N'%' + #search_criteria + '%')
OR (SOUNDEX(LTRIM(RTRIM(com020.t_suno))) LIKE N'%' + SOUNDEX(#search_criteria) + '%')
OR (LTRIM(RTRIM(hebcom020.t_nama)) LIKE N'%' + #search_criteria + '%')
OR (SOUNDEX(LTRIM(RTRIM(hebcom020.t_nama))) LIKE N'%' + SOUNDEX(#search_criteria) + '%')
OR (LTRIM(RTRIM(hebcom020.t_namb)) LIKE N'%' + #search_criteria + '%')
OR (SOUNDEX(LTRIM(RTRIM(hebcom020.t_namb))) LIKE N'%' + SOUNDEX(#search_criteria) + '%')
END
ELSE /* hebrew */
BEGIN
SELECT com020.t_suno 'Supplier Code'
, hebcom020.t_nama 'Supplier Name1'
, hebcom020.t_namb 'Supplier Name2'
FROM com020 WITH (NOLOCK)
INNER hebcom020 WITH (NOLOCK)
ON hebcom020.t_suno = com020.t_suno
WHERE hebcom020.t_nama Collate Hebrew_CI_AI LIKE N'%' + #search_criteria + '%' Collate Hebrew_CI_AI
OR (LTRIM(RTRIM(hebcom020.t_namb)) LIKE N'%' + #search_criteria + '%')
END
END
When I'm trying to pass something like exec FindSupplier 'ב' the SQL server recognizes char 'ב' as '?'
Your help will be highly appreciated
UPD: exec FindSupplier N'ב' worked
UPD2: In Visual Studio need to run sp with following string
="exec FindSupplier N'" & Parameters!search_criteria.Value & "'"
The problem is simply that the string literal used in the LIKE condition is not prefixed with an N to indicate that it is a Unicode string. The following example shows the difference:
DECLARE #search_criteria NVARCHAR(100) = N'ב';
IF #search_criteria LIKE '%[אבגדהוזחטיחכךילמנפףערקשת]%'
BEGIN
PRINT 'WithOUT "N"-prefix';
END;
IF #search_criteria LIKE N'%[אבגדהוזחטיחכךילמנפףערקשת]%'
BEGIN
PRINT 'WITH "N"-prefix';
END;
Returns:
WITH "N"-prefix
To more easily understand why there is this difference in behavior, consider the following:
-- when the DB has a default collation of Latin1_General_100_CI_AS_SC (code page 1252)
SELECT '%[אבגדהוזחטיחכךילמנפףערקשת]%'
-- %[????????????????????????]%
-- when the DB has a default collation of Hebrew_100_CI_AS_SC (code page 1255)
SELECT '%[אבגדהוזחטיחכךילמנפףערקשת]%'
-- %[אבגדהוזחטיחכךילמנפףערקשת]%
The string literals are parsed in the code page used by the default collation of the current database. If the code page can support these characters, then not prefixing with the upper-case "N" will work. But, if those characters do not exist in that code page, then they are converted into "?"s.
Related
I'm creating a stored procedure where I have this openquery:
SELECT #MY_QUERY = 'SELECT * FROM OPENQUERY(HYPER_CONN, ''
SELECT COALESCE(SUM(QUANT_RIGA),0) FROM DDT_CLI_RIGHE WHERE DOC_RIGA_ID = ''''' + #THE_DDT + ''''' '')'
In the where clause I set this variable #THEDDT:
DECLARE #THE_DDT nvarchar(MAX) = (SELECT STRING_AGG(DOC_RIGA_ID,',') FROM ...
For example it will be like #THEDDT = test1,test2,test3
I want set this variable in my "where in" clause.
So in the openquery I'm trying to have something like this (but using the varaible):
WHERE DOC_RIGA_ID IN ('test1','test2','test3')
Is there a way to do this?
This is more of a stab in the dark, as we don't have all the information, however, as I mentioned, it seems all you need to do is change your DOC_RIGA_ID = {literal} clause to a DOC_RIGA_ID IN ({delimited List}) clause:
DECLARE #THE_DDT nvarchar(MAX) = (SELECT STRING_AGG(QUOTENAME(DOC_RIGA_ID,''''),',') --Assumes DOC_RIGA_ID can't have a value longer than 128 characters
FROM ...
SELECT #MY_QUERY = 'SELECT * FROM OPENQUERY(HYPER_CONN, ''
SELECT COALESCE(SUM(QUANT_RIGA),0) FROM DDT_CLI_RIGHE WHERE DOC_RIGA_ID IN (' + REPLACE(#THE_DDT,'''','''''') + ')'') OQ;';
This is, of course, untested as I have no way of testing this statement.
I have a stored procedure which is called from a program. This stored procedure is passed 2 names and needs to find similar names in the database. However when I try to compare - 'AFC Bournemouth' with the name in the db which is 'Bournemouth'.
bet.searchFixtureForResult
#homeTeam NVARCHAR(MAX),
#awayTeam NVARCHAR(MAX),
#date DATE
AS
SELECT fixtureId
FROM bet.fixture
WHERE homeTeam IN (SELECT teamId
FROM bet.team
WHERE team LIKE '%' + #homeTeam + '%')
AND awayTeam IN (SELECT teamId
FROM bet.team
WHERE team LIKE '%' + #awayTeam + '%')
AND fixtureDate = #date
This supposedly returns the Id of the fixture that falls within the parameters given. How can compare similar strings such that I compare in the same way you compare with .Contains in C#?
I don't think you need bet.team there at all, your query will be like
SELECT fixtureId
FROM bet.fixture
WHERE (HomeTeam LIKE '%' + #HomeTeam + '%' OR #HomeTeam LIKE '%' + HomeTeam + '%')
AND
(AwayTeam LIKE '%' + #AwayTeam + '%' OR #AwayTeam LIKE '%' + AwayTeam + '%')
AND
fixtureDate = #date;
Here is a little Demo
When it comes to search record with optional parameter in SQL stored procedure, out of these two queries. Both return the same results. Considering performance, which one will you use and why?
I have a stored procedure which has multiple search parameters and will be searching in multiple tables, with joins from a huge record set.
DECLARE #EventName VARCHAR(100)
--SET #EventName = ''
--SET #EventName = NULL
SET #EventName = 'Coffee in Coffee Bean'
-- Query - 1
SELECT *
FROM EventDetails
WHERE
1 = CASE
WHEN #EventName IS NULL OR #EventName = '' THEN 1
WHEN EventName LIKE '%'+ #EventName +'%' THEN 1 ELSE 0
END
-- Query - 2
SELECT *
FROM EventDetails
WHERE
EventName LIKE '%' + CASE
WHEN LEN(LTRIM(#EventName)) > 0
THEN #EventName
ELSE EventName
END + '%'
You can try this by writing a single query
SELECT *
FROM EventDetails
WHERE ((#EventName IS NULL OR #EventName) OR (EventName LIKE '%'+ #EventName +'%'))
My money is on this:
IF ISNULL(#EventName), '') = ''
SELECT * FROM EventDetails
ELSE
SELECT * FROM EventDetails WHERE EventName = '%' + #EventName + '%'
If you can't consider dynamic SQL, then try to use as less functions and data tampering as possible. The most common approach for this would be something like the following:
DECLARE #OptionalFilter1 INT
DECLARE #OptionalFilter2 VARCHAR(100)
-- ...
DECLARE #OptionalFilterN BIT
SELECT
YourColumns
FROM
YourTable AS T
WHERE
(#OptionalFilter1 IS NULL OR #OptionalFilter1 = T.Filter1Column) AND
(#OptionalFilter2 IS NULL OR #OptionalFilter2 = T.Filter2Column) AND
-- ...
(#OptionalFilterN IS NULL OR #OptionalFilterN = T.FilterNColumn)
For your example would be:
DECLARE #EventName VARCHAR(100) = 'Coffee in Coffee Bean'
SELECT
*
FROM
EventDetails AS E
WHERE
(#EventName IS NULL OR E.Event LIKE '%' + #EventName + '%')
If this is gonna end in a procedure, consider using OPTION (RECOMPILE) on the query with many filters and/or assigning the stored procedure parameters to new local scope variables to prevent parameter sniffing. You can read about parameter sniffing problem (with an example similar to yours) in this post.
Why below Query Returns null instead of a dynamic query??
declare #Query Nvarchar(2000),
#IdentificationNo Nvarchar(255)=NULL
Set #Query='select VD.* from VWNROCDetail VD Where'
Set #Query=#Query+'((NROCApplicationId like ''%' + #IdentificationNo + '%'')OR (ISNULL('''+#IdentificationNo+''','''') = ''''))'
select #Query
Because #IdentificationNo is NULL. You need to use COALESCE(#IdentificationNo, '') or something like that.
'A' + NULL + 'B'
Returns Null
Whereas
'A' + '' + 'B'
returns 'AB'
The result ist null in String concatenation.Because your variable #IdentificationNo is null. If you append NULL to any String, the result is always NULL.
Not sure what you are trying to archive, but you should take a look at the sp_executesql procedure.
Example:
EXEC sp_executesql N'《your statement using #p1 as variable》', N'#p1 NVARCHAR(255)', #p1 = #IdentificationNo;
If you explain the Statement, i could offer some help.
I agree Alan. Now, it's really necessary to build a query with concantenation? In your case you can just do it :
declare #IdentificationNo Nvarchar(255)=NULL;
select VD.* from VWNROCDetail VD
Where VD.NROCApplicationId like '%' + #IdentificationNo + '%' or #IdentificationNo is null ;
I'm writing a stored procedure about searching the database based on aspx page textbox input text.
This stored procedure works well, but I have a problem.
Sometimes #DeptName and #DutyName parameters are empty or null.
So I want to skip or ignore where clauses when that parameter values are empty. But I am confused as to how to handle this situation.
Please give me your advice.
My stored procedure code:
DECLARE
#CompanyCode varchar(20)
, #DeptName nvarchar(20)
, #DutyName nvarchar(20)
SELECT
#CompanyCode = 'h101'
, #DeptName = 'IT'
, #DutyName = 'Manager'
SELECT
U.ADDisplayName AS UserName
, LOWER(U.UserID) AS EmpID
, ISNULL(CPN.CompanyName, '') AS CompanyCode
, ISNULL(U.DisplayName_Eng, '') AS DisplayName_Eng
, ISNULL(DT.DisplayName, '') AS DeptName
, ISNULL(DTY.DutyName, '') AS DutyName
, ISNULL(U.CellPhone, '') AS CellPhone
, ISNULL(U.ExtensionNumber, '') AS ExtensionNumber
, ISNULL(U.FaxNumber, '') AS FaxNumber
, ISNULL(U.ChargeJob, '') AS ChargeJob
, ISNULL(LOC.LocationName, '') AS LocationName
, ISNULL(U.Workplace, '') AS Workplace
, ISNULL(U.EMail, '') AS EMail
FROM dbo.tb_User U
INNER JOIN dbo.tb_Dept DT
ON U.MainDeptCode = DT.DeptCode
INNER JOIN dbo.tb_Company CPN
ON U.CompanyCode = CPN.CompanyCode
INNER JOIN dbo.tb_Location LOC
ON U.LocationCode = LOC.LocationCode
AND U.CompanyCode = LOC.CompanyCode
AND U.GroupCode = LOC.GroupCode
AND U.DetailCode = loc.DetailCode
INNER JOIN dbo.tb_Duty DTY
ON U.DutyCode = DTY.DutyCode
AND U.CompanyCode = DTY.CompanyCode
AND U.GroupCode = DTY.GroupCode
AND U.DetailCode = DTY.DetailCode
WHERE U.CompanyCode = #companyCode
AND DT.DisplayName like '%' + #DeptName + '%'
AND DTY.DutyName like '%' + #DutyName + '%'
Order by DeptName desc
Thank you.
A very common construction is :
WHERE U.CompanyCode = #companyCode
AND (#DeptName is null or DT.DisplayName like '%' + #DeptName + '%')
AND (#DutyName is null or DTY.DutyName like '%' + #DutyName + '%')
...
...
with (recompile)
The with (recompile) hint at the end of your statement is telling SQL Server to check the optimization plan "after" replacing the variables by their values. Doing so it allows to completely ignore a condition when its parameter is null, resulting normally in an optimal execution (only on very complex statements you will need to do more in order to help the SQL engine to find the better execution plan).
It's also worth noting that using the with (recompile) clause forces to check for a new plan at every execution (instead of reusing an existing one), so if your sentence is going to be executed several times for second, then you will be better suited using an alternative, like parameterized dynamic SQL. Although this is not the most usual situation.
PS: If your parameter can also be an empty string, then use isnull to check both options. You still need to add the recompilation hint to execute it optimally.
WHERE U.CompanyCode = #companyCode
AND (isnull(#DeptName, '') = '' or DT.DisplayName like '%' + #DeptName + '%')
AND (isnull(#DutyName, '') = '' or DTY.DutyName like '%' + #DutyName + '%')
...
...
with (recompile)
Add an extra #DeptName is null and #DeptName ="" to each clause:
WHERE U.CompanyCode = #companyCode
AND ((DT.DisplayName like '%' + #DeptName + '%') or (#DeptName is null) or (#DeptName =''))
AND ((DTY.DutyName like '%' + #DutyName + '%') or (#DeptName is null) or (#DeptName = ''))
Order by DeptName desc
You can try this.
Using ISNULL you can replace NULL with a specified replacement value.
In this case, IF #DeptName is null then replace it with value of DT.DisplayName. same applies to #DutyName.
The Logical Function IIF is used to check empty value but this applies starting SQL2012 version, otherwise CASE expression for SQL2008 or later versions.
WHERE U.CompanyCode = #companyCode
AND DT.DisplayName like '%' + ISNULL(IIF(#DeptName = '',NULL,#DeptName),DT.DisplayName) + '%'
AND DTY.DutyName like '%' + ISNULL(IIF(#DutyName = '',NULL,#DutyName),DTY.DutyName) + '%'
Order by DeptName desc