Is this T-SQL stored procedure written correctly? - sql-server

I am new to SQL Server and T-SQL, but I do have some experience building applications in MS Access.
This stored procedure runs fine when I execute it from the application, however when I am debugging it in SSMS, I get an error
Unable to Step. Invalid Operation.
but it will allow me to step through. Based on my research, it seems like I am creating a race condition but I have not been able to correctly fix the issue. I would also appreciate any advice to optimize this or fix any issues that are apparent.
What the code does:
This code is to enter a new customer into the database. The first select statement looks for an existing ID. If the ID is null, it will add a new customer. If the ID is not null, it will not add the customer. The same goes for the second IF statement to check if #pName2 and #pName3 are null before inserting these values.
Here is my code:
#pUID nvarchar(16) = null,
#pName1 nvarchar(50) = null,
#pName2 nvarchar(50) = null,
#pName3 nvarchar(50) = null,
#pAddress1 nvarchar(30) = null,
#pAddress2 nvarchar(30) = null,
#pAddress3 nvarchar(30) = null,
#pZipCode nvarchar(30) = null
AS
BEGIN
SET NOCOUNT ON;
DECLARE #ID INT
SELECT #ID = ID FROM tblCustomer WHERE strUID = #pUID
IF #ID IS NULL
BEGIN
DECLARE #Customer_ID INT
INSERT INTO tblCustomer(strUID, strName)
VALUES(#pUID, #pName1)
SET #Customer_ID = ##IDENTITY
IF (#pName2 <> '') OR (#pName3 <> '')
BEGIN
INSERT INTO tblSecondaryCustomer(CustomerID, strName2, strName3)
VALUES(#Customer_ID, #pName2, #pName3)
END
INSERT INTO tblAddress(CustomerID, strAddress1, strAddress2, strAddress3, strZipCode)
VALUES(#Customer_ID, #pAddress1, #pAddress2, #pAddress3, #pZipCode)
END
END

Try replacing your IF statement with the following:
IF NOT EXISTS(SELECT ID FROM tblCustomer WHERE strUID = #pUID)
It doesn't seem your using #ID other than a check for existence...and you can use the ISNULL function to make sure you cover NULL cases...
IF (ISNULL(#pName2,'') <> '') OR (ISNULL(#pName3,'') <> '')
HTH
Dave

Related

Inserting into MS SQL DB with procedure not working

I've tried a lot of googling and following some tutorials. I'm using MS SQL and trying to make a simple User table and salt and hashing the password, haven't gotten to the salting part, yet.
The table looks like this:
CREATE TABLE dbo.[User] (
UserID INT IDENTITY(1,1) NOT NULL,
Email NVARCHAR(45) NOT NULL,
Password BINARY(64) NOT NULL,
FirstName NVARCHAR(45) NULL,
LastName NVARCHAR(45) NULL,
CONSTRAINT [PK_User_UserID] PRIMARY KEY CLUSTERED (UserID ASC)
)
And the procedure looks like this:
ALTER PROCEDURE dbo.[uspAddUser]
#pEmail NVARCHAR(45),
#pPassword NVARCHAR(45),
#pFirstName NVARCHAR(45) = NULL,
#pLastName NVARCHAR(45) = NULL,
#responseMessage NVARCHAR(250) OUTPUT
AS
BEGIN
SET NOCOUNT ON
BEGIN TRY
INSERT INTO dbo.[User] (Email, Password, FirstName, LastName)
VALUES (#pEmail, HASHBYTES('SHA_512', #pPassword), #pFirstName, #pLastName)
SET #responseMessage = 'Success'
END TRY
BEGIN CATCH
SET #responseMessage = ERROR_MESSAGE()
END CATCH
END
When I try to insert with the procedure it won't work:
DECLARE #responseMessage NVARCHAR(250)
EXEC dbo.[uspAddUser]
#pEmail = N'Admin#email.com',
#pPassword = N'123',
#pFirstName = N'Admin',
#pLastName = N'Administrator',
#responseMessage=#responseMessage OUTPUT
SELECT *
FROM [dbo].[User]
No results are shown. After inserting normally and then retrieving the results it shows the newly created tuple but with the ID auto incremented like other tuples were created. I'm not really sure where the problem is and would be grateful if someone else understood.
EDIT:
SOLVED
Apparently the fault was I used the wrong kind of sha hash. Instead of using SHA_512 I should've used SHA2_512.
HASHBYTES('SHA_512', #pPassword) returns null so that insert query gets aborted. Instead, you can use algorithms SHA2_512 or SHA2_256 or any other encryption algorithm you want.
Check out this link for more info.

Column values as stored procedure input

I have the following code when inputting parameters for a SP:
USE [MDAmanager]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[spCougarExport]
#PropertyCodeString = NULL,
#Date = NULL,
#InferDate = NULL,
#TransactionCodeString = NULL
SELECT 'Return Value' = #return_value
GO
For the #PropertyCodeString I would like to pass the values from a seperate table with all the property codes.
Below is an example of the property codes
What I'm trying to achieve is have the SP always return all properties and not require updating the property codes when a new property is added.
Any assistance or direction would be greatly appreciated.
Assuming you are able to amend your SP then you can utilise a user defined table type e.g.
CREATE TYPE [dbo].[PropertyCode_UDT] AS TABLE
( [PropertyCode] [bigint] NOT NULL
)
GO
DECLARE #PCTab [dbo].[PropertyCode_UDT]
;
INSERT INTO #PCTab
( [PropertyCode]
)
SELECT PC.[PropertyCode]
FROM [dbo].[PropertyCode] PC
;
DECLARE #return_value int
EXEC #return_value = [dbo].[spCougarExport]
#PropertyCode = #PCTab,
#Date = NULL,
#InferDate = NULL,
#TransactionCodeString = NULL
;
Your Sp will need to be amended to accept the correct type for #PropertyCode and you can just join your query within the SP on this table to get all the Property Codes
Eg
CREATE PROCEDURE [dbo].[spCougarExport]
#Date [date]
, #InferDate [date]
, #TransactionCodeString [nvarchar] (MAX)
, #PropertyCode PropertyCode_UDT READONLY
AS BEGIN;
.......
SELECT ...
FROM #PropertyCode atPC

how to write update procedure with scope identity

My insert procedure is working fine the way i want. But update is not working with scope identity.
SET ANSI_NULLS ON
ALTER PROCEDURE [dbo].[spr_unitCreation]
(
#Unit_Name VARCHAR(50) = NULL,
#Unit_Abbreviation VARCHAR(50) = NULL,
#Unit_type VARCHAR(50) = NULL,
#Decimal_Places VARCHAR(50) = NULL,
#Description VARCHAR(50) = NULL,
#Super_Unit VARCHAR(50) = NULL,
#Per_Unit VARCHAR(50) = NULL,
#unit_Id INT OUTPUT,
#abc VARCHAR(50) = NULL
)
AS
BEGIN
IF #abc = 'update' BEGIN
SET NOCOUNT ON;
SELECT #unit_Id AS SCOPE_IDENTITY
UPDATE tbl_UnitCreation
SET Unit_Name = #Unit_Name,
Unit_Abbreviation = #Unit_Abbreviation,
Unit_type = #Unit_type,
Decimal_Places = #Decimal_Places,
Description = #Description,
Super_Unit = #Super_Unit,
Per_Unit = #Per_Unit
WHERE unit_Id = #unit_Id
END
END
SELECT * FROM tbl_UnitCreation
SCOPE_IDENTITY returns the last identity value inserted into an identity column. You are not inserting a row.
To update a row all you need is to pass a value to #unit_Id when executing [spr_unitCreation]. Also remove the line "SELECT #unit_Id AS SCOPE_IDENTITY" from your code.
Based on the comments, you need to find the correct id by searching on relevant details. So you can get the id like this:
SELECT #unit_Id = unit_Id
FROM tbl_UnitCreation
WHERE Unit_Name=#Unit_Name -- NB: Ensure this column contains your relevant details
Another commonly used option is to use the OUTPUT clause of the UPDATE statement, inserting all the updated/"inserted" primary keys and Unit_name into a tablevariable.
https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql?view=sql-server-2017

SQL Server procedure update and coalesce issue

So I am making a very simple update procedure, like I have done before, but when I run the execution through it, it does not update. I have looked this over several times and do not see any error in why it wouldn't cause the update to pass through it. My manual updates are working fine, so I am thinking I am either missing something super-obvious or this is something going on with the coalesce function. Any help would be great. The more eyes the merrier.
USE AdventureWorks2012
GO
CREATE PROCEDURE UpdateCreditCard
#CreditCardID INT,
#CardType nvarchar(50) = NULL,
#CardNumber nvarchar(25) = NULL,
#ExpMonth tinyint = NULL,
#ExpYear smallint = NULL
AS
BEGIN
UPDATE [Sales].[CreditCard]
SET
#CardType = COALESCE(#CardType,CardType),
#CardNumber = COALESCE(#CardNumber,CardNumber),
#ExpMonth = COALESCE(#ExpMonth,ExpMonth),
#ExpYear = COALESCE(#ExpYear,ExpYear)
FROM Sales.CreditCard
WHERE #CreditCardID = CreditCardID
END
EXECUTE UpdateCreditCard
#CreditCardID = 19267,
#CardType = 'MasterCard',
#CardNumber = '99999999',
#ExpMonth = 4,
#ExpYear = 2025
You are updating the variables not the columns in CreditCard table.
.....
SET
#CardType = COALESCE(#CardType,CardType), -- here you are updating the #CardType variable
.....
Try this.
CREATE PROCEDURE UpdateCreditCard
#CreditCardID INT,
#CardType nvarchar(50) = NULL,
#CardNumber nvarchar(25) = NULL,
#ExpMonth tinyint = NULL,
#ExpYear smallint = NULL
AS
BEGIN
UPDATE [Sales].[CreditCard]
SET
CardType = COALESCE(#CardType,CardType),
CardNumber = COALESCE(#CardNumber,CardNumber),
ExpMonth = COALESCE(#ExpMonth,ExpMonth),
ExpYear = COALESCE(#ExpYear,ExpYear)
FROM Sales.CreditCard
WHERE CreditCardID=#CreditCardID
END

How to get data back from stored procedure

I'm trying to debug\execute a SP from t-sql (sql server 2008) and when I execute the following sql it returns only a message 'Command(s) completed successfully'.
I know the SP is returning the data in a table via the #RETURN_VALUE parameter, how do I get this to display in sql query window.
exec STARMS.dbo.GetMetaData ##Assembly=13366,##Namespace=NULL,##ParameterName=NULL,##Standard=0,##Timestamp=NULL
The SP looks something like this ( removed the main body) the interesting part is the creation of the temp table and then returning the contents of the temp table:
CREATE PROCEDURE [dbo].[GetMetaData]
##Assembly Sql_Variant = NULL,
##Namespace Varchar(30) = NULL,
##ParameterName Varchar(40) = NULL,
##Standard Bit = 0,
##Timestamp DateTime = NULL
AS
SET NOCOUNT ON
DECLARE #ResultTable TABLE (AssemblyId Int, Namespace Varchar(30), ParameterName Varchar(40), Value Varchar(100))
-- Does loads of stuff and then inserts into #ResultTable table...
SET NOCOUNT OFF
-- Return the result
SELECT AssemblyId, Namespace, ParameterName, [Value]
FROM #ResultTable
RETURN
Note: the reason I'm asking the question is because I'm trying to look at the performance of the SP in SQL Server 2008 and I'm unsure why this doesn't return the data in the query window.
Check your full code of SP, may be somewhere there is a RETURN statement, so - the SP will not return any data (pay attention on IF SomeContition IS TRUE RETURN):
CREATE PROCEDURE [dbo].[GetMetaData]
##Assembly Sql_Variant = NULL,
##Namespace Varchar(30) = NULL,
##ParameterName Varchar(40) = NULL,
##Standard Bit = 0,
##Timestamp DateTime = NULL
AS
SET NOCOUNT ON
DECLARE #ResultTable TABLE (AssemblyId Int, Namespace Varchar(30), ParameterName Varchar(40), Value Varchar(100))
-- Does loads of stuff and then inserts into #ResultTable table...
IF SomeContition IS TRUE RETURN
SET NOCOUNT OFF
-- Return the result
SELECT AssemblyId, Namespace, ParameterName, [Value]
FROM #ResultTable
RETURN

Resources