LIKE operator, N and % SQL Server doesn't work on nvarchar column - sql

Is there any way to make following query Work?
declare #t nvarchar(20)
set #t='حس'
SELECT [perno] ,[pName]
FROM [dbo].[People]
Where [pName] like N''+#t +'%'
I cann't use like this:
Where [pName] like N'حس%'
Or using an stored procedure :
ALTER PROCEDURE [dbo].[aTest]
(#t nvarchar(20))
AS
BEGIN
SELECT [perno] ,[pName]
FROM [dbo].[People]
WHERE ([People].[pName] LIKE N'' +#t + '%')
END

You don't need to use N prefix in the WHERE clause since your variable is already nvarchar, and you are passing a variable not a literal string.
Here is an example:
CREATE TABLE People
(
ID INT,
Name NVARCHAR(45)
);
INSERT INTO People VALUES
(1, N'حسام'),
(2, N'حسان'),
(3, N'حليم');
DECLARE #Name NVARCHAR(45) = N'حس';--You need to use N prefix when you pass the string literal
SELECT *
FROM People
WHERE Name LIKE #Name + '%'; --You can use it here when you pass string literal, but since you are passing a variable, you don't need N here
Live demo
You may have seen Transact-SQL code that passes strings around using an N prefix. This denotes that the subsequent string is in Unicode (the N actually stands for National language character set). Which means that you are passing an NCHAR, NVARCHAR or NTEXT value, as opposed to CHAR, VARCHAR or TEXT.
From docs
Prefix Unicode character string constants with the letter N. Without the N prefix, the string is converted to the default code page of the database. This default code page may not recognize certain characters.
To answer your question in the comment with a simple answer, you are using the wrong datatype, so ALTER the stored procedure and change the datatype of your parameter from VARCHAR to NVARCHAR.
UPDATE:
Since you are using an SP, you can create your SP (according to your comment) as
CREATE PROCEDURE MyProc
(
#Var NVARCHAR(45)
)
AS
BEGIN
SELECT *
FROM People
WHERE Name LIKE ISNULL(#Var, Name) + '%';
--Using ISNULL() will return all rows if you pass NULL to the stored procedure
END
and call it as
EXEC MyProc N'حس'; --If you don't use N prefix then you are pass a varchar string
If you see, you need to use the N prefix when you pass literal string to your SP not inside the SP or the WHERE clause neither.
Demo for the SP

in these lines
declare #t nvarchar(20)
set #t='حس'
the 'حس' is a varchar constant that you then assign to an nvarchar variable. But you already lost data with the original conversion to that varchar constant and you cannot get that back.
The solution is to use an nvarchar constant:
set #t=N'حس'

It might be much simpler:
Try this
declare #t nvarchar(20)
set #t='حس';
SELECT #t; --the result is "??"
You are declaring the variable as NVARCHAR correctly. But the literal does not know its target. Without the N it is taken as a VARCHAR with the default collation.
The following line
Where [pName] like N''+#t +'%'
will search for a pName LIKE '??%'.
The solution should be
set #t=N'حس'; --<-- N-prefix

Related

[Insert Destination [26]] Error: Column "GovtProgYN" cannot convert between unicode and non-unicode string data types

I am executing an ETL process and getting captioned error:
source datatype is char(1) and destination datatype is nchar(2)
How do I insert data from char to nchar?
Please help.
You don't say what platform you are using but you need to tell it to convert. Something like
SELECT CAST(GOVTPROGYN as NCHAR(2)) FROM TABLENAME_YOU_DID_NOT_SAY
or
SELECT CAST(GOVTPROGYN as CHAR(1)) FROM TABLENAME_YOU_DID_NOT_SAY
Per your title error, the n in nchar adds support for unicode, (same with nvarchar vs varchar). The data you are trying to insert is type char, but your destination field (GovtProgYN?) requires nchar.
Most SQL engines support a CAST function, which looks something like this: CAST( field AS datatype ). In your case, you would want to cast your insert value to nchar(2).
Example:
INSERT INTO Table ( GovtProgYN )
VALUES ( CAST ( #value AS nchar(2) )
Some SQL engines, like SQL Server, require you to designate unicode using the N prefix to a character string. If you are trying to manually insert a nchar value, use N'c' rather than 'c'.
Example:
INSERT INTO Table ( GovtProgYN )
VALUES ( N'c' )

Deterministic string replace and collate

I have a persisted computed column which calls a Scalar Valued Function. As you know, this function needs to be deterministic in order to persist the value. Even if REPLACE function behaves in a deterministic way(I can't think a case where it's not), SQL Server seems to interpret it as nondeterministic. Therefore, I can not use it in the function.
What I try to do is converting some non-english characters to english. Case sensitivity is important here. I wanted to convert the letters of ğĞüÜşŞıİöÖçÇ to gGuUsSiIoOcC respectively. I can achieve it(in a "nondeterministic" way) simply by using something like:
SET #ColumnValue = REPLACE(#ColumnValue COLLATE SQL_Latin1_General_CP1253_CS_AS, 'ı', 'i') --This character("ı") is converted to "?" after collation so that I manually replace it
SET #ColumnValue = #ColumnValue COLLATE SQL_Latin1_General_CP1253_CS_AS --This line takes care of the other characters
SQL Server interprets this code above as nondeterministic (demo) because of REPLACE and COLLATE (I think that it's deterministic though..).
Another thing that I tried was using CHARINDEX with STUFF in a WHILE loop but needed to use collation because of the need of case sensitivity. Without the collation, SQL Server treats it as deterministic though.
What are my options?
Is your column really of varchar type, not nvarchar?
It looks like COLLATE SQL_Latin1_General_CP1253_CS_AS is deterministic for nvarchar, but non-deterministic for varchar.
The following function is deterministic.
Note, that you need to prefix your string literals with N for it to work correctly.
CREATE FUNCTION dbo.TestFunc1 (#ColumnValue NVARCHAR(4000))
RETURNS NVARCHAR(4000)
WITH SCHEMABINDING
AS
BEGIN
SET #ColumnValue = REPLACE(#ColumnValue COLLATE SQL_Latin1_General_CP1253_CS_AS, N'ı', N'i') --This character("ı") is converted to "?" after collation so that I manually replace it
SET #ColumnValue = #ColumnValue COLLATE SQL_Latin1_General_CP1253_CS_AS --This line takes care of the other characters
RETURN #ColumnValue
END
If you need to use varchar, then I'd use binary collation to replace specific characters. The following function is also deterministic.
CREATE FUNCTION dbo.TestFunc2 (#ColumnValue VARCHAR(8000))
RETURNS VARCHAR(8000)
WITH SCHEMABINDING
AS
BEGIN
SET #ColumnValue = REPLACE(#ColumnValue COLLATE Latin1_General_BIN2, N'ı', N'i')
SET #ColumnValue = REPLACE(#ColumnValue COLLATE Latin1_General_BIN2, N'ö', N'o')
...
RETURN #ColumnValue
END

Escape SQL function string parameter within query

I have a SQL view that calls a scalar function with a string parameter. The problem is that the string occasionally has special characters which causes the function to fail.
The view query looks like this:
SELECT TOP (100) PERCENT
Id, Name, StartDate, EndDate
,dbo.[fnGetRelatedInfo] (Name) as Information
FROM dbo.Session
The function looks like this:
ALTER FUNCTION [dbo].[fnGetRelatedInfo]( #Name varchar(50) )
RETURNS varchar(200)
AS
BEGIN
DECLARE #Result varchar(200)
SELECT #Result = ''
SELECT #Result = #Result + Info + CHAR(13)+CHAR(10)
FROM [SessionInfo]
WHERE SessionName = #Name
RETURN #Result
END
How do I escape the name value so it will work when passed to the function?
I am guessing that the problem is non-unicode characters in dbo.Session.Name. Since the parameter to the function is VARCHAR, it will only hold unicode characters, so the non-unicode characters are lost when being passed to the function. The solution for this would be to change the parameter to be NVARCHAR(50).
However, if you care about performance, and more importantly consistent, reliable results stop using this function immediately. Alter your view to simply be:
SELECT s.ID,
s.Name,
s.StartDate,
s.EndDate,
( SELECT si.Info + CHAR(13)+CHAR(10)
FROM SessionInfo AS si
WHERE si.SessionName = s.Name
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') AS Information
FROM dbo.Session AS s;
Using variable concatenation can lead to unexpected results which are dependent on the internal pathways of the execution plan. So I would rule this out as a solution immediately. Not only this, the RBAR nature of a scalar UDF means that this will not scale well at all.
Various ways of doing this grouped concatenation have been benchmarked here, where CLR is actually the winner, but this is not always an option.

Difficulty printing one particular query in MSSQL

I'm trying to construct a small query which will pull data from individual fields in a DB and print them in a human readable list format (it's what the operators are used to seeing). The code I have here is far from complete but It seems to me that it should work.
DECLARE #PSUCARD VARCHAR(20)
DECLARE #EQUIPMENT VARCHAR(50)
DECLARE #T1 VARCHAR
SET #PSUCARD = 'PSU-888'
SET #EQUIPMENT = '123_POUCH'
PRINT #PSUCARD + ':'
PRINT #EQUIPMENT
PRINT ''
IF (SELECT TEMPERATURE_MAIN FROM PSU WHERE PSU.PART_ID = #PSUCARD AND PSU.OPERATION_RESOURCE_ID = #EQUIPMENT)IS NOT NULL BEGIN
SET #T1 = (SELECT TEMPERATURE_MAIN FROM PSU WHERE PSU.PART_ID = #PSUCARD AND PSU.OPERATION_RESOURCE_ID = #EQUIPMENT)
PRINT 'Temperature: ' + #T1
--(SELECT TEMPERATURE_MAIN FROM PSU WHERE PSU.PART_ID = #PSUCARD AND PSU.OPERATION_RESOURCE_ID = #EQUIPMENT)
END
If I execute the code as is, #T1 returns a * rather than a value. If I remove comments from the line below I am reassured that there is indeed a value there.
I have other code very similar to this which works fine. Any ideas?
Also, I don't know if this helps in diagnosing the problem, but despite the temperature field in the DB being an INT, I get a conversion message if I try to treat #T1 an an INT.
This is because you declared #T1 as VARCHAR without a length. According to this:
When n is not specified in a data definition or variable declaration
statement, the default length is 1. When n is not specified when using
the CAST and CONVERT functions, the default length is 30.
You should always specify a length when declaring a VARCHAR variable:
DECLARE #T1 VARCHAR(50)
You need to give length for varchar datatype else it is going to take only one character
DECLARE #T1 VARCHAR(50)

Why does string variable store only first symbol?

Can anyone tell me why the LikeString variable is always % ? Here's the code:
DECLARE #LikeString NVARCHAR = CAST('%4075%' AS nvarchar)
SELECT #LikeString
I've tried this in SQL Server 2008 R2 and SQL Server 2012, but #LikeString always contains % instead of %4075% as I expected.
for char, varchar, nchar, nvarchar
When size is not specified in variable declaration statement, the default length is 1
DECLARE #LikeString NVARCHAR(6) = CAST('%4075%' AS nvarchar(6))
SELECT #LikeString
or simpler:
DECLARE #LikeString NVARCHAR(6) = N'%4075%'
SELECT #LikeString
From the SQL Server 2008 R2 Transact-SQL documentation...
"When n is not specified in a data definition or variable declaration statement, the default length is 1. When n is not specified with the CAST function, the default length is 30."
https://msdn.microsoft.com/en-us/library/ms186939(v=sql.105).aspx
You are using a variable declaration statement, therefore all but the first character is being truncated from the string when you attempt to initialize the variable with "%4075%".
Therefore, as others have stated, the solution is to specify the length of your nvarchar data type variable.
Use this:
DECLARE #LikeString NVARCHAR(50) = CAST('%4075%' AS nvarchar(50))
SELECT #LikeString