Stored Procedure that accepts all table fields and updates those values - sql

I'm working through a couple practice questions and I've run across this problem, I keep getting an error when trying to execute the procedure that says
Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'Procedure'."
Can someone please help?
Write a procedure UpdateTitle that accepts all the Title table columns and will update the title with those values. Raise error messages for the following: The ISBN does not exist The Category and/or Publisher Codes are not valid.
Create PROCEDURE UpdateTitle (#ISBN char(10), #SuggestedPrice smallmoney,#NumberInStock smallint,#PublisherCode int,#CategoryCode int)
AS
BEGIN
IF #ISBN is null or #CategoryCode is null or #PublisherCode is null
BEGIN
RAISERROR ('ISBN,CategoryCode, or PublisherCode is not valid please enter valid data',16,1)
END
ELSE
BEGIN
IF (SELECT COUNT(*) FROM Title WHERE ISBN = #ISBN) = 0
BEGIN
RAISERROR ('ISBN does not exist.',16,1)
END
ELSE
BEGIN
SELECT 'Table Sucessfully Updated.';
UPDATE Title
SET SuggestedPrice = #SuggestedPrice
WHERE ISBN = #ISBN;
BEGIN
IF (SELECT COUNT(*) FROM Title WHERE ISBN = #ISBN) = 0
BEGIN
RAISERROR ('ISBN does not exist.',16,1)
END
ELSE
BEGIN
SELECT 'Table Sucessfully Updated.';
UPDATE Title
SET NumberInStock = #NumberInStock
WHERE ISBN = #ISBN;
END
BEGIN
IF (SELECT COUNT(*) FROM Title WHERE ISBN = #ISBN) = 0
BEGIN
RAISERROR ('ISBN does not exist.',16,1)
END
ELSE
BEGIN
SELECT 'Table Sucessfully Updated.';
UPDATE Title
SET PublisherCode = #PublisherCode
WHERE ISBN = #ISBN;
END
BEGIN
IF (SELECT COUNT(*) FROM Title WHERE ISBN = #ISBN) = 0
BEGIN
RAISERROR ('ISBN does not exist.',16,1)
END
ELSE
BEGIN
SELECT 'Table Sucessfully Updated.';
UPDATE Title
SET CategoryCode = #CategoryCode
WHERE ISBN = #ISBN;
END
END
END
END
END
END
END
GO
Then
Execute Procedure UpdateTitle #ISBN ='1021031040', #suggestedproce ='40' , #NumberInStock ='10', #PublisherCode = '200', #CategoryCode = '1'

Execute Procedure UpdateTitle ...
Should be:
EXEC dbo.UpdateTitle ...
Some other comments:
ISBN is no longer limited to 10 characters (this change happened in 2007, if you believe WikiPedia).
Always use the schema prefix when creating or referencing objects.
You only need to check that the ISBN is valid once. And you shouldn't do so using a count IMHO, especially since - presumably - that is the key and it could only ever return 0 or 1 anyway.
You shouldn't select "update successful" and then perform the update. You should make sure the update was successful before telling the user it was successful.
There is no reason to separate this out into multiple updates either.
Please be liberal with carriage returns, indenting and whitespace. The value in readability is worth the extra cost in typing it (since you only type it once, but you will read it multiple times).
Use RETURN; as an exit mechanism so that you don't have to nest IF and ELSE multiple times.
Always use SET NOCOUNT ON; at the beginning of your procedures.
You probably want to customize the message to tell the user which parameter(s) were invalid.
Oh yeah, and please future-proof your code by using semi-colons to terminate statements.
Here is a much more concise version that satisfies all of your requirements:
CREATE PROCEDURE dbo.UpdateTitle
#ISBN CHAR(10),
#SuggestedPrice SMALLMONEY,
#NumberInStock SMALLINT,
#PublisherCode INT,
#CategoryCode INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #msg VARCHAR(255);
IF #ISBN IS NULL OR #CategoryCode IS NULL OR #PublisherCode IS NULL
BEGIN
SELECT #msg = 'The following parameter(s) were invalid:'
+ CASE WHEN #ISBN IS NULL THEN ' #ISBN' ELSE '' END
+ CASE WHEN #CategoryCode IS NULL THEN ' #CategoryCode' ELSE '' END
+ CASE WHEN #PublisherCode IS NULL THEN ' #PublisherCode' ELSE '' END;
RAISERROR (#msg, 11, 1);
RETURN;
END
IF NOT EXISTS (SELECT 1 FROM dbo.Title WHERE ISBN = #ISBN)
BEGIN
SET #msg = 'ISBN %s does not exist.';
RAISERROR(#msg, 11, 1, #ISBN);
RETURN;
END
BEGIN TRY
UPDATE dbo.Title
SET SuggestedPrice = #SuggestedPrice,
NumberInStock = #NumberInStock,
PublisherCode = #PublisherCode,
CategoryCode = #CategoryCode
WHERE ISBN = #ISBN;
SELECT 'Update successful.';
END TRY
BEGIN CATCH
SET #msg = ERROR_MESSAGE();
RAISERROR(#msg, 11, 1);
END CATCH
END
GO

Related

How to union multiple select statements while they are not near together?

I have an sql query which check for existence of some records, if those records exist rise error for them otherwise insert them to database. In my query as I need to return error messages for every record, I need to select some custom texts, problem is that they are showing as separate tables, not in one table, which I want (as I am calling this query from nodejs app and it returns an array for me so it only returns first table (error message) for me).
I searched and reach these two options:
1- Use UNION (which is not solving my case)
2- Insert all records in another table and then get all it's record (which isn't beautiful! :) )
DECLARE #errorCOUNT int
SET #errorCOUNT = 0
BEGIN TRANSACTION [Tran1]
IF EXISTS (SELECT * FROM Categories WHERE CategoryName = 'myCat1')
BEGIN
SELECT 'This is error for is = 4' As err
SET #errorCOUNT = #errorCOUNT + 1
END
ELSE
BEGIN
INSERT INTO Categories VALUES ('myCat1')
END
----------------------------
IF EXISTS (SELECT * FROM Categories WHERE CategoryName = 'myCat2')
BEGIN
SELECT 'This is error for is = 5' AS err
SET #errorCOUNT = #errorCOUNT + 1
END
ELSE
BEGIN
INSERT INTO Categories VALUES ('myCat2')
END
----------------------------
IF #errorCOUNT > 0
BEGIN
ROLLBACK TRANSACTION [Tran1]
END
ELSE
BEGIN
COMMIT TRANSACTION [Tran1]
END
As I mentioned I want all these select statements to be shown in one table so they return to my server as one array.
I just think it is good to mention that my query completes in a loop, so it may have different amount of IF...ELSE (between --- lines).
I hope I was clear. Thanks in advance.
Try this one, would work:
BEGIN TRANSACTION [Tran1]
DECLARE #err AS TABLE ( msg NVARCHAR(MAX) NOT NULL )
DECLARE #errorCOUNT AS INT = 0
IF EXISTS (SELECT * FROM Categories WHERE CategoryName = 'myCat1')
BEGIN
INSERT INTO #err (msg) VALUES ('This is error for is = 4')
SET #errorCOUNT = #errorCOUNT + 1
END
ELSE
BEGIN
INSERT INTO Categories VALUES ('myCat1')
END
IF EXISTS (SELECT * FROM Categories WHERE CategoryName = 'myCat2')
BEGIN
INSERT INTO #err (msg) VALUES ('This is error for is = 5')
SET #errorCOUNT = #errorCOUNT + 1
END
ELSE
BEGIN
INSERT INTO Categories VALUES ('myCat2')
END
IF #errorCOUNT > 0
BEGIN
SELECT * FROM #err
ROLLBACK TRANSACTION [Tran1]
END
ELSE
BEGIN
COMMIT TRANSACTION [Tran1]
END
I don't understand what you're really want to do there, but here is a tip using MERGE statement and OUTPUT clause maybe it's what you're after
DECLARE #T TABLE(CategoryName VARCHAR(45));
MERGE INTO T
USING (VALUES('MyCat1'), ('MyCat2')) TT(CategoryName)
ON T.CategoryName = TT.CategoryName -- Or <> instead of =
WHEN NOT MATCHED THEN
INSERT VALUES(TT.CategoryName)
OUTPUT TT.CategoryName INTO #T;
SELECT CASE WHEN CategoryName = 'MyCat1'
THEN 'This is error for is = 4'
WHEN CategoryName = 'MyCat2'
THEN 'This is error for is = 5'
END Res
FROM #T;
Also, I don't think you need to the #ErrorCount variable, since you already have ##ROWCOUNT which you can use it instead.
Here is a db<>fiddle where you can see how it's working.

if condition not working

I want to show a message if record is not in the table.
I wrote this small piece of code, but it's giving me an error.
create procedure abc(#id varchar(25))
as
declare #msg1 as varchar(55)
begin
select id,fname,lname from student where id=#id
--up to this is working correctly
--for showing msg i write down this lince of code
if id=#id
select #msg=“correct record“
else
select #msg=“record not found“
end
end
Add an EXISTS check instead of selecting the records
IF EXISTS ( select 1 from student where id=#id)
BEGIN
SET #msg = 'correct record'
END
ELSE
BEGIN
SET #msg = 'incorrect record'
END
Are you trying to return the value of #msg? If yes, add SELECT #msg at the end.
Use single quotes not double. And check for any results with ##rowcount
create procedure abc(#id varchar(25))
as
begin
select id,fname,lname from student where id=#id
if ##rowcount > 0
select 'correct record' as msg
else
select 'record not found' as msg
end
end

expression of non-boolean type specified when merging?

I have the following code to create a stored procedure, but I seem to be getting a lot of errors below this line:
ON (Target.Email = Source.Email AND Target.PromoName = Source.PromoName)
The error on this line is "expression of non-boolean type specified".
What am I doing wrong here?
CREATE PROCEDURE [dbo].InsertUpdateBasicPromoEntry
#Email nvarchar(100)
,#PromoName varchar(100)
,#MaxEntries tinyint
AS
BEGIN
SET NOCOUNT ON;
MERGE [dbo].[BasicCodePromoEntries] AS Target
USING (
SELECT
#Email as Email
,#PromoName as PromoName
) AS Source
ON (Target.Email = Source.Email AND Target.PromoName = Source.PromoName)
WHEN MATCHED
THEN
BEGIN
IF Target.PeriodExpires < GETDATE()
BEGIN
UPDATE SET
Target.PeriodExpires = GETDATE()
,Target.PeriodEntries = 1
END
ELSE IF Target.PeriodExpires > GETDATE() AND Target.PeriodEntries < #MaxEntries
BEGIN
UPDATE SET
Target.PeriodEntries = Target.PeriodEntries + 1
END
ELSE
BEGIN
RETURN 1
END
RETURN 0
END
WHEN NOT MATCHED BY Target
THEN
BEGIN
INSERT INTO Target (Email, PromoName, PeriodEntries, PeriodExpires) VALUES (#Email, #PromoName, 1, DATEADD(day, 1, GETDATE()))
RETURN 0
END
END
PS: Every BEGIN and END is underlined, saying, incorrect syntax near...

how to track the stored procedure execution by using PRINT statements?

I Have a stored procedure and its task is that, It will take a file and transfer the records into TEMP table after that will do validation accordingly and then it will put the records into Main Staging table.(Aditionally we have 3 more tables for validation purpose and those are StockIntegrityCheck, IntegrityErrorLog, InterfaceIntegrity )
Problem: When an empty file has come(0KB file), It is not supposed to put any entry any of the tables. but it is putting an entry in InteggrityErrorLog Table which is not needed. I want to correct the stored procedure accordingly?
Here is SP:
USE [PARAM.DB]
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo]. [usp_LDMDB_GMIH_DSOA_STAGING]') AND type in (N'P'))
DROP PROCEDURE [dbo].[usp_LDMDB_GMIH_DSOA_STAGING]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*
Description: This program will insert records from LDMDB_GMIH_DSO_A_STAGING_TEMP table to LDMDB_GMIH_DSO_A_STAGING table
*/
CREATE PROCEDURE [dbo].[usp_LDMDB_GMIH_DSOA_STAGING]
AS
DECLARE
#DATA VARCHAR(200),
#HDRDATA VARCHAR(200),
#FLAG INT,
#ErrStmt VARCHAR(500),
#ProcessDate datetime,
/* Stock Integrity Changes for I0180 Starts */
#Integritycheck INT,
#Totalcount VARCHAR(10),
#Totalquantity VARCHAR(10),
#TrackingID VARCHAR(20),
#count INT,
#quantity INT;
/* Stock Integrity Changes for I0180 Ends */
BEGIN
BEGIN TRANSACTION
select #ProcessDate = GETDATE()
/* Stock Integrity Changes for I0180 Starts */
SET #count = 0;
SET #quantity = 0;
SET #Integritycheck = (SELECT Value from dbo.LDMStockIntegrityCheck where interfacename = 'I0180' and filename = 'PIZ.HW.NDC.CALLOFF.FILE.LDM');
/* Stock Integrity Changes for I0180 Ends */
DECLARE CUR_JOB CURSOR LOCAL
FOR
SELECT DATA FROM LDMDB_GMIH_DSO_A_STAGING_TEMP ORDER BY ROW_ID
OPEN CUR_JOB
IF ##ERROR <> 0
BEGIN
SET #ErrStmt= 'Error while Opening the Cursor'
GOTO ERRHDL
END
-- LOOPING THROUGH EACH RECORD.
FETCH NEXT FROM CUR_JOB INTO #DATA
IF ##ERROR <> 0
BEGIN
SET #ErrStmt= 'Error while Fetching the Record From Cursor'
GOTO ERRHDL
END
WHILE ##FETCH_STATUS = 0
BEGIN
SET #FLAG = 0
IF(SUBSTRING (#DATA,1,1)= '1')
BEGIN
SET #HDRDATA = #DATA
SET #FLAG = 0
/* Stock Integrity Changes for I0180 Starts */
IF (#Integritycheck = 1 )
BEGIN
SET #TrackingID = SUBSTRING(#data,19,20);
SET #Totalcount = CONVERT(INT,SUBSTRING(#data,39,10));
SET #Totalquantity = CONVERT(INT,SUBSTRING(#data,49,15));
END
/* Stock Integrity Changes for I0180 Ends */
END
IF(SUBSTRING (#DATA,1,1)= '5')
BEGIN
SET #FLAG = 1
/* Stock Integrity Changes for I0180 Starts */
IF (#Integritycheck = 1 )
BEGIN
SET #count= #count +1 ;
SET #quantity = #quantity + CONVERT(INT,SUBSTRING(#data,45,09)) ;
END
/* Stock Integrity Changes for I0180 Ends */
END
IF (#FLAG = 1)
BEGIN
INSERT INTO LDMDB_GMIH_DSO_A_STAGING
( FileCreationDate,
GenerationNumber,
WAREHOUSE_CODE,
ALLOC_RUN_DATE,
SUPP_CODE,
SUPP_LOC_CODE,
PICKSHEET_NUM,
UPC,
DELIVERY_POINT,
STORE_NUM,
VALUE_TOTAL_SEND,
COUNTRY_CODE,
DISPATCH_PRIORITY,
QTY,
ProcessDate
)
SELECT LTRIM(RTRIM(SUBSTRING(convert( varchar(20),(CONVERT(datetime, SUBSTRING (#HDRDATA,2,8), 111)),121),1,10))) FileCreationDate,
LTRIM(RTRIM(SUBSTRING (#HDRDATA,10,9))) GenerationNumber,
LTRIM(RTRIM(SUBSTRING (#DATA,2,3))) WAREHOUSE_CODE ,
LTRIM(RTRIM(SUBSTRING(convert( varchar(20),(CONVERT(datetime, SUBSTRING (#DATA,5,8), 111)),121),1,10))) ALLOC_RUN_DATE,
RIGHT(REPLICATE('0',10) + LTRIM(RTRIM(SUBSTRING (#DATA,13,4))),5) SUPP_CODE,
LTRIM(RTRIM(SUBSTRING (#DATA,17,5))) SUPP_LOC_CODE,
LTRIM(RTRIM(SUBSTRING (#DATA,22,6))) PICKSHEET_NUM,
LTRIM(RTRIM(SUBSTRING (#DATA,29,8))) UPC,
LTRIM(RTRIM(SUBSTRING (#DATA,37,4))) DELIVERY_POINT,
LTRIM(RTRIM(SUBSTRING (#DATA,41,4))) STORE_NUM,
(SELECT CASE WHEN cast(SUBSTRING (#DATA,45,9) AS NUMERIC) < 0 THEN ('-' + LTRIM(RTRIM(SUBSTRING (#DATA,46,8)))) ELSE LTRIM(RTRIM(SUBSTRING (#DATA,45,9))) END) VALUE_TOTAL_SEND,
LTRIM(RTRIM(SUBSTRING (#DATA,54,3))) COUNTRY_CODE,
LTRIM(RTRIM(SUBSTRING (#DATA,57,2))) DISPATCH_PRIORITY,
LTRIM(RTRIM(SUBSTRING (#DATA,59,9))) QTY,
#ProcessDate
IF ##ERROR <> 0
BEGIN
SET #ErrStmt= 'Error while Inserting the Records into the Staging Table'
GOTO ERRHDL
END
END
FETCH NEXT FROM CUR_JOB INTO #DATA
END
CLOSE CUR_JOB
DEALLOCATE CUR_JOB
IF (#Integritycheck = 0)
BEGIN
COMMIT TRANSACTION
END
FINISH:
BEGIN
/* Stock Integrity Changes for I0180 Starts */
IF (#Integritycheck = 0 )
BEGIN
SET #ErrStmt= 'Inserting the Records into the Staging Table Successful'
PRINT 'Inserting the Records into the Staging Table Successful'
Return
END
ELSE
BEGIN
IF ((#count = #Totalcount)AND(#quantity = #Totalquantity))
BEGIN
INSERT INTO dbo.LDMInterfaceIntegrity VALUES ('I0180','PIZ.HW.NDC.CALLOFF.FILE.LDM',#TrackingID,#Totalquantity,#Totalcount,#ProcessDate);
COMMIT TRANSACTION;
BEGIN
SET #ErrStmt= 'Inserting the Records into the Staging Table Successful';
Return
END
END
ELSE
BEGIN
ROLLBACK TRANSACTION;
IF (#count <> #Totalcount)
BEGIN
INSERT INTO dbo.LDMIntegrityErrorLog VALUES ('I0180','PIZ.HW.NDC.CALLOFF.FILE.LDM',#TrackingID,'Count Mismatch',#ProcessDate);
PRINT 'Count mismatch';
END
ELSE
BEGIN
INSERT INTO dbo.LDMIntegrityErrorLog VALUES ('I0180','PIZ.HW.NDC.CALLOFF.FILE.LDM',#TrackingID,'Quantity Mismatch',#ProcessDate);
PRINT 'Quantity Mismatch';
END
RETURN;
END
END
/* Stock Integrity Changes for I0180 Ends */
END
ERRHDL:
BEGIN
ROLLBACK TRANSACTION
RETURN
END
END
Use RAISERROR ... WITH NOWAIT as per this (among many others): http://www.mssqltips.com/sqlservertip/1660/using-the-nowait-option-with-the-sql-server-raiserror-statement/
At certain error levels, RAISERROR isn't actually considered an error, so it can be used as an alternative to PRINT.
Sql server management studio provide facility to debug the store procedure . by debugging the store procedure you can check value of each variable and which statement executed during execution of the store procedure .
just put the debug point in statement in store procedure and press debug .
Check http://www.youtube.com/watch?v=618LE_FZCxI

Problems with IF EXISTS()

When I try to run update a credit card type by passing in the #ID and #Name I get an error that says:
Msg 2786, Level 16, State 1, Procedure sp_SaveCreditCardType, Line 29
The data type of substitution parameter 1 does not match the expected type of the format specification.
The problem is with my piece of code that checks for the existence of the id in the CreditCardTypes table using this statement:
-- make sure the ID is a valid number
IF NOT EXISTS (SELECT * FROM CreditCardTypes WHERE ID = #ID)
BEGIN
RAISERROR('The Credit Card ID ''%s'' does not exist. Update Failed.', 15, 1, #ID)
RETURN -100
END
Does anyone have any idea why this may be giving me an error? I have seen many examples of using the the if exists() in this way, but for some reason it's giving me an error.
Here is the entire proc.
CREATE PROCEDURE dbo.sp_SaveCreditCardType
(
#ID int = null,
#Name varchar(50),
#Description varchar(150) = null
)
AS
DECLARE
#Err INT
BEGIN
SET NOCOUNT ON
-- check to make sure a Name was passed in
IF #Name IS NULL
BEGIN
RAISERROR('A Name was not specified. Execution aborted.', 15, 1, #Name)
RETURN -100
END
-- check to see if an ID is passed
IF #ID IS NOT NULL AND #ID <> 0
BEGIN
-- make sure the ID is a valid number
IF NOT EXISTS (SELECT * FROM CreditCardTypes WHERE ID = #ID)
BEGIN
RAISERROR('The Credit Card ID ''%s'' does not exist. Update Failed.', 15, 1, #ID)
RETURN -100
END
-- update an existing credit card type
UPDATE CreditCardTypes
SET Name = #Name,
[Description] = #Description
WHERE ID = #ID
SET #Err = ##ERROR
IF #Err <> 0 GOTO ErrorHandler
END
ELSE
BEGIN
-- first check to make sure the credit card type doesn't already exist
IF NOT EXISTS (SELECT * FROM CreditCardTypes WHERE Name = #Name)
BEGIN
-- insert a new credit card type
INSERT INTO CreditCardTypes (Name, [Description])
VALUES (#Name, #Description)
SET #Err = ##ERROR
IF #Err <> 0 GOTO ErrorHandler
END
ELSE
RAISERROR('The Credit Card Type ''%s'' already exists. Insert failed.', 15, 1, #Name)
RETURN -100
END
SET #Err = ##ERROR
IF #Err <> 0 GOTO ErrorHandler
RETURN 0
ErrorHandler:
RAISERROR('An error occured while saving the credit card type ''%s''', 16, 1, #Name) WITH LOG
RETURN -100
END
GO
Change:
RAISERROR('The Credit Card ID ''%s'' does not exist. Update Failed.', 15, 1, #ID)
To:
RAISERROR('The Credit Card ID ''%d'' does not exist. Update Failed.', 15, 1, #ID)
%s is used for substituting strings... but %d is the substitution parameter for ints.
RAISERROR in MSDN