SQL Server query: what is the meaning of 'N' preceding a string? - sql

In SQL Server, the query
SELECT custid, country, region, city
FROM Sales.Customers
WHERE region = N'WA'
what is the meaning of 'N' in the where clause? I remove it, get same result.

It is casting your literal to a Unicode string.
See here for official explanation:
Unicode strings have a format similar to character strings but are preceded by an N identifier (N stands for National Language in the SQL-92 standard).
In many cases, it won't make a difference, unless your literal contains Unicode characters. If it does, and you leave out the explicit cast, it will convert your Unicode characters to a '?':
select 'Ộ', N'Ộ'
---- ----
? Ộ

Unicode string constants that appear in code executed on the server, such as in stored procedures and triggers, must be preceded by the capital letter N. This is true even if the column being referenced is already defined as Unicode. Without the N prefix, the string is converted to the default code page of the database. This may not recognize certain characters.
For example, the stored procedure created in the previous example can be executed on the server in the following way:
EXECUTE Product_Info #name = N'Chain'
The requirement to use the N prefix applies to both string constants that originate on the server and those sent from the client.

'N' stands for National Language and denotes that you are passing a value for NVARCHAR, NCHAR. The data types that accept languages other than English start with N.
Keep in mind that you are not required to wrap your parameter with 'N' for data types like VARCHAR, CHAR because they don't accept Unicode characters.
Any other language such as Arabic, Farsi will be considered as Unicode so they should be manipulated in data types like NVARCHAR and values should be wrapped with 'N' as below:
DECLARE #Name AS NVARCHAR(50);
SET #Name = N'اسم';
PRINT #Name;
This will return:
اسم
If you try without 'N':
DECLARE #Name AS NVARCHAR(50);
SET #Name = 'اسم';
PRINT #Name;
This will return
???
It is because you haven't wrapped the value with 'N' although the data type is NVARCHAR and system doesn't know anything about the word 'اسم'.

Related

Getting different results from LIKE query and stored procedure for (starts and ends with) search

