Stored procedure in SQL Server with select query then if condition and then insert query - sql

I want to create a stored procedure in which first select statement and depending on the selected parameter if valid, insert record in the another table else do nothing. How to write the stored procedure for this?
I have tried with stored procedure and it is executed with no errors, but when I tried to EXEC stored procedure, it doesn't do the task as written in procedure.
CREATE PROCEDURE sp_CreateExpiryDocumentFollowup
(#param INT = NULL,
#param2 INT = NULL,
#param3 INT = 1,
#param4 BIT = 0,
#followupid INT = NULL)
AS
BEGIN
SELECT
#param1 = [TABLE_A].[VEHICLE_ID],
#param2 = [TABLE_A].[VEHICLE_DOCUMENT_ID],
#followupid = [TABLE_B].[FOLLOWUP_ID]
FROM
[TABLE_A]
LEFT JOIN
[TABLE_B] ON [TABLE_B].[VEHICLE_DOCUMENT_ID] != [TABLE_A].[VEHICLE_DOCUMENT_ID]
WHERE
[TABLE_A].[STATUS] = 1;
IF #followupid = NULL
BEGIN
INSERT INTO [TABLE_B] (VALUE_1, VALUE_2, VALUE_3, VALUE_4)
VALUES (#param1, #param2, #param3, #param4)
END
END
GO
I expect the record to insert in the TABLE_B if #followupid is null. The #followupid is null as I executed the select statement only. But while executing whole stored procedure it will return the result 0 row which in my case should be 1. And I checked the table as well, no any record is inserted but stored procedure runs successfully.

Here's how I would write it:
CREATE PROCEDURE sp_CreateExpiryDocumentFollowup
(
--#param1 int = null -- this is no longer needed
--#param2 int = null -- this is no longer needed
#param3 int = 1,
#param4 bit = 0
--,#followupid int = null -- -- this is no longer needed
)
AS BEGIN
INSERT INTO [TABLE_B] (VALUE_1, VALUE_2, VALUE_3, VALUE_4)
SELECT [TABLE_A].[VEHICLE_ID], [TABLE_A].[VEHICLE_DOCUMENT_ID], #param3, #param4
FROM [TABLE_A]
LEFT JOIN [TABLE_B]
-- as stated in the comments to the questions,
-- Shouldn't this condition be `=` instead of `!=`?
ON [TABLE_B].[VEHICLE_DOCUMENT_ID] != [TABLE_A].[VEHICLE_DOCUMENT_ID]
WHERE [TABLE_A].[STATUS] = 1
AND [TABLE_B].[FOLLOWUP_ID] IS NULL
END
GO
Instead of first selecting and then inserting, you can do an insert...select operation which leads to a shorter, more readable code.
This way, if the select statement doesn't return any rows, nothing gets inserted into the target table.
Also, you can't use equality operators on NULL in SQL. Instead, you can only use IS NULL or IS NOT NULL (Or NOT IS NULL if you like that better).
Please note that if the select statement returns more than one row, all of them will be inserted into the target table.

Related

Set Value From Action Update, Delete, Inserted in Stored Procedure SQL

I have created my stored procedure, but I am confused how to set one column of from my table.
This is separate of my code:
CREATE PROC [dbo].[SP_Gabungan]
#REPORT_DT DATE
AS
BEGIN
DECLARE #action NVARCHAR(10),
#insCount INT = (SELECT COUNT (*) FROM INSERTED),
#delCount INT = (SELECT COUNT (*) FROM DELETED)
SELECT
#REPORT_DT AS REPORT_DATE,
FD.BRANCH_CODE AS [BRANCH],
#action AS [ID_OPERATIONAL], -- I want to set this value as 1(if there is a new input data, 2
-- (if there is updated data), 3 (if there is deleted data) from
-- from another field
BR.REGULATOR_BRANCH as [RG_BRANCH]
FROM
[DBO].[F_RR_FUNN] FD
LEFT JOIN
[DBO].[MS_BRANCH] BR ON BR.BRANCH_CD = FD.BRANCH_CODE
WHERE
FD.GROUP_PRODUCT = 'CA'
AND Y17sa = '1'
AND FD.REPORT_DATE = #REPORT_DT
END
How do I set column ID_OPERASIONAL as 1 (if there is a new data from another field), 2 for exists updated data from another field, 3 for deleted data from another field in a stored procedure.
ERROR from this code is:
Invalid object name 'INSERTED'
The problem the ERROR shows is that you cannot use deleted/inserted tables in stored procedures but just accessible in triggers.
If you want to have the count of inserted records or deleted records in a table there are two ways for doing this which the easiest one is:
Create you stored procedure like this:
CREATE PROC [dbo].[SP_Gabungan]
#REPORT_DT DATE,#DeletedCount INT , #InsertedCount Int
AS
BEGIN
...
Create a Trigger after insert and delete (so you can have inserted/deleted tables)
Then get the count just like you did in your code:
DECLARE #action nvarchar (10),
#insCount int = (SELECT COUNT (*) FROM INSERTED),
#delCount int = (SELECT COUNT (*) FROM DELETED)
Call your stored procedure in the Trigger and pass the #insCount and #delCount as inputs
EXEC [dbo].[SP_Gabungan]
#REPORT_DT = GETDATE() , #InsertedCount = #insCount , #DeletedCount = #delCount
A similar question is this for more other ways like temp tables or...
How use inserted\deleted table in stored procedure?
Also the link below is a question asking defining a trigger for both delete and insert so you can use both deleted/inserted tables together
SQL Trigger on Update, Insert, Delete on non-specific row, column, or table
Second way which is better when you are doing all these process a lot, is to get the log of your inserts or updates or deletes so you dont use triggers which reduce performance of your process.
(If usefull I can recommend some ideas for saving table logs)
CREATE PROC [dbo].[SP_Gabungan]
#REPORT_DT DATE
,#DeletedCount INT
,#InsertedCount INT
,#UpdateCount INT
AS BEGIN
DECLARE #action INT
SET #action = CASE
WHEN #InsertCount <> 0 THEN 1
WHEN #UpdateCount <> 0 THEN 2
WHEN #DeletedCount <> 0 THEN 3
END
SELECT
#REPORT_DT AS REPORT_DATE,
FD.BRANCH_CODE AS [BRANCH],
#action AS [ID_OPERATIONAL],
BR.REGULATOR_BRANCH as [RG_BRANCH]
FROM
[DBO].[F_RR_FUNN] FD
LEFT JOIN
[DBO].[MS_BRANCH] BR ON BR.BRANCH_CD = FD.BRANCH_CODE
WHERE
FD.GROUP_PRODUCT = 'CA'
AND Y17sa = '1'
AND FD.REPORT_DATE = #REPORT_DT END
CREATE TRIGGER [YourTriggerName]
AFTER INSERT/UPDATE/DELETE ON [db].[tablename]
FOR EACH ROW
BEGIN
DECLARE
#insCount int = (SELECT COUNT (*) FROM New), -- New in MySQL is same as inserted,deleted,updated
#delCount int = (SELECT COUNT (*) FROM Old),
#upCount int = (SELECT COUNT (*) FROM New),
EXEC [dbo].[SP_Gabungan]
#REPORT_DT = GETDATE()
,#DeletedCount = #delCount
,#InsertedCount = #insCount
,#UpdateCount = #upCount
END

Using SQL Server CASE statement in WHERE

I want to select records from a table in a stored procedure. Given parameters can be empty or a string including some keys separated by comma (1, 2, etc)
I want to manage that when a parameter is an empty string, "WHERE" ignore searching.
I'm using this code:
where (CASE when #PatientID <> 0 then ( dental.ID_Sick in (1,2)) else (1=1) end)
Something like that is working in W3School. I mean:
SELECT * FROM Customers
WHERE (case when 1=1 then (Country IN ('Germany', 'France', 'UK')) else 1=1 end);
What is the problem in my query that does not work? SQLServerManagementStudio is giving error on "IN" statement.
Solution:
The best way to handle such optional parameters is to use dynamic SQL and built the query on the fly. Something like....
CREATE PROCEDURE myProc
#Param1 VARCHAR(100) = NULL
,#Param2 VARCHAR(100) = NULL
,#Param3 VARCHAR(100) = NULL
,#ListParam VARCHAR(100) = NULL
--, etc etc...
AS
BEGIN
SET NOCOUNT ON;
Declare #Sql NVARCHAR(MAX);
SET #Sql = N' SELECT *
FROM TableName
WHERE 1 = 1 '
-- add in where clause only if a value was passed to parameter
+ CASE WHEN #Param1 IS NOT NULL THEN
N' AND SomeColumn = #Param1 ' ELSE N'' END
-- add in where clause a different variable
-- only if a value was passed to different parameter
+ CASE WHEN #Param2 IS NOT NULL THEN
N' AND SomeOtherColumn = #Param3 ' ELSE N'' END
-- List Parameter used with IN clause if a value is passed
+ CASE WHEN #ListParam IS NOT NULL THEN
N' AND SomeOtherColumn IN (
SELECT Split.a.value(''.'', ''VARCHAR(100)'') IDs
FROM (
SELECT Cast (''<X>''
+ Replace(#ListParam, '','', ''</X><X>'')
+ ''</X>'' AS XML) AS Data
) AS t CROSS APPLY Data.nodes (''/X'') AS Split(a) '
ELSE N'' END
Exec sp_executesql #sql
, N' #Param1 VARCHAR(100), #Param2 VARCHAR(100) ,#Param3 VARCHAR(100) ,#ListParam VARCHAR(100)'
, #Param1
, #Param2
,#Param3
, #ListParam
END
Problem with Other approach
There is a major issue with this other approach, you write your where clause something like...
WHERE ( ColumnName = #Parameter OR #Parameter IS NULL)
The Two major issues with this approach
1) you cannot force SQL Server to check evaluate an expression first like if #Parameter IS NULL, Sql Server might decide to evaluate first the expression ColumnName = #Parameterso you will have where clause being evaluated even if the variable value is null.
2) SQL Server does not do Short-Circuiting (Like C#), even if it decides to check the #Parameter IS NULL expression first and even if it evaluates to true, SQL Server still may go ahead and evaluating other expression in OR clause.
Therefore stick to Dynamic Sql for queries like this. and happy days.
SQL Server does not have a Bool datatype, so you can't assign or return the result of a comparison as a Bool as you would in other languages. A comparison can only be used with IF-statements or WHERE-clauses, or in the WHEN-part of a CASE...WHEN but not anywhere else.
Your specific example would become this:
SELECT * FROM Customers
WHERE 1=1 OR Country IN ('Germany', 'France', 'UK')
It would be better readable to rewrite your statement as follows:
WHERE #PatientID = 0
OR dental.ID_Sick in (1,2)
Referring to your actual question, I'd advise to read the linked question as provided by B House.
May be this straight way will work for you
IF (#PatientID <> 0)
BEGIN
SELECT * FROM Customers
WHERE Country IN ('Germany', 'France', 'UK')
END
try this:
WHERE 1=(CASE WHEN #PatientID <>0 AND dental.ID_Sick in (1,2) THEN 1
WHEN #PatientID =0 THEN 1
ELSE 0
END)

Receiving 0 results from my stored procedure

I am trying to run a stored procedure in SQL Server and I'm getting 0 results. I initially had this running just fine (attached to SSRS) but then users requested a multiple value input for the ProviderName parameter and I realized I was in over my head. I contacted our vendor who provided a KnowledgeBase article which I essentially copied and pasted right in. See below...
ALTER PROCEDURE [dbo].[Test]
(#dStartDate DATETIME
,#dEndDate DATETIME
,#nProviderName VARCHAR(MAX)
,#nAllProviderName VARCHAR(1) = 'N')
AS
BEGIN
DECLARE #dStart AS DATETIME = CONVERT(DATETIME,CONVERT(DATE,#dStartDate)) ;
DECLARE #dEnd AS DATETIME = DATEADD(ms,-3, DATEADD(day,1,CONVERT(DATETIME,CONVERT(DATE,#dEndDate))))
DECLARE #cProviderName AS VARCHAR(MAX) = #nProviderName
DECLARE #tProviderName AS TABLE (PCPID VARCHAR(MAX) NOT NULL);
IF UPPER(#nAllProviderName) = 'N'
BEGIN
INSERT INTO #tPCPName ( PCPID )
SELECT LTRIM(RTRIM(Item))
FROM [dbo].[Auto_Split]('|',#nProviderName ) ;
END;
SELECT ...
WHERE
([TestMnemonic] = 'GLU' OR
[TestMnemonic] = '%HA1C')
AND [Status] != 'DIS CLI'
AND [TextLine] IS NOT NULL
AND [DateTime] BETWEEN #dStart AND #dEnd
AND (UPPER(#nAllProviderName) = 'Y' OR
[PCPID] COLLATE DATABASE_DEFAULT
IN (SELECT PCPID FROM #tProviderName ) ) ;
END
So if I comment out the last 4 lines of code it runs fine. So it's something in that last bit (or something at the top?) I'm hoping this is a quick fix, any and all help is appreciated!
Thanks!
I'm curious about the Collate statement at the bottom. What us your system default and do you really need that when comparing against a temp table you made?
Without Collate
OR [PCPID] IN (SELECT PCPID FROM #tProviderN
I think you need to switch #tProviderName with #tPCPName in last line.
If your #nAllProviderName is "N" than you search PCPID from memory table called #tPCPName
And there is some code missing, so I didn't get the full picture .. If you could put your from and joins statments and your missing "where clause", when your #nAllProviderName is "Y"
and you don't need this part in your SQL
IF UPPER(#nAllProviderName) = 'N'
BEGIN
INSERT INTO #tPCPName ( PCPID )
SELECT LTRIM(RTRIM(Item))
FROM [dbo].[Auto_Split]('|',#nProviderName ) ;
END
if you switch your last line with
AND (UPPER(#nAllProviderName) = 'Y' OR
[PCPID] COLLATE DATABASE_DEFAULT
IN ( SELECT LTRIM(RTRIM(Item))
FROM [dbo].[Auto_Split]('|',#nProviderName ) ) ) ;

IN Clause is not taking dynamic passed value in SQL 2008

I have below SQL Procedure where I am passing and setting dynamic values.
Code: SQL Procedure Name: GetArchivedData
ALTER PROCEDURE [dbo].[GetArchivedData](#PublicationURL varchar(100),#Number int,#Action varchar(max))
AS
DECLARE #TEST Varchar(max)
IF (#Action = 'ALL')
BEGIN
SET #TEST = '''ADD'''+','+'''UPD'''+','+'''DEL''';
END
ELSE
BEGIN
SET #TEST = #Action
END
IF (#Number !=0)
BEGIN
PRINT 'Inside'+ #TEST
BEGIN TRANSACTION TRAN1
SELECT
1 AS Tag,
NULL AS Parent,
NULL AS [root!1!],
NULL AS [Item!2!Id],
NULL AS [Item!2!Action],
NULL AS [Item!2!Publication_Id],
NULL AS [Item!2!Item_Reference_Id],
NULL AS [Item!2!Item_type],
convert( datetime, '9999-01-01' ) AS [Item!2!Last_Published_Date],
NULL AS [Item!2!Url],
NULL AS [Item!2!Schema_Id]
UNION
SELECT TOP (#Number)
2,
1,
'1',
T.ID,
T.ACTION,
T.PUBLICATION_ID,
T.ITEM_REFERENCE_ID,
T.ITEM_TYPE,
T.LAST_PUBLISHED_DATE,
T.URL,
T.SCHEMA_ID
FROM DBO.AUTN_ITEMS T WHERE FLAG=1 AND ACTION IN (#TEST) AND URL LIKE #PublicationURL+'%'
ORDER BY [Item!2!Last_Published_Date] DESC
FOR XML EXPLICIT
COMMIT TRANSACTION TRAN1
END
ELSE IF (#Number = 0)
BEGIN
PRINT 'Outside'+ #TEST
BEGIN TRANSACTION TRAN2
SELECT
1 AS Tag,
NULL AS Parent,
NULL AS [root!1!],
NULL AS [Item!2!Id],
NULL AS [Item!2!Action],
NULL AS [Item!2!Publication_Id],
NULL AS [Item!2!Item_Reference_Id],
NULL AS [Item!2!Item_type],
convert( datetime, '9999-01-01' ) AS [Item!2!Last_Published_Date],
NULL AS [Item!2!Url],
NULL AS [Item!2!Schema_Id]
UNION
SELECT
2,
1,
'1',
T.ID,
T.ACTION,
T.PUBLICATION_ID,
T.ITEM_REFERENCE_ID,
T.ITEM_TYPE,
T.LAST_PUBLISHED_DATE,
T.URL,
T.SCHEMA_ID
FROM DBO.AUTN_ITEMS T WHERE FLAG=1 AND ACTION IN (#TEST) AND URL LIKE #PublicationURL+'%'
ORDER BY [Item!2!Last_Published_Date] DESC
FOR XML EXPLICIT
COMMIT TRANSACTION TRAN2
END
RETURN
Excuting SQL Procedure:
DECLARE #return_value int
EXEC #return_value = [dbo].[GetArchivedData]
#PublicationURL = N'/in',
#Number = 0,
#Action = N'ALL'
SELECT 'Return Value' = #return_value
I can see the values are getting set properly, if I am printing it in the procedure however one value works perfectly but when I am setting SET #TEST = '''ADD'''+','+'''UPD'''+','+'''DEL'''; no results are returned
Please suggest!!
Use Table Variable instead of #Test as string like this,
DECLARE #ActionTbl table ([Action] varchar(3))
IF (#Action = 'ALL')
BEGIN
INSERT INTO #ActionTbl SELECT 'Add' AS ID
UNION ALL
SELECT 'UPD' AS ID
UNION ALL
SELECT 'DEL' ID
END
ELSE
BEGIN
INSERT INTO #ActionTbl VALUES(#Action)
END
And in query use
ACTION IN (Select Action from #ActionTbl)
Instead of
ACTION IN (#TEST)
First of all the main issue here - you CAN'T use IN to search one string in another. IN is used to search value in the row set of values. Also the #TEST STRING value is 'ADD,'UPD','DEL' (each item is with quotas). I guess the Action field contains values without quotas so additional y to other answers there is one more way:
Replace
ACTION IN (#TEST)
with
#TEST LIKE '%'''+ACTION+'''%'

SQL Server - check input parameter for null or zero

I have a stored procedure for sql server 2008 like this:
create procedure test_proc
#someval int,
#id int
as
update some_table
set some_column = ISNULL(#someval, some_column)
where id = #id
go
If the parameter #someval is NULL, this SP will just use the existing value in some_column.
Now I want to change this behaviour such that if value for #someval is 0, a NULL is stored in some_column otherwise it behave just the way it is doing now.
So I am looking for something like:
if #someval == 0
set some_column = NULL
else
set some_column = ISNULL(#someval, some_column)
I don't have the option to create a varchar #sql variable and call sq_executesql on it (at least that is the last thing I want to do). Any suggestions on how to go about doing this?
You can do this using the CASE expression. Something like this:
update some_table
set some_column = CASE WHEN #someval = 0 THEN NULL
WHEN #someval IS NULL THEN somcolumn
ELSE #someval -- the default is null if you didn't
-- specified one
END
where id = #id
something like this?
create procedure test_proc
#someval int,
#id int
as
update some_table
set some_column = CASE
WHEN #someval = 0 THEN NULL
ELSE ISNULL(#someval, some_column) END
where id = #id
go
I think it's a really bad idea - I'd suggest that if someone wants to store a NULL, they really shouldn't have to pass some other magical value to cause it to happen. However, let's show how it can be done:
update some_table
set some_column = CASE WHEN #someVal = 0 THEN NULL ELSE ISNULL(#someval, some_column) END
where id = #id
Given the simplicity of the stored procedure in your question, of course, the whole matter can be cleared up by not calling the stored procedure if you don't want to alter some_column. I'd imagine that your real procedure is more complex. Instead, what I'd do is have:
create procedure test_proc
#someval int,
#someval_specified bit,
#id int
as
update some_table
set some_column = CASE WHEN #someval_specified = 1 THEN #someval ELSE some_column END
where id = #id
And now NULL means NULL, 0 means 0, etc.