Writing a Stored Procedure If/Else to create error message - sql

I am trying to create a stored procedure with an if/else statement that will result in a Text message if the wrong CustomerID is entered into the stored procedure. As it is now it will only give me a print line when there is nothing entered in the CustomeID.
Create proc spCustOrder
#CustomerID VarChar(10),
#StartDate SmallDateTime = null,
#EndDate SmallDateTime = NUll
as
Begin
iF #CustomerID > 0
Select Distinct OrderID, OrderDate
from Customer C join CustOrder CO on CO.CustomerID = C.CustomerID
where C.CustomerID = #CustomerID and
OrderDate >= Isnull(#startDate,'1900-01-01') and
OrderDate <= IsNull(#EndDate, getDate( ))
Else
Print 'Please enter a CustomerID'
end
Basically what i am unclear on is what should i use instead of the "0" in this "#CustomerID > 0" to make the program function. i tried using CustomerID or C. and CO.CustomerID but it says that there is an error with using that command.

Try
IF Exists(
SELECT DISTINCT OrderID, ...
)
ELSE
PRINT ...
END
Also, you typically want to return an ID or true/false value from stored procedures and do any printing or IO in the routine that calls the proc; avoid doing IO in the proc itself.

Your query as written doesn't seem to require the Customers table, so the query can be written as:
Select OrderID, OrderDate
from CustOrder CO
where CO.CustomerID = #CustomerID and
OrderDate >= Isnull(#startDate,'1900-01-01') and
OrderDate <= IsNull(#EndDate, getDate( ));
You then want to print something when there are no rows in the table. I would suggest using a temporary table for storing the intermediate results so they don't have to be calculated twice. The result is something like this:
Create procedure spCustOrder (
#CustomerID VarChar(10),
#StartDate SmallDateTime = null,
#EndDate SmallDateTime = NUll
)
as Begin
Select OrderID, OrderDate
into #tmp
from CustOrder CO
where CO.CustomerID = #CustomerID and
OrderDate >= Isnull(#startDate,'1900-01-01') and
OrderDate <= IsNull(#EndDate, getDate( ));
if exists (select 1 from #tmp)
begin
select *
from #tmp;
end
else
Print 'Please enter a CustomerID'
end; -- spCustOrder

I have used SQL Server's RAISERROR function to throw an error if user doesnt pass a CustomerID.
RETURN keyword will stop the code execution there and exit, no further lines of code will be executed after the RETURN keyword. i.e if the value for #CustomerID is null or 0 and control enters the IF Block.
Create proc spCustOrder
#CustomerID VarChar(10) = NULL,
#StartDate SmallDateTime = null,
#EndDate SmallDateTime = NUll
AS
BEGIN
SET NOCOUNT ON;
IF (#CustomerID IS NULL OR #CustomerID = 0)
BEGIN
RAISERROR('Please enter a CustomerID',16,1)
RETURN;
END
Select Distinct OrderID, OrderDate
from Customer C join CustOrder CO
on CO.CustomerID = C.CustomerID
where C.CustomerID = #CustomerID
and OrderDate >= Isnull(#startDate,'1900-01-01')
and OrderDate <= IsNull(#EndDate, getDate( ))
END

To be honest I would do it completely different. you can use code like:
ALTER PROCEDURE name
#CustomerID (uniqueidentifier) - varchar is very bad solution for your performance
#date1 DATE,
#date2 DATE,
#result INT OUTPUT=0 - use it as output parameter and handle text in app code
AS
BEGIN TRAN
IF EXISTS (your SELECT query. You don't need DISTINCT)
BEGIN
-- if exists do something smart. I don't know... UPDATE TABLE
IF ##error<>0
BEGIN
SET #result=1 --there was an error executing query in something smart
END
ELSE - from IF EXISTS statement
BEGIN
SET #result=2 --means no records found
END
IF #result=1
BEGIN
RETURN 1 --you know that this is error from your application code
ROLLBACK TRAN --there was an error in doing something smart
END
IF #result=2
RETURN 2 -- from your application code you know that this means no users found
END
IF RETURN=0
BEGIN
RETURN 0 -- userid found and something smart done without error :)
COMMIT TRAN
END
Hope this helps. You should analyze more bit about what will you do on application level and what do you want to do on DB level.
If helped mark it if no, ping with questions

Try IS NULL :
Create proc spCustOrder
#CustomerID VarChar(10),
#StartDate SmallDateTime = null,
#EndDate SmallDateTime = NUll
as
Begin
iF (#CustomerID IS NULL)
Select Distinct OrderID, OrderDate
from Customer C join CustOrder CO on CO.CustomerID = C.CustomerID
where C.CustomerID = #CustomerID and
OrderDate >= Isnull(#startDate,'1900-01-01') and
OrderDate <= IsNull(#EndDate, getDate( ))
Else
Print 'Please enter a CustomerID'
end

Related

how to execute procedure with multiply arguement?

create proc [dbo].[SSRproc] (
#StartDate Date
,#EndDate Date
,#DepartmentGroupKey int
)
as begin
select F.Date,
F.AccountKey,
F.Amount,
F.OrganizationKey,
O.OrganizationName,
F.DepartmentGroupKey,
D.DepartmentGroupName
from [AdventureWorksDW2017].[dbo].[FactFinance] as f
inner join dbo.DimOrganization as O on F.OrganizationKey = O.OrganizationKey
inner join dbo.DimDepartmentGroup as D on F.DepartmentGroupKey = D.DepartmentGroupKey
where F.Date between #StartDate and #EndDate and #DepartmentGroupKey = F.DepartmentGroupKey
end
[dbo].[SSRproc] '2010-12-29', '2011-01-29', (3,5)
here is my procedure code and at the end I have execution but I need DepartmentGroupKey has multiply argument like key will be (3,5) or (3,8,9) and like that what I have to do?
If your Procedure is called from where a Table Valued Parameter is supported that would be the best solution. But if your Procedure is called from somewhere else this is not always possible so here is a alternative.
create proc [dbo].[SSRproc] (
#StartDate Date
,#EndDate Date
,#DepartmentGroupKey varchar(10)
)
as begin .....
.....and F.DepartmentGroupKey in (select value from STRING_SPLIT(#DepartmentGroupKey)
And then the execute:
execute dbo.SSRproc
#DepartmentGroupKey = '3,5'

SQL Return to front end

I have the following SQL Server stored procedure and when this is called by the front end code it returns the return value which is 0 instead of select of total count. can any one tell me what changes do i need to do to make it return the select values instead of return value
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[getTotalSent1]
(
#vendorworksationID uniqueidentifier ,
#sdate date,
#edate date
)
as
begin
select
camp.totalSent + bcamp.totalSent as totalSent
from
(select
COUNT(*) as totalSent
from
AdvertisedCampaignHistory a
where
CAST(a.CreationDate AS DATE) BETWEEN CAST(#sdate as DATE) AND CAST(#edate as DATE)
and a.CampaignID in (select cc.CampaignID
from campaign cc, VendorWorkStation vw
where cc.VendorWorkStationID = vw.VendorWorkStationID
and VendorID = #vendorworksationID)) as camp
join
(select
COUNT(*) as totalSent
from
AdvertisedCampaignHistory a
where
CAST(a.CreationDate AS DATE) BETWEEN CAST(#sdate as DATE) AND CAST(#edate as DATE)
and a.CampaignID in (select bc.BCampaignID
from BeaconCampaign bc, VendorWorkStation vw
where bc.VendorWorkStationID = vw.VendorWorkStationID
and VendorID = #vendorworksationID)) as bcamp on 1=1
end
Output:
Totalsent
---------
240
return
-----
0
It's returning 0, I want total sent value
CREATE PROCEDURE getTotalSent1
AS
DECLARE #TotalSent int
-- Do some work here
SELECT #TotalSent = 240
RETURN #TotalSent
GO
-- EXEC CODE
DECLARE #totalsent int
EXEC #totalsent = dbo.getTotalSent1
SELECT #totalsent as totalSent
ALTER procedure [dbo].[getTotalSent1]
(
#vendorworksationID uniqueidentifier ,
#sdate date,
#edate date
#total_set int output
)
as
`enter code here`
return
get param like this
declare #got_it int
exec [dbo].[getTotalSent1] xxx,yyy,#total_set=#got_it output
`
Try this:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[getTotalSent1]
(
#vendorworksationID uniqueidentifier ,
#sdate date,
#edate date
)
as
begin
DECLARE #totalSent INT
select
#totalSent =camp.totalSent + bcamp.totalSent
from
(select
COUNT(*) as totalSent
from
AdvertisedCampaignHistory a
where
CAST(a.CreationDate AS DATE) BETWEEN CAST(#sdate as DATE) AND CAST(#edate as DATE)
and a.CampaignID in (select cc.CampaignID
from campaign cc, VendorWorkStation vw
where cc.VendorWorkStationID = vw.VendorWorkStationID
and VendorID = #vendorworksationID)) as camp
join
(select
COUNT(*) as totalSent
from
AdvertisedCampaignHistory a
where
CAST(a.CreationDate AS DATE) BETWEEN CAST(#sdate as DATE) AND CAST(#edate as DATE)
and a.CampaignID in (select bc.BCampaignID
from BeaconCampaign bc, VendorWorkStation vw
where bc.VendorWorkStationID = vw.VendorWorkStationID
and VendorID = #vendorworksationID)) as bcamp on 1=1
return #totalSent
end
After BEGIN type SET NOCOUNT ON;
This disables the default return value for stored procedures, so that you get the results of your query instead.
And as a side note, you need to replace your proprietary joins with the ANSI equivalent...
e.g.
...
FROM tblA a
JOIN tblB b
ON a.key = b.key
It's better to avoid doing the join in the WHERE clause.

calling a remote sproc from a function

I have a stored procedure SprocA resides on ServerA. SprocA takes 4 parameters, executes a dynamic sql and returns a record with 1 column (1 integer value).
I'd like to be able to call this from a function FnB on ServerB so that I can use it in a stored procedure SprocB on server ServerB to return a recordset.
For example, I'd like to have something like this
Create Function FnB
#CustomerId int
,#PartId varchar(30)
,#DateFrom datetime
,#DateTo datetime
Returns int
As
Begin
Declare #Ret int
Exec #Ret = LnkSrv.DB_History.dbo.SprocA(#CustomerId, #PartId, #DateFrom, #DateTo)
Return #Ret
End --FnB
Create Procedure SprocB
#RowId int
As
Begin
Select Partid, FnB(Customerid, Partid, DateFrom, DateTo) As TotalQtyShipped
, AskedPrice, AskedQty, AppvPrice, AppvQty
From Tbl_Header a
Inner Join Tbl_Detail b On a.RowID = b.RowID
Where a.RowID = #RowId
End --SprocB
Possible result:
PartID TotalQtyShipped AskedPrice AskedQty AppvPrice AppQty
pn1 1000 10 100 10 100
pn2 550 20 50 15 50
pn3 2000 5 2000 5 1500
Please help
TL
If your solution based on dynamic SQL (ServerA.SprocA) you can't use functions at all in the following call sequence because SQL Server treats functions as deterministic and you can't change SQL Server state in the function call.
if I were on your place I'd made that LnkSrv.DB_History.dbo.SprocA creates denormalized table (tbl_FnB) with following (see below) columns insted of returning scalar value
CustomerId PartId DateFrom DateTo TotalQtyShipped
then SprocB would look like this
Create Procedure SprocB
#RowId int
As
Begin
exec LnkSrv.DB_History.dbo.SprocA; -- creates table Tbl_FnB on its side
Select Partid, Tbl.TotalQtyShipped
, AskedPrice, AskedQty, AppvPrice, AppvQty
From Tbl_Header a
Inner Join Tbl_Detail b On a.RowID = b.RowID
Inner Join LnkSrv.DB_History.dbo.Tbl_FnB f On f.CustomerId = b.Customerid
and f.Partid = b.Partid
and f.DateFrom = b.DateFrom
and f.DateTo = b.DateTo
Where a.RowID = #RowId
End --SprocB
I assumed that fields CustomerId PartId DateFrom DateTo located in the Tbl_Detail table
There's no real issue with what you're asking for except that you cannot use execute inside a function as you have it;
You can however do this:
create proc [dbo].[GetRowCount] (#TblName NVARCHAR(25) , #Itemid INT,#RowCnt int = 0)
AS BEGIN
DECLARE #Sqlstring nvarchar(2000)
set #Sqlstring = 'SELECT #RowCnt = COUNT(*) FROM ['+ #TblName +']
WHERE Itemid = '+ convert(varchar(10),#Itemid)
EXEC sp_executesql #Sqlstring,N'#RowCnt int output',#RowCnt output
END
...
declare #RowCnt int
exec [GetRowCount] #TblName='TableName',#Itemid='ItemID',#RowCnt=#RowCnt output
select #RowCnt
you should be able to adapt this for your own situation.

SQL Server Trigger to handle multiple update rows. sub query returning more then one value

I got this trigger working for single row insert or update, but when I try to update multiple rows at once, it gives error that sub query returns more then one value.
For example
update paymentdata
set stat=1
Trigger code is here
USE [AGP]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[OnpaymentUpdate]
ON [dbo].[paymentData]
AFTER UPDATE --operations you want trigger to fire on
AS
BEGIN
SET NOCOUNT ON;
DECLARE #customerID NCHAR(50), #lastpaymentDate DATETIME, #stat nchar(50), #month int;
SET #customerID= (SELECT customerID FROM inserted) --table inserted contains inserted rows (or new updated rows)
SET #stat= (SELECT stat FROM inserted) --table inserted contains inserted rows (or new updated rows)
set #lastpaymentDate = (SELECT MAX(paymentDate) FROM paymentReceipt where customerID=#customerID)
SET #month= (SELECT DATEDIFF(MONTH, #lastpaymentDate,GETDATE()))
DECLARE #balance BIGINT
SET #balance =
(
SELECT (totalprice-(paidAmount+concession))
FROM paymentData
WHERE customerID = #customerID
)
UPDATE PaymentData
SET balanceAmount = #balance ,
lastpaymentDate=#lastpaymentDate
WHERE customerID = #customerID
if (#month >=2 and #stat!='Cancel' and #stat!='Refund' And #stat!='Refunded' and #stat!='Transfered' and #stat!='Transfer')
Begin
IF (#month <2 and #stat='Defaulter')
SET #stat='Regular'
IF (#balance<=0)
SET #stat='Payment Completed'
else
SET #stat='Defaulter'
End
else
Begin
if #stat='Refund'
Set #stat='Refunded'
if #stat='Cancled'
Set #stat='Cancel'
if #stat='Transfer'
Set #stat='Transfered'
End
UPDATE PaymentData
SET stat =#stat
WHERE customerID = #customerID
END
If I understand this properly, then the following should work... Give it a try and correct any syntax errors you find:
NOTE: Personally, I would not use a trigger for this. I would put this code in the store procedure that applies the payment.
ALTER TRIGGER [dbo].[OnpaymentUpdate]
ON [dbo].[paymentData]
AFTER UPDATE --operations you want trigger to fire on
As
BEGIN
Declare #today datetime = dateAdd(dd, datediff(dd, 0, getDate()), 0)
Declare #custInfo table
(custId integer Primary Key not null,
stat varChar(30) not null,
balance bigint not null,
lastPymnt datetime not null,
lastGap smallint not null)
Insert #custInfo(custId, stat, balance, lastPymnt, lastGap)
Select i.customerId, i.stat,
totalprice-(paidAmount+concession),
MAX(paymentDate),
Min(datediff(month, paymentDate, #today))
From inserted i
join paymentReceipt r On r.customerId = i.customerId
join PaymentData d On d.CustomerId = i.customerId
Group By i.customerId, i.stat,
d.totalprice-(d.paidAmount + d.concession)
Update pd Set
balanceAmount = i.balance,
lastpaymentDate = i.lastPymnt,
stat = case When lastGap >=2 and i.stat!='Cancel'
and i.stat!='Refund' And i.stat!='Refunded'
and i.stat!='Transfered' and i.stat!='Transfer') Then Case
When #month >= 2 And i.stat='Defaulter' Then 'Regular'
When #balance<=0 Then 'Payment Completed'
Else 'Defaulter' End
Else Case #stat
When 'Refund' Then 'Refunded'
When 'Cancled' Then 'Cancel'
When 'Transfer' Then 'Transfered' End
End
From PaymentData pd Join #custInfo i
On i.custId = pd.customerID
END

Loop through a recordset and use the result to do another SQL select and return the results

I am completely new to stored procedure. This time, I need to create a stored procedure in MS SQL.
Let's say I have the following table.
Table name: ListOfProducts
--------------------------
SomeID, ProductID
34, 4
35, 8
35, 11
How do I pass in a SomeID. Use this SomeID to select a recordset from table, ListOfProducts. Then loop through this record set.
Let's say I pass in SomeID = 35.
So, the record set will return 2 records with SomeID 35. In the loop, I will get ProductID 8 and 11, which will be used to do another select from another table.
The stored procedure should return the results from the 2nd select.
How can I do this in MS SQL stored procedure?
Sorry, for this newbie question. Thanks for any help.
If you want looping through the records. You can do like:
--Container to Insert Id which are to be iterated
Declare #temp1 Table
(
tempId int
)
--Container to Insert records in the inner select for final output
Declare #FinalTable Table
(
Id int,
ProductId int
)
Insert into #temp1
Select Distinct SomeId From YourTable
-- Keep track of #temp1 record processing
Declare #Id int
While((Select Count(*) From #temp1)>0)
Begin
Set #Id=(Select Top 1 tempId From #temp1)
Insert Into #FinalTable
Select SomeId,ProductId From ListOfProducts Where Id=#Id
Delete #temp1 Where tempId=#Id
End
Select * From #FinalTable
There is probably no point in writing an explicit loop if you don't need to preform some action on the products that can't be done on the whole set. SQL Server can handle stuff like this much better on its own. I don't know what your tables look like, but you should try something that looks more like this.
CREATE PROC dbo.yourProcName
#SomeID int
AS
BEGIN
SELECT
P.ProductId,
P.ProductName
FROM
Product P
JOIN
ListOfProducts LOP
ON LOP.ProductId = P.ProductId
WHERE
LOP.SomeId = #SomeID
END
I had to do something similar in order to extract hours from a select resultset start/end times and then create a new table iterating each hour.
DECLARE #tCalendar TABLE
(
RequestedFor VARCHAR(50),
MeetingType VARCHAR(50),
RoomName VARCHAR(MAX),
StartTime DATETIME,
EndTime DATETIME
)
INSERT INTO #tCalendar(RequestedFor,MeetingType,RoomName,StartTime,EndTime)
SELECT req as requestedfor
,meet as meetingtype
,room as rooms
,start as starttime
,end as endtime
--,u.datetime2 as endtime
FROM mytable
DECLARE #tCalendarHours TABLE
(
RequestedFor VARCHAR(50),
MeetingType VARCHAR(50),
RoomName VARCHAR(50),
Hour INT
)
DECLARE #StartHour INT,#EndHour INT, #StartTime DATETIME, #EndTime DATETIME
WHILE ((SELECT COUNT(*) FROM #tCalendar) > 0)
BEGIN
SET #StartTime = (SELECT TOP 1 StartTime FROM #tCalendar)
SET #EndTime = (SELECT TOP 1 EndTime FROM #tCalendar)
SET #StartHour = (SELECT TOP 1 DATEPART(HOUR,DATEADD(HOUR,0,StartTime)) FROM #tCalendar)
SET #EndHour = (SELECT TOP 1 DATEPART(HOUR,DATEADD(HOUR,0,EndTime)) FROM #tCalendar)
WHILE #StartHour <= #EndHour
BEGIN
INSERT INTO #tCalendarHours
SELECT RequestedFor,MeetingType,RoomName,#StartHour FROM #tCalendar WHERE StartTime = #StartTime AND EndTime = #EndTime
SET #StartHour = #StartHour + 1
END
DELETE #tCalendar WHERE StartTime = #StartTime AND EndTime = #EndTime
END
Do something like this:
Declare #ID int
SET #ID = 35
SELECT
p.SomeID
,p.ProductID
FROM ListOfProducts p
WHERE p.SomeID = #ID
-----------------------
--Or if you have to join to get it
Declare #ID int
SET #ID = 35
SELECT
c.SomeID
,p.ProductID
,p.ProductName
FROM ListOfProducts p
INNER JOIN categories c on p.ProductID = c.SomeID
WHERE p.SomeID = #ID
You can use option with WHILE loop and BREAK/CONTINUE keywords
CREATE PROC dbo.yourProcName
#SomeID int
AS
BEGIN
IF OBJECT_ID('tempdb.dbo.#resultTable') IS NOT NULL DROP TABLE dbo.#resultTable
CREATE TABLE dbo.#resultTable
(Col1 int, Col2 int)
DECLARE #ProductID int = 0
WHILE(1=1)
BEGIN
SELECT #ProductID = MIN(ProductID)
FROM ListOfProducts
WHERE SomeID = #SomeID AND ProductID > #ProductID
IF #ProductID IS NULL
BREAK
ELSE
INSERT dbo.#resultTable
SELECT Col1, Col2
FROM dbo.yourSearchTable
WHERE ProductID = #ProductID
CONTINUE
END
SELECT *
FROM dbo.#resultTable
END
Demo on SQLFiddle