I am trying to implement a stored procedure that gets the two parameters #startsWith and #endsWith and constructs this query string:
#startswith + '%' + #endsWith
To search for entries of a single column (Name) that start end end with the parameters. Here is the stored procedure:
CREATE PROCEDURE termNameStartsEndsWith(
#startsWith AS nvarchar,
#endsWith AS nvarchar
)
AS
BEGIN
SELECT * FROM Term WHERE
Name LIKE (#startsWith + '%' + #endsWith)
END;
However, I get unexpected results when one of the two query parameters is empty (''). Here is an example where I would expect only results where the Term column entry starts with 'water', but i get a bunch of additional rows:
I dont get these results when executing as a query:
So I expect that the problem is coming from the empty string concatenation being handled differently in a stored procedure? If so, how can I adapt the procedure accordingly?
Thanks for the help in advance.
As noted by Larnu in the comments, the issue isn't the query, it's your parameter declarations.
You have two NVARCHAR(n) parameters declared, but there is no length declared for either of them. From the documentation (emphasis added):
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.
So both parameters are exactly one character long. Conveniently, SQL Server will let you assign a longer value to that parameter, and then just take the first character and silently truncate the rest.
Modify your parameters to have length definitions, and you should be in business.

Can I treat a subquery with one row and one column as a scalar?

Suppose I have the following SQL (which can be run against the Data Explorer, if you'd like):
SELECT COUNT(Id) AS "Count"
INTO #temp
FROM Posts
PRINT (SELECT * FROM #temp)
This produces an error:
"Subqueries are not allowed in this context. Only scalar expressions are allowed."
Now, in this case, I know that #temp is a table of one row and one column, and hence that (SELECT * FROM #temp) will produce only one value. Is there any way to persuade SQL Server to treat it as a scalar?
I am aware that I can save it off to a variable and then PRINT that instead:
DECLARE #count int = (SELECT * FROM #temp)
PRINT #count
But this seems like an extra step that shouldn't be necessary.
No this isn't possible according to the grammar.
The only way of doing it other than assigning to a variable at the same scope would be to wrap the select in a UDF as far
as I can see.
The documentation States
PRINT msg_str | #local_variable | string_expr
msg_str Is a character string or Unicode string constant. For more
information, see Constants (Transact-SQL).
# local_variable Is a variable of any valid character data type.
#local_variable must be
char, nchar, varchar, or nvarchar, or it must be able to be implicitly
converted to those data types.
string_expr Is an expression that
returns a string. Can include concatenated literal values, functions,
and variables. For more information, see Expressions (Transact-SQL).
So assuming that "functions" includes user defined functions and not just built in functions this would work. Otherwise you're out of luck.
And for your specific use case you are certainly out of luck as, even ignoring the ridiculousness of creating a scalar UDF for this, they can't access temp tables anyway.
As far as I can tell, nope. Even a statement as simple as PRINT (SELECT 1) or PRINT (SELECT TOP (1) 1) fails.
My guess is that PRINT simply won't execute SQL of any kind to prevent possible injections. It's PRINT, after all, not EXEC. It's meant to return a string message to the client.
Nope. Print is NOT a query method. It simply prints values. Seems you don't need a temp table for this though.
Declare #Count int
select #Count = COUNT(*)
from Posts
Print #Count
Source
PRINT (Transact-SQL)
Returns a user-defined message to the client.
PRINT msg_str | #local_variable | string_expr
msg_str
Is a character string or Unicode string constant. For more information, see Constants (Transact-SQL).
#local_variable
Is a variable of any valid character data type. #local_variable must be char, nchar, varchar, or nvarchar, or it must be able to be implicitly converted to those data types.
string_expr
Is an expression that returns a string. Can include concatenated literal values, functions, and variables. For more information, see Expressions (Transact-SQL).
There isn't any kind of use of query or sub-query for that.
Source
Expressions (Transact-SQL)
{ constant | scalar_function | [ table_name. ] column | variable
| ( expression ) | ( scalar_subquery )
| { unary_operator } expression
| expression { binary_operator } expression
| ranking_windowed_function | aggregate_windowed_function
}
Per the documentation:
https://msdn.microsoft.com/en-us/library/ms176047.aspx
PRINT requires a variable which can be set to a fairly large data stream but it has to be single variable.
Though it appears to be redundant if you are trying to debug using PRINT you must set it to a variable first. I cant think of any other way around it.

script issue Transact-SQL

I Want to return All table names from a use data base but this just return a char
declare #contador int
set #contador = 1
while (#contador<=(select count(table_name) from INFORMATION_SCHEMA.TABLES))
begin
declare #tableName varchar
set #tableName = (select top 1 * from (select top(#contador) table_name from INFORMATION_SCHEMA.TABLES order by table_name asc) as nombre order by table_name desc)
print #tableName
set #contador = #contador + 1
end
the output is s
s
s
s
s
s
declare #tableName varchar(100)
You need to define the length of #tableName, by default it is set to 1 character.
try
declare #tableName varchar(100)
You need to change your tablename to have a value for the number of characters. Currently that value is defaulted to one. I would suggest a much larger value than you think you neeed to ensure that all tables fit inside the field.
declare #tableName varchar needs to have a size like varchar(50)
T-SQL has the type SYSNAME for storing things like table names:
The sysname data type is used for table columns, variables, and stored
procedure parameters that store object names. The exact definition of
sysname is related to the rules for identifiers. Therefore, it can
vary between instances of SQL Server. sysname is functionally the same
as nvarchar(128) except that, by default, sysname is NOT NULL. In
earlier versions of SQL Server, sysname is defined as varchar(30).
So try declaring your variable like this:
DECLARE #tableName SYSNAME;
Using the VARCHAR(100) declaration, as suggested in other answers, will fail if the table name contains characters outside your current code page or is longer than 100 characters.
This excerpt from SQL Server's rules for identifiers describes the form of a table name:
The first character must be one of the following:
A letter as defined by the Unicode Standard 3.2. The Unicode
definition of letters includes Latin characters from a through z, from
A through Z, and also letter characters from other languages.
The underscore (_), at sign (#), or number sign (#).
Certain symbols at the beginning of an identifier have special meaning
in SQL Server. A regular identifier that starts with the at sign
always denotes a local variable or parameter and cannot be used as the
name of any other type of object. An identifier that starts with a
number sign denotes a temporary table or procedure. An identifier that
starts with double number signs (##) denotes a global temporary
object. Although the number sign or double number sign characters can
be used to begin the names of other types of objects, we do not
recommend this practice.
Some Transact-SQL functions have names that start with double at signs
(##). To avoid confusion with these functions, you should not use
names that start with ##.
Subsequent characters can include the following:
Letters as defined in the Unicode Standard 3.2.
Decimal numbers from either Basic Latin or other national scripts.
The at sign, dollar sign ($), number sign, or underscore.
The identifier must not be a Transact-SQL reserved word. SQL Server
reserves both the uppercase and lowercase versions of reserved words.
Embedded spaces or special characters are not allowed.
Supplementary characters are not allowed.
See the documentation links in my answer for more information.

Find reserved keywords in TSQL

I am not sure if there is any built-in function in sql server 2008 that will tell whether it is reserved keyword or not.
The reason I wanted to do this is because I find sometimes the column names are using the same name as the reserved keywords, for example, a column called 'desc', 'user', 'state', etc, which then we have to wrap them with square brackets ([desc], [user], [state]) to be able to query the columns correctly.
If such a built-in function does exist, then we probably can do
if isReservedKeyword (#name) = true
set #column = REPLACE(#column, #name, '[' + #name+ ']')
else
set #column = #name
Reserved words are documented here:
http://msdn.microsoft.com/en-us/library/ms189822.aspx
That list is exhaustive, but it's not so long that you couldn't just re-enter those into your own database table to check against.
There is a built in function that will take care of this, and also 'unusual' characters: QUOTENAME
:
Returns a Unicode string with the
delimiters added to make the input
string a valid SQL Server delimited
identifier.
The following example takes the
character string abc[]def and uses the
[ and ] characters to create a valid
SQL Server delimited identifier.
SELECT QUOTENAME('abc[]def')
Here is the result set.
[abc[]]def]
(1 row(s) affected)
Notice that the right bracket in the
string abc[]def is doubled to indicate
an escape character.
Just put brackets around every column. That way you ensure that even reserved words are taken care of.

Convert Binary Id Field to Text

I need the text (representation) of a id field in SQL Server 2005. Is there a way, we can generate the textual representation of the id field?
For instance, if the id field reads as 0x00000000000002F0, I need the text value of 0x00000000000002F0 so that I can run SUBSTR operations on the same.
Constraints
I am not allowed to create a stored procedure in the Database (as creation of SP is not allowed)
Thanks!
You can convert unicode strings to binary using
SELECT CONVERT(VARBINARY(40),N'Hello World')
(returns 0x480065006C006C006F00200057006F0072006C006400)
Convert from binary back to unicode using
SELECT CONVERT(NVARCHAR(20), 0x480065006C006C006F00200057006F0072006C006400)
(returns 'Hello World')
Whilst it's not immediately obvious to me why you would want to do this for comparison purposes (as opposed to matching binary values), the undocumented function sys.fn_varbintohexstr should do the trick
declare #vb binary(8)
,#vc varchar(20)
set #vb = 0x00000000000002F0
set #vc = sys.fn_varbintohexstr(#vb)
--prove that this works by concatenating a string to the varchar value
select #vb, '#' + #vc