SQL Server: help with a simple stored procedure? - sql

I'm trying to create a simple stored procedure which I can use to write data to a log table. I'm a noob in stored procedures, so what I'm missing here? I get an error saying:
Msg 201, Level 16, State 4, Procedure toLog, Line 0
Procedure or function 'toLog' expects parameter '#messageTime', which was not supplied.
How to modify this code to get this work?
USE <database>
GO
IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'logTable')
DROP TABLE dbo.logTable
GO
CREATE TABLE dbo.logTable (
messageTime DATETIME NULL,
etlJobName NVARCHAR(40) NULL,
whereTo VARCHAR(10) NOT NULL,
messag VARCHAR(255) NULL
)
/*************** procedure ************/
--DROP PROC dbo.toLog
CREATE PROCEDURE dbo.toLog
#messageTime DATETIME,
#etlJobName NVARCHAR(60) = 'unknown',
#whereTo NVARCHAR(20) = 'print',
#messag NVARCHAR(255) = 'empty'
AS
BEGIN
SET #messageTime = GETDATE()
IF #whereTo = 'log' OR #whereTo = 'logandprint'
INSERT INTO logTable(messageTime, etlJobName, whereTo, messag)
VALUES (#messageTime, #etlJobName, #whereTo, #messag)
IF #whereTo = 'print' OR #whereTo = 'logandprint'
PRINT CONVERT(VARCHAR, GETDATE(), 113) + ', ' + #etlJobName + ', ' + #whereTo + ', ' + ', ' + #messag
END
GO
--execution
EXEC dbo.toLog #whereTo = 'log'

It's because your toLog sproc is expecting you to supply the #messageTime parameter, which you haven't done, and it doesn't have a default value like the other parameters.
As you set the #messageTime always to GETDATE() inside the sproc, it looks like you just want to scrap that parameter:
CREATE PROCEDURE dbo.toLog
#etlJobName NVARCHAR(60) = 'unknown',
#whereTo NVARCHAR(20) = 'print',
#messag NVARCHAR(255) = 'empty'
AS
BEGIN
IF #whereTo = 'log' OR #whereTo = 'logandprint'
INSERT INTO logTable(messageTime, etlJobName, whereTo, messag)
VALUES (GETDATE(), #etlJobName, #whereTo, #messag)
IF #whereTo = 'print' OR #whereTo = 'logandprint'
PRINT CONVERT(VARCHAR, GETDATE(), 113) + ', ' + #etlJobName + ', ' + #whereTo + ', ' + ', ' + #messag
END
Or, if you do want to be able to pass in a datetime yourself:
CREATE PROCEDURE dbo.toLog
#messageTime DATETIME = null,
#etlJobName NVARCHAR(60) = 'unknown',
#whereTo NVARCHAR(20) = 'print',
#messag NVARCHAR(255) = 'empty'
AS
BEGIN
IF (#messagetime IS NULL) SET #messagetime = GETDATE()
IF #whereTo = 'log' OR #whereTo = 'logandprint'
INSERT INTO logTable(messageTime, etlJobName, whereTo, messag)
VALUES (#messageTime, #etlJobName, #whereTo, #messag)
IF #whereTo = 'print' OR #whereTo = 'logandprint'
PRINT CONVERT(VARCHAR, #MessageTime, 113) + ', ' + #etlJobName + ', ' + #whereTo + ', ' + ', ' + #messag
END

When You are creating the stored procedure with parameters, At any cause we need to pass the parameter values, when executing stored procedure.
Example 1:
EXEC dbo.toLog '','','',''
In the above line when you are executing the stored procedure , it will not thrown any errors. because passed the Parameters values are a NULL.
Example 2:
EXEC dbo.toLog '','','log',''
In the above line when you are executing the stored procedure , it will not thrown any errors, data will be Logged in your table. Based on the Stored procedure inside script logic

Related

What's the limit of a variable in T-SQL? Why does my variable prints out as NULL?

I'm creating a stored procedure with the following code:
CREATE OR ALTER PROCEDURE Insert_Into_Table
#Origin VARCHAR(255),
#Destination VARCHAR(255),
#Origin_Columns VARCHAR (4000),
#Destination_Columns VARCHAR (4000),
#Delete_Date_Column_Name VARCHAR(63), --Nullable
#Delete_Period_Months INT -- Nullable
AS
BEGIN TRY
DECLARE #insert_query VARCHAR(4000) = NULL;
DECLARE #delete_query VARCHAR(4000) = NULL;
DECLARE #check_query VARCHAR (4000) = NULL;
DECLARE #Date_To_Delete DATETIME = CAST(DATEADD(MONTH, -#Delete_Period_Months, GETDATE()) AS DATETIME);
-- Table names cannot be referenced directly in SPs, so we bypass
-- this issue by declaring a variable containing the query
IF #Delete_Date_Column_Name IS NOT NULL
OR #Delete_Period_Months IS NOT NULL
SET #delete_query = 'DELETE FROM ' + #Destination + ' WHERE ' +
#Delete_Date_Column_Name + ' >= ' + CONCAT(CHAR(39),CAST(#Date_To_Delete AS VARCHAR(255)),CHAR(39));
ELSE
PRINT N'Missing or no values provided for table deletion. Only executing copy';
CREATE TABLE #temptable (count INT)
SET #check_query = 'INSERT INTO #temptable SELECT TOP 1 1 AS count FROM ' + #Origin
EXECUTE(#check_query)
SET #insert_query = 'INSERT INTO' + QUOTENAME(#Destination) + QUOTENAME(#Destination_Columns, '()') +
'SELECT ' + #Origin_Columns + ' FROM ' + QUOTENAME(#Origin);
BEGIN TRY
IF EXISTS (SELECT TOP 1 * FROM #temptable)
BEGIN TRANSACTION
EXECUTE(#delete_query);
EXECUTE(#insert_query);
COMMIT
END TRY
BEGIN CATCH
ROLLBACK;
THROW 51000, 'The Origin table is empty', 1;
END CATCH
END TRY
BEGIN CATCH
THROW 51000, 'Error creating transaction', 1;
END CATCH
GO
When executing the stored proecedure with the parameters shown, it works correctly:
EXEC Insert_Into_Table
#Origin = 'Sink_Proc',
#Destination = 'Sink_Test',
#Origin_Columns = 'customer, order_number, created_date',
#Destination_Columns = 'customer, order_number, created_date',
#Delete_Date_Column_Name = NULL,
#Delete_Period_Months = NULL
However, when executing it with 25+ columns as Origin/Destination columns, when I print the #insert_query variable, it returns NULL and no operation is done. Why is this happening?

Error in using SELECT to set a variable value in SQL

I have following stored procedure and I have identified the issue with the stored procedure is that using select to set the value of #DeliveryAddress variable and so for all the Letter Requests raised it is only retaining the last value which is in Requests. I tried using SET by explicitly setting each value used in #DeliveryAddresss Calculation but of no use as I ended of getting error that subquery returns multiple rows.
I am unable to understand what shall I change in this SP, so that for each value in #Requests, a different #deliveryAddress value is set and used for insertion in LetterRequest table. Please help.
Note #WorkFlowAcct is a temp table having around 10 unique AccountIds and for each account we have atleast one debtorid.
ALTER PROCEDURE [dbo].[WorkFlow_Action_RequestLetterPref]
AS
DECLARE #LetterID INTEGER;
DECLARE #LetterType CHAR(3);
DECLARE #LetterDescription VARCHAR(50);
DECLARE #JobName VARCHAR(256);
DECLARE #DateCreated DATETIME;
DECLARE #DeliveryMethod VARCHAR(7);
DECLARE #DeliveryAddress VARCHAR(1023);
SELECT #LetterID = [LetterID],
#LetterType = CASE
WHEN [type] IN ('SIF', 'PIF', 'PPS', 'PDC', 'ATT', 'CUS') THEN [type]
ELSE 'DUN'
END,
#LetterDescription = ISNULL([Description], ''),
FROM [dbo].[letter]
WHERE [code] = #LetterCode;
DECLARE #Requests TABLE (
[AccountID] INTEGER NOT NULL,
[DebtorID] INTEGER NOT NULL,
[Seq] INTEGER NOT NULL,
[ErrorMessage] VARCHAR(500) NULL
);
IF #PrimaryDebtor = 1 OR #LetterType IN ('CUS', 'ATT') BEGIN
INSERT INTO #Requests ([AccountID], [DebtorID], [Seq])
SELECT DISTINCT [master].[number] AS [AccountID],
[Debtors].[DebtorID] AS [DebtorID],
[Debtors].[Seq] AS [Seq],
FROM #WorkFlowAcct AS [WorkFlowAcct]
INNER JOIN [dbo].[master] WITH (NOLOCK)
ON [WorkFlowAcct].[AccountID] = [master].[number]
INNER JOIN [dbo].[customer] WITH (NOLOCK)
ON [master].[customer] = [customer].[customer]
INNER JOIN [dbo].[Debtors] WITH (NOLOCK)
ON [master].[number] = [Debtors].[number]
AND [Debtors].[Seq] = [master].[PSeq]
LEFT OUTER JOIN [dbo].[DebtorAttorneys]
ON [Debtors].[DebtorID] = [DebtorAttorneys].[DebtorID];
END;
DECLARE #Street1 VARCHAR(512);
DECLARE #Street2 VARCHAR(512);
DECLARE #City VARCHAR(512);
DECLARE #Country VARCHAR(512);
DECLARE #Zip VARCHAR(512);
IF #Pref = 'Letter'
BEGIN
SET #DeliveryMethod = 'Letter';
SELECT #DeliveryAddress = [Street1] + ' ' + [Street2] + ' ' + [City] + ' ' + [Zipcode] + ' ' + [Country], #Street1 = [Street1], #Street2 = [Street2], #City = [City], #Country = [Country], #Zip = [ZipCode] FROM [Debtors] inner join #Requests AS Requests on [Debtors].[DebtorID] = Requests.[DebtorID] AND [Street1] IS NOT NULL;
IF #Street2 IS NULL
BEGIN
SET #DeliveryAddress = #Street1 + ' ' + #City + ' ' + #Zip + ' ' + #Country;
END
END
SET #DateCreated = GETDATE();
SET #JobName = 'WorkFlow_' + CAST(NEWID() AS CHAR(36)) + CAST(NEWID() AS CHAR(36)) + CAST(NEWID() AS CHAR(36)) + CONVERT(VARCHAR(50), GETDATE(), 126);
BEGIN TRANSACTION;
--Updated params for current Letter Request Table
INSERT INTO [dbo].[LetterRequest] ([AccountID], [LetterID], [LetterCode], [DeliveryMethod], [DeliveryAddress])
SELECT [Requests].[AccountID],
[Requests].[CustomerCode],
#LetterID AS [LetterID],
#LetterCode AS [LetterCode],
#DeliveryMethod AS [DeliveryMethod],
#DeliveryAddress AS [DeliveryAddress]
FROM #Requests AS [Requests]
INNER JOIN #AllowedCustomers AS [AllowedCustomers]
ON [Requests].[CustomerCode] = [AllowedCustomers].[CustomerCode]
WHERE [Requests].[ErrorMessage] IS NULL;
COMMIT TRANSACTION;
RETURN 0;

How to select the ALL passed parameter values inside the stored procedure in SQL like SQL Trace

How to select all parameters and values passed to the stored procedure as like in SQL Trace, inside the procedure using any ## function without any customization.
For Example I have a stored procedure like
CREATE PROC test_Procedure
#ln varchar(25) = '',
#fn varchar(25) = '',
#dob datetime = NULL,
#id INT = 0
AS
BEGIN
SELECT * FROM tb_users
WHERE ln= #ln
AND fn = #fn
AND dob = #dob
AND Id = #id
------------ SELECT ##
END
If I called the procedure like
EXEC [dbo].test_Procedure #ln = N'a',#fn = NULL,#dob = NULL,#id = 1
I need to select this exact string inside the procedure using any built in function or user defined function .
If you're trying to output debugging style info you could use something like this;
SELECT CONCAT('test_Procedure #ln = ', #ln, ', #fn = ', #fn, ', #dob = ', #dob, ', #id = ', #id)

Dynamic sql stored procedure update query issue?

I've written the below code to set filepath column in my table as 'F:\DataMigration\Wise\DELTA_20121008\Attachments\SR\SR_1.txt'
where SR_1 is file_name column
.txt is file_ext column from my table.
but after executing following procedure, I'm getting filepath column in table as
'F:\DataMigration\Wise\DELTA_20121008\Attachments\file_name.file_ext'
means It's treating column names as string, how i can make it as column so it will
use values in that column.
alter procedure [dbo].[WISEMissingAttachmentReportGenerator]
(
#tablename varchar(255), #pathonlocal nvarchar(255)
)
as
begin
--step 1
exec dbo.proc_alter_table #tablename
--step 2
EXEC ('update '+ #tablename +
' set filepath = '''+ #pathonlocal + ' file_name'+'.'+'file_ext''')
EXEC('Select * from '+#tablename)
end
exec [dbo].[WISEMissingAttachmentReportGenerator] [WISE.Non_VP_Service_Request_Attachments_File_Check_Analysis],
N'F:\DataMigration\Wise\DELTA_20121008\Attachments\SR\'
Try;
EXEC('UPDATE '+ #tablename +
' SET filepath = '''+ #pathonlocal + ''' + file_name + '''+'.'+''' + file_ext')
Equal as;
UPDATE [YourTable] SET filepath = 'YourPath' + file_name + '.' + file_ext
Try changing your statement to this:
EXEC ('update '+ #tablename +
' set filepath = '''+ #pathonlocal + ''' + file_name + ''.'' + file_ext')
declare #tblnm varchar(20) = 'test'
declare #upda varchar(20) = 'update '
declare #set varchar(25) = ' set'
declare #id varchar(25) = ' id'
declare #cmd varchar(1000)
set #cmd = #upda + #tblnm + #set + #id + '=7'
exec(#cmd)
SAMPLE SQL UPDATE QUERY - FOR BUILDING TABLENAME DYNAMICALLY
EXECUTED GUYS - THIS IS CALL JUGAAAAAAAAAD [NO NEED TO GET INTO ''' STUFF]

SQL trigger only returning one record during a delete

Below is a trigger I've created for a table in a SQL database (We are running SQL Server 2008). We are going to be doing updates, inserts, and deletes in bulk so we created this trigger and a "storage" table (TransactionLog) to capture all the activity. So far, this trigger works perfectly for inserts and updates. All the records wind up in the "storage" table with all appropriate values.
However, the problem occurs when we try to delete anything more than one record. The only record this trigger captures and sends to the "storage" table is the last record deleted. All others get lost.
CREATE TRIGGER [dbo].[trg_Agent_ALL]
ON [dbo].[Agent]
FOR INSERT, UPDATE, DELETE
AS
BEGIN
--TransactionLog variables
DECLARE #tableName char(25) = 'Agent'
DECLARE #transDate datetime
DECLARE #lastChangeOperator char(6)
DECLARE #tableString char(255)
DECLARE #action char(1) = 'I'
DECLARE #userId char(25)
--Trigger table variables
DECLARE #sNumber char(10)
DECLARE #controlId char(3)
DECLARE #entityType char(1)
DECLARE #firstName nvarchar(50)
DECLARE #lastName nvarchar(50)
DECLARE #suffix nvarchar(10)
DECLARE #corpName nvarchar(100)
IF EXISTS (SELECT * FROM deleted)
BEGIN
SET #action =
CASE
WHEN EXISTS (SELECT * FROM inserted) THEN 'U'
ELSE 'D'
END
END
IF #action = 'D'
BEGIN
SELECT #sNumber = sNumber, #lastChangeOperator = LastChangeOperator, #transDate = LastChangeDate, #entityType = EntityType,
#firstName = FirstName, #lastName = LastName, #suffix = NameSuffix, #corpName = CorporateName, #controlId = ControlId
FROM deleted
IF #firstName IS NULL SET #firstName = 'NULL'
IF #lastName IS NULL SET #lastName = 'NULL'
IF #suffix IS NULL SET #suffix = 'NULL'
IF #corpName IS NULL SET #corpName = 'NULL'
IF #controlId IS NULL SET #controlId = 'NULL'
SET #tableString = 'sNum:' + #sNumber + ' ' + 'EntType:' + #entityType + ' ' + 'Fname:' + #firstName + ' ' + 'Lname:' + #lastname + ' ' + 'suf:' + #suffix +
' ' + 'crpName:' + #corpName + ' ' + 'crlId:' + #controlId
END
ELSE
BEGIN
SELECT #sNumber = SymetraNumber, #lastChangeOperator = LastChangeOperator, #transDate = LastChangeDate, #entityType = EntityType,
#firstName = FirstName, #lastName = LastName, #suffix = NameSuffix, #corpName = CorporateName, #controlId = ControlId
FROM inserted
IF #firstName IS NULL SET #firstName = 'NULL'
IF #lastName IS NULL SET #lastName = 'NULL'
IF #suffix IS NULL SET #suffix = 'NULL'
IF #corpName IS NULL SET #corpName = 'NULL'
IF #controlId IS NULL SET #controlId = 'NULL'
SET #tableString = 'sNum:' + #sNumber + ' ' + 'EntType:' + #entityType + ' ' + 'Fname:' + #firstName + ' ' + 'Lname:' + #lastname + ' ' + 'suf:' + #suffix +
' ' + 'crpName:' + #corpName + 'crlId:' + #controlId
END
INSERT INTO TransactionLog (TransactionDate, Operator, TableName, Action, TableString, UserId)
VALUES (#transDate, 'Op', #tableName, #action, #tableString, #lastChangeOperator)
END
Based on the comments below I've altered the SQL code in the delete section. The hard-coded values seem to be working, however the main reason I placed them in there just to show those are the values I need for those specific columns. I have variables set with these values in the code above (see the DECLARE statements). This, however, is giving me the following error message:
Conversion failed when converting the varchar value 'P' to data type int.
This error is coming off of the EntityType attribute in the inner SELECT statement. What confuses me is that this column has a data type set to char(1), and the TableString column (the destination of the concatenated values) has a data type of nvarchar(255). No clue where the "int" is coming from...
IF #action = 'D'
BEGIN
INSERT INTO TransactionLog (TransactionDate, Operator, TableName, Action, TableString, UserId)
SELECT LastChangeDate, 'Op', 'Agent', 'D',
(SELECT CAST(CAST(sNumber as nvarchar) + ' ' + EntityType + ' ' + ISNULL(FirstName, ' ') + ' ' + ISNULL(LastName, ' ') + ' ' + ISNULL(NameSuffix, ' ') + ' ' +
ISNULL(CorporateName, ' ' ) + ' ' + ISNULL(CAST(ControlId as nvarchar), ' ') AS nvarchar) as TableString
FROM deleted), LastChangeOperator
FROM deleted
END
ELSE
EDIT
By casting the sNumber and controlId fields to nvarchar I was able to move past my previous error message. Right now, however I am receiving a different error message posted below:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
FINAL EDIT
Altering the subquery like so allowed me to return multiple deleted records into the Audit table as I was only requesting one record at a time.
IF #action = 'D'
BEGIN
INSERT INTO TransactionLog (TransactionDate, Operator, TableName, Action, TableString, UserId)
SELECT LastChangeDate, 'Op', 'Agent', 'D',
CAST('SymNum:' + CAST(SymetraNumber as nvarchar(30)) + ' entType:' + EntityType + ' Fname:' + ISNULL(FirstName, 'NULL') + ' Lname:' + ISNULL(LastName, 'NULL') +
' suff:' + ISNULL(NameSuffix, 'NULL') + ' corpName:' + ISNULL(CorporateName, 'NULL' ) + ' ctrlId:' + ISNULL(CAST(ControlId as nvarchar(30)), 'NULL') AS nvarchar(30)) as TableString
, LastChangeOperator
FROM deleted
END
ELSE
That select #sNumber = sNumber, .. syntax will overwrite the variables once for each row, so you end up only with the last row's values.
And then you also do an insert into ... values (...), which can only insert one row.
You should try to rewrite it in the form:
insert into TransactionLog ( ... )
select sNumber, ... from deleted
You can use ISNULL(lastname, 'NULL') instead of your if-statements.