Select does not work with variable in SQL Server 2017 - sql-server

I have a table called UserList which has UserName and UserPassword columns. When I query as below, it Works and returns the right data.
SELECT * FROM dbo.UserList WHERE UserName = 'aliserin'
But when I try it as below, it doesn't give me any result. It just returns empty. It doesn't give an error, but I really didn't understand the reason. It is a local database if it matters.
declare
#UserName as NVARCHAR
SET
#UserName = 'aliserin'
SELECT * FROM dbo.UserList WHERE UserName = #UserName
When I try the same code on UserId constraint as below, it works. Does anyone has any idea why?
DECLARE #UserName1 AS NVARCHAR
SET #UserName1 = 2
SELECT * FROM dbo.UserList WHERE UserId = #UserName1

You need to specify a length parameter for the varchar type: What is the effect of omitting size in nvarchar declaration
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.
This means your query is actually doing SELECT * FROM UserList WHERE UserName = 'a'.
So you want:
DECLARE #userName AS nvarchar(8)
SET #userName = 'aliserin'
SELECT * FROM dbo.UserList WHERE UserName = #userName
You can also simplify this by using the DECLARE = syntax and omitting the AS keyword (I avoid using AS for types as it's usually used to alias column names)
DECLARE #userName nvarchar(8) = 'aliserin'
SELECT * FROM dbo.UserList WHERE UserName = #userName

Related

SQL Server: get column value from string column name, assign value to variable

In SQL Server in a stored procedure, I want to get the value in a column of a single-row table given the column name, and assign that value to a variable. The column name may be different every time (I use T-SQL to interrogate the schema at run time).
The example given below is as minimal as I can make it, the important thing is that you cannot assume that the column name will always be entity_client, it could be anything at all, though (due to interrogation of INFORMATION SCHEMA) we will have the value assigned to the variable #entity_column_name.
Example preparation SQL:
IF OBJECT_ID('tempdb..#foo') IS NOT NULL
BEGIN;
DROP TABLE #foo;
END;
CREATE TABLE #foo
(
id INT,
entity_client NVARCHAR(255)
);
INSERT INTO #foo VALUES (1, 'clientcode|client_number');
DECLARE #entity_column_name NVARCHAR(255) = 'entity_client';
DECLARE #entity_column_value NVARCHAR(255);
I have tried the following:
SELECT TOP 1 #entity_column_name = [#entity_column_value]
FROM #foo;
...which generates an error
Invalid column name '#entity_column_value'
I have also tried:
EXEC('SELECT TOP 1 #entity_column_value = [' + #entity_column_name + '] FROM #foo;');
which generates another error
Must declare the scalar variable "#entity_column_value"
The following works, but unfortunately the column name is hard-coded - I wanted to be able to vary the column name:
SELECT TOP 1 #entity_column_value = [entity_client]
FROM #foo;
Yes, I have looked on SO and found the following questions, but they do not provide an answer where the value is assigned to a variable, in both cases the SELECT output is simply dumped to screen:
Get column value from string column name sql
Get column value from dynamically achieved column name
This will actually work but you need to declare the output variable:
DECLARE #entity_column_name NVARCHAR(255) = 'entity_client';
DECLARE #entity_column_value NVARCHAR(255);
DECLARE #tsql NVARCHAR(1000) = 'SELECT TOP 1 #entity_column_value = [' + #entity_column_name + '] FROM #foo;'
EXEC sp_executesql #tsql, N'#entity_column_value NVARCHAR(255) OUTPUT',
#entity_column_value OUTPUT;

Comparing VARCHARs of different length

I'm writing a stored procedure and I need to compare a SQL Server variable to a column. The problem, is that if my SQL variable is a VARCHAR that's not the same length as the column type, it won't match.
Example:
Let's say, I have a table types with a column name that has a type VARCHAR(100). Running the code below won't give me any results:
DECLARE #type VARCHAR(20);
SET #type = 'My Type Name';
select * from types where name = #type
However, running this query will find my column:
DECLARE #type VARCHAR(100);
SET #type = 'My Type Name';
select * from types where name = #type
Now, I'd like to be able to do it the first way, especially because if I modify the column, I don't want this query to start failing. Can anyone tell me what I'm doing wrong?
Edit:
Here's my column schema:
Query:
DECLARE #event_type VARCHAR(20);
SET #event_type = 'Price Increase Notification';
select * from events.types where name = #event_type
Output:
Query:
DECLARE #event_type VARCHAR(100);
SET #event_type = 'Price Increase Notification';
select * from events.types where name = #event_type
Output:
The following will behave as you described:
CREATE TABLE #types
(
type VARCHAR(100)
)
INSERT INTO #types (type) VALUES ('My Type Name')
-- returns 1 row
select * from #types
-- returns 0 rows
DECLARE #type VARCHAR(10);
SET #type = 'My Type Name';
select * from #types where type = #type
-- returns 1 row
DECLARE #long_type VARCHAR(100);
SET #long_type= 'My Type Name';
select * from #types where type = #long_type
drop table #types
The point is that DECLARE #type VARCHAR(10); SET #type = 'My Type Name'; will actually set your variable to 'My Type Na' (length = 10).
So, if your value is longer than your variable, the variable is set to the truncated value. No warning, no error. If you then try to equate it to the original (longer) value, you'll find they aren't equal.
Your edited example:
DECLARE #event_type VARCHAR(20);
SET #event_type = 'Price Increase Notification';
select * from events.types where name = #event_type
The string you are setting #event_type to is 27 characters so it is getting truncated to the 20 characters and therefore there is no match.
What I would probably do to ensure if the column length changes you are ok is declare #event_type as varchar(max)
here is what I would do
select * from events.types where ltrim(rtrim(name)) = #event_type

SQL Server - Replace

What's the problem with my query, it doesn't work
DECLARE #_old nvarchar = '#35_D'
DECLARE #_new nvarchar = '#Dima'
UPDATE ShoppingComment SET Commnet =Replace(Commnet,#_old,#_new)
It doesn't show error, but query isn't replace, but when I use it without DECLARE , it works fine
Datatype length is missing in your code.
From MSDN
When n is not specified in a data definition or variable declaration
statement, the default length is 1.
So only the first character will be assigned to the variable
DECLARE #_old nvarchar(50) = '#35_D' --here
DECLARE #_new nvarchar(50) = '#Dima' --here
UPDATE ShoppingComment SET Commnet =Replace(Commnet,#_old,#_new)

how can I use a sproc #param as column alias?

How can use a sproc param as a column alias? For example:
SELECT '12345' AS #MySprocParam
I tried the following sql but it doesn't work:
DECLARE #MySprocParam VARCHAR(50) = 'TestAlias'
SELECT 'ASDF' AS #MyProcParam
You need dynamic sql
DECLARE #MySprocParam VARCHAR(50) = 'TestAlias'
SET #MyProcParam = QUOTENAME(#MyProcParam)
exec( 'SELECT ''ASDF'' AS '+#MyProcParam)

Null values stored in table via Stored Procedure

Following is my stored procedure which stores data in two tables namely SuccessfulLogins and FailedLogins
ALTER procedure [dbo].[Proc_CheckUser]
#UserID VARCHAR(50),
#Password VARCHAR(50)
AS
SET NOCOUNT ON
DECLARE #ReturnVal VARCHAR(500)
DECLARE #PasswordOld VARCHAR(50)
DECLARE #Type NVARCHAR(50)
DECLARE #IP NVARCHAR(50)
SELECT #PasswordOld = Password,#Type=ClientType,#IP=IPAddress
FROM Clients
WHERE Username = #userid
IF (#PasswordOld IS NULL)
BEGIN
SET #ReturnVal='1|Incorrect Username'
INSERT INTO FailedLogins(Username,Password,ClientType,Reason,IPAddress)
VALUES(#UserID,Hashbytes('SHA1',#Password),#Type,'Invalid Username',#IP)
END
ELSE
BEGIN
IF (#PasswordOld!=Hashbytes('SHA1',#Password))
BEGIN
SET #ReturnVal='1|Incorrect Password'
INSERT INTO FailedLogins(Username,Password,ClientType,Reason,IPAddress)
VALUES(#UserID,Hashbytes('SHA1',#Password),#Type,'Invalid Password',#IP)
END
ELSE
BEGIN
SET #ReturnVal='0|Logged in Successfully' +'|'+ rtrim(cast(#Type as char))
INSERT INTO SuccessfulLogins(Username,Password,ClientType,Reason,IPAddress)
VALUES(#UserID,Hashbytes('SHA1',#Password),#Type,'Valid Login Credentials Provided',#IP)
END
END
SELECT #ReturnVal
The problem here is that whenever I enter an Invalid Username,the stored procedure returns the correct message ie Incorrect Username but it stores NULL values in the fields ClientType and IPAddress in Failed Logins Table
Following is my insert query for Invalid username
IF (#PasswordOld!=Hashbytes('SHA1',#Password))
BEGIN
SET #ReturnVal='1|Incorrect Password'
INSERT INTO FailedLogins(Username,Password,ClientType,Reason,IPAddress)
VALUES(#UserID,Hashbytes('SHA1',#Password),#Type,'Invalid Password',#IP)
END
Can anyone help me to rectify this.How to check condition for username?
Thanks
Your code reads
SELECT #PasswordOld = Password,#Type=ClientType,#IP=IPAddress
FROM Clients
WHERE Username = #userid
Wouldn't this mean that no row will be returned for a Username that does not exist? So, the values for ClientType and IPAddress will not get populated and will remain NULL, which would be the expected functionality.
However, if you want to store some value, or these fields are not nullable, assign a static value to these parameters.
Your query is correct. When there is no match for the Username = #UserId , The #Type , #IP variables will be null. Since there is no record in the table for that UserName. What you can do is that in the declaration you can initiate to some default value,so that it will be inserted to table FailedLogins.
DECLARE #Type NVARCHAR(50)="DefaultType/NoType"
DECLARE #IP NVARCHAR(50)="0.0.0.1"
Something like the above.
If the username is invalid it does not appear in the table Clients so your fields pulled from that table will also be NULL. To negate this you could decide to use default values for ClientType and IPAddress using static values in your declarations, but storing this would just be obsolete data and I would think changing the structure of FailedLogins to not store this would seem more logical.

Resources