Can I use output variables to get a value? - sql-server

I have a stored procedure where I'm checking if username exists and if it does not exists insert into user table then gets userid for the same username. I was trying to use an output variable to get the userid. Am I going about this wrong?
alter Procedure Check_User_Name
(
#username varchar(25),
#password varchar(100),
#role_id integer,
#idn nvarchar output
)
As
Begin
IF NOT EXISTS(SELECT idn=#idn
FROM [user] WHERE username = #username)
BEGIN
INSERT INTO [user] (username,[password],role_id) VALUES
(#username, #password,#role_id)
--select #idn=idn from [user]
Print 'UserName inserted successfully'
End
Else IF EXISTS(SELECT * FROM [user] WHERE username = #username)
Begin
Print 'UserName already exists'
End
END

You had it close -- After replacing your column names to match with what is in my user table, this worked for me. (I think I replaced everything back).
On your Else, you're basically doing a second lookup by username - which is unnecessary in this case.
ALTER Procedure Check_User_Name
(
#username varchar(25),
#password varchar(100),
#role_id integer,
#idn nvarchar(20) output
)
As
Begin
IF NOT EXISTS(SELECT idn
FROM [user] WHERE username = #username)
BEGIN
INSERT INTO [user] (username,[password], role_id) VALUES
(#username, #password)
select #idn=idn from [user] WHERE username = #username
Print 'UserName inserted successfully'
End
Else
Begin
Print 'UserName already exists'
SELECT #idn = idn FROM [user]
WHERE username = #username
End
END
GO
Execute with:
DECLARE #idnOut nVarChar(20)
exec Check_User_Name #username = 'user2127184', #password = 'asdf', #role_id = 0, #idn = #idnOut OUTPUT
SELECT #idnOut

You can use out params, but I always avoid out params in SQL like I do in C# for the same reasons.
If you have a result set with just the UserId:
select #UserId;
then you expand it to include other things later:
select #UserId, #UserGuid;
without much trouble.
Even if you need to return a status (Login Allowed / Locked Out) and details you can just use multiple result sets:
select #Status;
select #UserId; //etc.
If you have out parameters you have to change the Signature of the procedure - which can be a problem if you are supporting multiple clients calling it.
The only change you need to make to the calling code with result sets is to keep finding the new column from the result set.

Related

Stored Procedure that it's not working

I have this procedure, but it doesn't work..I can't figure it out why. Any ideas what am I doing wrong?
CREATE PROCEDURE [dbo].[spCheckLogin]
( #Username varchar(30),
#Password varchar(15))
AS
BEGIN
Declare
#Result int = 0;
IF (#Password=(SELECT password from users where Username=#Username))
set #Result=1
ELSE
set #Result=0
return #Result
END
GO
The comparison you are using is incorrect. It should be something like:
IF EXISTS (SELECT 1 from users where Username=#Username AND password = #password)
Also note that storing passwords in plaintext is not a good practice. Suggested reading: Why are plain text passwords bad, and how do I convince my boss that his treasured websites are in jeopardy?
Instead of a return value you would want to use an output value. However a return value is of type integer, thus might work for you.
You would never want to use a plain password stored, but I would assume you are doing this just for testing purposes on a hobby project.
CREATE PROCEDURE [dbo].[spCheckLogin]
( #Username varchar(30),
#Password varchar(15))
AS
BEGIN
Declare #Result int = case
when exists (SELECT *
from users
where Username=#Username and password = #Password))
THEN 1
ELSE 0
END
return #Result
END
GO
Like metnioned, use an OUTPUT paramter:
CREATE PROC [dbo].[spCheckLogin] #Username varchar(30),
#Password varchar(30),
#Success bit OUTPUT
AS
BEGIN
IF EXISTS (SELECT 1
FROM users
WHERE Username = #Username
AND Password = #Password)
BEGIN
SET #Success = 1;
END
ELSE
BEGIN
SET #Success = 0;
END
END
But, also, as mentioned, don't store passwords in an unhashed and unsalted format in your database. If you are, change your design.

How to get a output response as integer from a stored procedure in SQL Server

I'm trying to get the following response from a stored procedure to authenticate the user and read a response from stored procedure based on the user input.
CREATE Procedure sp_UserAuthentication
#UserName varchar(20),
#UserPassword varchar(20),
#Resp int output
AS
DECLARE #Count int;
DECLARE #IsAdmin bit;
DECLARE #IsActive bit;
Select #Count = COUNT(UserName) from tbl_UserDetails where UserName = #UserName and UserPassword = #UserPassword
IF #Count = 1
BEGIN
Select #IsActive = IsActive, #IsAdmin = #IsAdmin from tbl_UserDetails where UserName = #UserName and UserPassword = #UserPassword
IF #IsActive = 0 -- InActive user
BEGIN
SET #Resp = 3
END
ELSE IF #IsAdmin = 1 -- Admin user
BEGIN
SET #Resp = 2
END
ELSE -- Normal user
BEGIN
SET #Resp = 1
END
END
ELSE -- InValid user
BEGIN
SET #Resp = 0
END
GO
I'm getting response as always 1 for a valid user and 0 for invalid user. I'm not getting the response as 2 for admin and 3 for an inactive user.
DECLARE #Res int
exec sp_UserAuthentication 'user', 'pwd', #Res out
SELECT #Res
Table:
Create Table tbl_UserDetails(
UserName Varchar(20) primary key,
UserPassword Varchar(20) NOT NULL,
IsAdmin Bit Default 0,
IsActive Bit Default 1
);
Keep in mind everybody's stern reprimands about storing clear text passwords. You desperately need to read about and understand how to encrypt these. But your entire procedure could be greatly simplified to something like this.
CREATE Procedure UserAuthentication
(
#UserName varchar(20),
#UserPassword varchar(20),
#Resp int output
)
AS
set #Resp = 0 --This sets the response to invalid unless we actually find a user
Select #Resp =
case when IsActive = 0 then 3 --Inactive User
when IsAdmin = 1 then 2 --Admin user
else 1 --Normal user
end
from tbl_UserDetails
where UserName = #UserName
and UserPassword = #UserPassword
Let's ignore that you're putting usernames and passwords into a table. Please don't do that, and if you do, please use some kind of encryption/hashing. But look in your SELECT statement in the middle:
Select #IsAdmin = #IsAdmin
You are setting #IsAdmin to #IsAdmin, you need to set that to just IsAdmin.

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.

Username increment by 1 if already exist in mssql 2008

Create table TEMP_USER
(
USERNAME nvarchar(50) ,
ID int,
Phone nvarchar(30)
);
IF the user name already exist in temp_user it should incement by 1 while inserting through SP.
Example : RAM .Narayan if anyone trying to insert again ram.narayan it should insert as ram.narayan1 next time anyone trying to insert ram.narayan it should insert ram.narayan2 ..How to do this in MSSQL 2008
Try something like the following (untested, but it should give you a good start). It assumes the variables #username, #id, and #phone are already declared or passed as parameters.
DECLARE #curr_uname nvarchar(50) = #username
DECLARE #i INT = 0
WHILE EXISTS (SELECT 1 FROM TEMP_USER WHERE USERNAME = #curr_uname)
BEGIN
SET #i += 1
SET #curr_uname = #username + CAST(#i AS NVARCHAR(7))
END
INSERT INTO TEMP_USER (USERNAME, ID, Phone)
VALUES (#curr_uname, #id, #phone)

Problem in stored procedure result

I have a store procedure like this :
ALTER PROCEDURE [dbo].[CheckUser&Pass]
(
#Username nchar(15),
#Password nchar(15)
)
AS
SET NOCOUNT ON;
SELECT Username, Pass, Code_Person
FROM Login
WHERE (Username = #Username) AND (Pass = #Password)
And Execution :
DECLARE #return_value int
EXEC #return_value = [dbo].[CheckUser&Pass]
#Username = N'admin',
#Password = N'1234'
SELECT 'Return Value' = #return_value
GO
I Want to know how I can set #return_Value to 1 when the username is admin and password is 1234.
but it doesn't work properly, is that possible ?
To set the return value within a stored procedure, you need to use the RETURN statement
e.g.
IF (##ROWCOUNT > 0 AND #Username = 'admin' and password='1234')
RETURN 1
ELSE
RETURN 0
Please note, I've given exactly what you've asked for just to demonstrate use of the RETURN statement. There's a few concerns I have that should be pointed out:
Looks like you're storing the password in plain text, which if is the case, is a bad idea
This hardcoded condition for admin username and password combination is horrible. One better solution is to have an "IsAdmin" flag in the db - if the supplied username/password is valid, then return 1 if the flag indicates the account is an admin.
Use of nchar - all usernames and passwords will be padded out to 15 characters. You should consider nvarchar instead.
You could change your stored proc to return the count, assuming that username and password are unique you should get a 1 or a 0 for the result, but I reckon there must be a better way.
ALTER PROCEDURE [dbo].[CheckUser&Pass]
(
#Username nchar(15),
#Password nchar(15)
)
AS
SET NOCOUNT ON;
SELECT Count(Username)
FROM Login
WHERE (Username = #Username) AND (Pass = #Password)
you should change your stored procedure in order to return the value you want
ALTER PROCEDURE [dbo].[CheckUser&Pass]
(
#Username nchar(15),
#Password nchar(15)
)
AS
SET NOCOUNT ON;
DECLARE #cnt INT
SELECT #cnt = COUNT(*)
FROM Login
WHERE (Username = #Username) AND (Pass = #Password)
RETURN #cnt

Resources