Setting output parameters in SELECT statement with an IF EXISTS check - sql-server

I am trying to make an efficient SQL stored procedure for retrieving user data from my database, but I am running into a syntax issue I can't seem to figure out.
Basically, I want to assign my output variable within my SELECT statement. I also want to see if the user actually exists by IF EXISTS. Unfortunately, I can't seem to do both.
Here is my procedure:
CREATE PROCEDURE [dbo].FindUser(#UserID binary(16), #UserExists bit OUTPUT, #Name
nvarchar(MAX) OUTPUT)
AS
SET NOCOUNT ON
IF EXISTS (SELECT #Name = Name FROM Users WHERE UserID = #UserID)
BEGIN
SET #UserExists = 1
END
RETURN
Currently, it gives me an "SQL46010 :: Incorrect syntax near #Name." error.
If I remove IF EXISTS, the statement compiles fine!
Why does the IF EXISTS check cause a syntax error?

set #UserExists = 0;
select #Name = Name,
#UserExists = 1
from Users
where UserID = #UserID;

SET NOCOUNT ON
IF EXISTS (SELECT 1 FROM Users WHERE UserID = #UserID)
BEGIN
SET #UserExists = 1
/* do other stuff here select user name or whatever */
END
If there is a record for #UserID in users table Selecting 1 will return true for exists clause and control will enter the BEGIN..END block.

Related

Simple SQL UPDATE works in Console but not as Stored Procedure

I know this is a very simple SQL routine, so I am confused as why it does not actually UPDATE.
These work perfectly on their own:
UPDATE ourwebsite.dbo.dealer
SET Active = 0
WHERE dealercode = 12345
UPDATE ourwebsite.dbo.reps
SET username = username + '_LR-3.0'
WHERE dealercode = 12345
But when I try to make them into a Stored Procedure, they seem ok and execute ok, but nothing updates.
#DealerCode VARCHAR
AS
SET NOCOUNT ON;
UPDATE ourwebsite.dbo.dealer
SET Active = 0
WHERE DealerCode = #DealerCode
UPDATE ourwebsite.dbo.reps
SET username = username + '_LR-3.0'
WHERE DealerCode = #DealerCode
END TRY
I am sure I must be missing something?
Thank you for your attention.
You have not specified length for your parameter
#DealerCode VARCHAR
so by default, it takes as VARCHAR(1). You can print or select #DealerCode in your procedure to check the same.
from you query
UPDATE ourwebsite.dbo.dealer
SET Active = 0
WHERE dealercode = 12345
UPDATE ourwebsite.dbo.reps
SET username = username + '_LR-3.0'
WHERE dealercode = 12345
I assumed that dealercode type is numeric because you didn't put ('...') on 12345, you could try this query that i made some bit modification on it
AS #DealerCode NUMERIC
BEGIN TRANSACTION
BEGIN TRY
SET NOCOUNT ON;
UPDATE ourwebsite.dbo.dealer
SET Active = 0
WHERE DealerCode = #DealerCode
UPDATE ourwebsite.dbo.reps
SET username = username + '_LR-3.0'
WHERE DealerCode = #DealerCode
-- Commit the updates into the table
COMMIT TRANSACTION
END TRY
BEGIN CATCH
-- Execute rollback upon error retrieval routine.
ROLLBACK TRANSACTION
END CATCH;
It's hard without seeing your entire procedure, as there is an END TRY at the bottom with no BEGIN TRY, so your statements might not even be executed because the execution jumps to the CATCH. Also make sure you are not starting a transaction without committing it.
Aside from that, there is a difference between your manual query and your procedure which is the #DealerCode data type. In your manual query is an INT (or numeric) while in your SP it's a VARCHAR of undeclared length. Check which data type is your dealercode column from your ourwebsite.dbo.reps table and make sure your variable is the same type. Also always indicate the length of your VARCHAR fields.
Test the following code and it will update your records, as it's the same as your stand-alone query:
CREATE PROCEDURE dbo.TestUpdate
#dealercode INT
AS
BEGIN
UPDATE ourwebsite.dbo.dealer
SET Active = 0
WHERE dealercode = #dealercode
UPDATE ourwebsite.dbo.reps
SET username = username + '_LR-3.0'
WHERE dealercode = #dealercode
END
If this works, either remove your BEGIN TRY ... END TRY and your entire CATCH to see exactly the error you are getting, or make sure you do a RAISERROR on your catch with the corresponding ERROR_MESSAGE(). Example:
CREATE PROCEDURE dbo.YourProcedure
#dealercode VARCHAR(20)
AS
BEGIN
BEGIN TRY
-- Your operations here
SELECT 1 / 0
END TRY
BEGIN CATCH
DECLARE #v_ErrorMessage VARCHAR(MAX) = CONVERT(VARCHAR(MAX), ERROR_MESSAGE())
-- Rollback if you have to
RAISERROR (#v_ErrorMessage, 16, 1)
END CATCH
END

SQL While Exists Gets stuck in loop?

I have a cursor that is basically inserting new usernames in a table. I am trying to check for existing ones and append a '_1' or '_2' etc.
However it appears as though my code is getting stuck in a loop and never finishes.
Here is the code in question I belive:
SET #NUM = 1
--If Username already exists append number
While Exists ( select Null from CUSTOMTABLE Where USER_PRINCIPAL_NAME = #UPN)
BEGIN
SET #UPN = #UPN+'_'+RTRIM(CONVERT(varchar(10), #NUM))
SET #NUM = #NUM+1
END
I then go on to insert the value '#upn' into a table. Am I not doing this while exists correctly?
This should absolutely work. You aren't taking NULL into account and you also are adding # repeatedly, so your string will start looking like x#, x_##, x###, etc.
SET #NUM = 1
SET #UPN=ISNULL(#UPN,'')
DECLARE #OrgUPN NVARCHAR(2000)
SET #OrgUPN = #UPN
--If Username already exists append number
While Exists ( select Null from CUSTOMTABLE Where USER_PRINCIPAL_NAME = #UPN)
BEGIN
SET #UPN = #OrgUPN+'_'+RTRIM(CONVERT(varchar(10), #NUM))
SET #NUM = #NUM+1
END

create a sql procedure

im trying to create a procedure query with ms-sql for my game but Im kinda stucked..
Lets say,
I have a database with username and password rows.
I use the procedure query to select the username and password.
If everything is right, then the procedure will output the "result-code"
How I call the procedure query
BEGIN_DECLARE_SQLUNIT( SP_AccountSelect, "{ call AccountAuth(?,?) }" )
BEGIN_VARIABLE()
char m_szUserID[MAX_SIZE_USER_ID + 1];
char m_szUserPW[MAX_SIZE_USER_ID + 1];
int m_nResultCode;
END_VARIABLE()
BEGIN_PARAM(3)
PARAM_ENTRY_STR(SQL_PARAM_INPUT, m_szUserID)
PARAM_ENTRY_STR(SQL_PARAM_INPUT, m_szUserPW)
PARAM_ENTRY(SQL_PARAM_OUTPUT, m_nResultCode)
END_PARAM()
END_DECLARE_SQLUNIT()
procedure I have till now:
ALTER PROCEDURE [dbo].[AccountAuth] /* Procedure Name. */
#m_szUserID varchar(20),
#m_szUserPW varchar(50)
AS
SET NOCOUNT ON;
DECLARE #m_nResultCode int
select #m_nResultCode = 100
BEGIN
SELECT #m_szUserID = username, #m_szUserPW = password
FROM account
WHERE username = #m_szUserID;
END
my problem now is that I dont know how I make IFS like checking if the username is right, if the password is right.. because I always have to make different result code. Login wrong = result code 100, wrong username = 101, wrong password = 102..
Im searching for hours now but I cant find anything useful.
Does anyone know a link where I can find helpful things?
This is the most basic procedure you can write for a login call, but in real life application you will need to check logins which exists but maybe disabled, deleted, not logged in for over some period of time and bla bla. You can add as many as check needed to make sure only authorised people has access.
Try something like this.....
ALTER PROCEDURE [dbo].[AccountAuth] /* Procedure Name. */
#m_szUserID varchar(20),
#m_szUserPW varchar(50),
#m_nResultCode int OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Password varchar(50);
IF EXISTS(SELECT 1 FROM account WHERE username = #m_szUserID)
BEGIN
SELECT #Password = [password]
FROM account
WHERE username = #m_szUserID;
IF (#Password = #m_szUserPW)
BEGIN
SET #m_nResultCode = 1; -- 1 for successful login
END
ELSE
BEGIN
SET #m_nResultCode = 0; -- 0 for Unsuccessful login
END
END
ELSE
BEGIN
SET #m_nResultCode = 2; -- 2 if User Name does not exists
END
END
Calling Stored Procedure
DECLARE #OUT_Result INT;
EXECUTE [dbo].[AccountAuth] #m_szUserID = 'UserName'
,#m_szUserPW = '123456'
,#m_nResultCode = #OUT_Result OUTPUT
-- Now do what ever you need to do with #OUT_Result variable.

Problems with SQL EXISTS

I'm going mad on this one. I have the following SP:
ALTER PROCEDURE [BankImport].[spBI_getIsBatchUnique]
#batchName varchar = 500
AS
BEGIN
SET NOCOUNT ON;
IF (EXISTS (SELECT 1 FROM [ACN_Main].[BankImport].[tblBI_Jobs]
WHERE [batchNumber] = #batchName))
BEGIN
SELECT 1
END
ELSE
BEGIN
SELECT 0
END
END
GO
But whatever the request is, I always get back 0!
I tried to modify it in several ways but with no success!
What I need to do is check if there is a record with that batch number and return true, otherwise return false.
Any tip?
Thanks
Your input parameter looks a bit funny
#batchName varchar = 500
Should it have been this?
#batchName varchar(500)
Ie set the length of the varchar datatype, how you currently have it, 500 is the default value for the batchName param.
I think because you compare batchNumber and batchName, try
EXISTS (SELECT 1 FROM [ACN_Main].[BankImport].[tblBI_Jobs]
WHERE [batchName] = #batchName)

Duplicate Auto Numbers generated in SQL Server

Be gentle, I'm a SQL newbie. I have a table named autonumber_settings like this:
Prefix | AutoNumber
SO | 112320
CA | 3542
A whenever a new sales line is created, a stored procedure is called that reads the current autonumber value from the 'SO' row, then increments the number, updates that same row, and return the number back from the stored procedure. The stored procedure is below:
ALTER PROCEDURE [dbo].[GetAutoNumber]
(
#type nvarchar(50) ,
#out nvarchar(50) = '' OUTPUT
)
as
set nocount on
declare #currentvalue nvarchar(50)
declare #prefix nvarchar(10)
if exists (select * from autonumber_settings where lower(autonumber_type) = lower(#type))
begin
select #prefix = isnull(autonumber_prefix,''),#currentvalue=autonumber_currentvalue
from autonumber_settings
where lower(autonumber_type) = lower(#type)
set #currentvalue = #currentvalue + 1
update dbo.autonumber_settings set autonumber_currentvalue = #currentvalue where lower(autonumber_type) = lower(#type)
set #out = cast(#prefix as nvarchar(10)) + cast(#currentvalue as nvarchar(50))
select #out as value
end
else
select '' as value
Now, there is another procedure that accesses the same table that duplicates orders, copying both the header and the lines. On occasion, the duplication results in duplicate line numbers. Here is a piece of that procedure:
BEGIN TRAN
IF exists
(
SELECT *
FROM autonumber_settings
WHERE autonumber_type = 'SalesOrderDetail'
)
BEGIN
SELECT
#prefix = ISNULL(autonumber_prefix,'')
,#current_value=CAST (autonumber_currentvalue AS INTEGER)
FROM autonumber_settings
WHERE autonumber_type = 'SalesOrderDetail'
SET #new_auto_number = #current_value + #number_of_lines
UPDATE dbo.autonumber_settings
SET autonumber_currentvalue = #new_auto_number
WHERE autonumber_type = 'SalesOrderDetail'
END
COMMIT TRAN
Any ideas on why the two procedures don't seem to play well together, occasionally giving the same line numbers created from scratch as lines created by duplication.
This is a race condition or your autonumber assignment. Two executions have the potential to read out the same value before a new one is written back to the database.
The best way to fix this is to use an identity column and let SQL server handle the autonumber assignments.
Barring that you could use sp_getapplock to serialize your access to autonumber_settings.
You could use repeatable read on the selects. That will lock the row and block the other procedure's select until you update the value and commit.
Insert WITH (REPEATABLEREAD,ROWLOCK) after the from clause for each select.

Resources