Passing multiple value parameter to stored procedure - sql

I have an existing stored procedure which accepts two single valued parameter. Now i have requirement to change one of its parameters to accept multiple values . I modified the stored procedure as below.
CREATE PROCEDURE [dbo].[GetSpecificationsM1]
#EntityType NVARCHAR(100)
,#EntityId BIGINT
AS
DECLARE #EntityTypeId AS BIGINT
SET #EntityTypeId=ISNULL((SELECT ID
FROM [ObjectTypes] WHERE [Type]=#EntityType),0)
SELECT ISNULL([Specifications].[Id],0) AS [SpecificationId]
,ISNULL([Specifications].[Measure],'') AS [Measure]
,ISNULL([Specifications].[Notes],'') AS [Notes]
,ISNULL([UOM].[UOM],'') As UOM
,ISNULL(SpecificationsTemplate.Name,'') As Specification
,ISNULL(SpecificationsTemplate.Id, 0) AS SpecificationTemplateId
,ISNULL(Specifications.EntityId, 0) AS EntityId
,(CASE WHEN ISNULL([SpecificationsTemplate].FieldTypeId,0)=0
THEN 8 ELSE [SpecificationsTemplate].FieldTypeId END) AS [FieldTypeId]
,ISNULL(SpecificationsTemplate.ListId,0) AS ListId
,ISNULL([Specifications].[ListItemId],0) AS [ListItemId]
FROM [SpecificationsTemplate] LEFT OUTER JOIN [Specifications]
ON [SpecificationsTemplate].[Id]=[Specifications].[SpecificationTemplateId]
AND [Specifications].[EntityTypeId]=#EntityTypeId
LEFT OUTER JOIN [UOM] ON [SpecificationsTemplate].[UOMId]=[UOM].[Id]
WHERE [Specifications].[EntityId] IN (#EntityId)
GO
In the above code I modified #EntityId to accept multiple values in the last line of the code. But I am getting an error as cannot convert Varchar to BigINt when i try to pass multiple values into the parameter as #EntityId=9,10,11.
Kindly help me out with the solution.
Thanks !

In your stored procedure change the parameter where condition something like below
Eg:
WHERE ([CostCentre]) collate database_default IN(SELECT Value FROM dbo.FnSplit(#CostCentre,','))
Complete code:
ALTER PROCEDURE [dbo].[SomeSP]
#CostCentre NVARCHAR(255)
AS
SELECT
[ProjectCode],[ProjectName], [ProjectManager],SUM([Hours]) AS [Hours MTD]
FROM dbo.Rpt_NRMA_CATS NC
INNER JOIN PeriodID P ON NC.PeriodID = P.PeriodID
WHERE
([CostCentre]) collate database_default IN (SELECT Value FROM dbo.FnSplit(#CostCentre, ','))

Just change your where condition to
WHERE [Specifications].[EntityId] IN (select item from dbo.fnSplit(#EntityId))
The code for fnSplit function is here

Related

Scalar Variable error using var Table but not Temp Table

I am stumped with this one. I have the following code it works fine up to the point of the last #POC_XLATE in the update statement and then I get the error MUST DECLARE SCALAR VARIABLE.
If I change the table to a temp table the code works fine. I have tried moving the select statement to the end of the code, that didn't work. Hope someone has some suggestion on why it is doing this. Thanks in advance.
declare #POC_XLATE as TABLE(
POC_XLATE_ID int NULL,
TAR_ID int NULL,
POC_USERID varchar(50) NULL,
ACTION_DATE datetime NULL
)
insert into #POC_XLATE(POC_XLATE_ID, TAR_ID, POC_USERID, ACTION_DATE)
select * from POC_XLATE
where POC_XLATE.ACTION_DATE is null
select * from #POC_XLATE
update #POC_XLATE
set ACTION_DATE = TAR_DATA.OPEN_DATE
from TAR_DATA
where #POC_XLATE.TAR_ID = TAR_DATA.TAR_ID
A column alias cannot start with a #. That is the sign for a declared scalar variable. So, use table aliases:
update p
set ACTION_DATE = td.OPEN_DATE
from #POC_XLATE p JOIN
TAR_DATA td
on p.TAR_ID = td.TAR_ID ;
But why you would write the query in two steps?
insert into #POC_XLATE(POC_XLATE_ID, TAR_ID, POC_USERID, ACTION_DATE)
select p.POC_XLATE_ID, p.TAR_ID, p.POC_USERID, td.OPEN_DATE
from POC_XLATE p left join
TAR_DATA td
on p.TAR_ID = td.TAR_ID
where p.ACTION_DATE is null;
One step is much cleaner than two.

How to parse a VARCHAR passed to a stored procedure in SQL Server?

I have two tables tbl_Products and tbl_Brands, both are joined on BrandId.
I have a stored procedure which should return all the products belong to the brand ids passed to it as parameter.
My code is as follows.
create proc Sp_ReturnPrdoucts
#BrandIds varchar(500) = '6,7,8'
AS
BEGIN
SELECT *
FROM tbl_Products as p
JOIN tbl_Brands b ON p.ProductBrandId = b.BrandId
WHERE b.BrandId IN (#BrandIds)
END
But this is giving error as BrandId is INT and #BrandIds is VARCHAR
When I hard code it this way as follows it works fine and returns the desired data from db ..
create proc Sp_ReturnPrdoucts
#BrandIds varchar(500) = '6,7,8'
AS
BEGIN
SELECT *
FROM tbl_Products AS p
JOIN tbl_Brands b ON p.ProductBrandId = b.BrandId
WHERE b.BrandId IN (6,7,8)
END
Any help :)
If possible, don't use varchar for this kind of things, use a table valued parameter instead.
To use a tabled value parameter you should first declare a user defined table type:
CREATE TYPE IntList As Table
(
IntValue int
)
Then change your stored procedure to accept this variable instead of the nvarchar:
create proc Sp_ReturnPrdoucts
#BrandIds dbo.IntList readonly -- Note: readonly is a must!
AS
BEGIN
SELECT *
FROM tbl_Products as p
join tbl_Brands b on p.ProductBrandId=b.BrandId
join #BrandIds ON(b.BrandId = IntValue)
END
The problem is that the IN() operator expects a list of variables separated by commas, while you provide a single variable that it's value is a comma separated string.
If you can't use a table valued parameter, you can use a string spliting function in sql to convert the value of the varchar to a table of ints. there are many splitters out there, I would recommend reading this article before picking one.
Another alternative is to use 'indirection' (as I've always called it)
You can then do..
create proc Sp_ReturnPrdoucts
#BrandIds varchar(500) = '6,7,8'
AS
BEGIN
if (isnumeric(replace(#BrandIds,',',''))=1)
begin
exec('SELECT * FROM tbl_Products as p join tbl_Brands b on p.ProductBrandId=b.BrandId WHERE b.BrandId IN ('+#BrandIds+')')
end
END
This way the select statement is built as a string, then executed.
I've now added validation to ensure that the string being passed in is purely numeric (after removing all the commas)

How to pass a date parameter into a stored procedure

I have created a stored procedure for booking rooms that are not in the tblBooking table for the date which is passing in as a parameter.
Pdate is of type varchar
When I try to run this stored procedure with the command:
usr_sp_Search_Room_by_City_Date '','8','','DEC 13 2014'
It is throws this error:
Msg 102, Level 15, State 1, Line 10
Incorrect syntax near '%D%'.
Here is my procedure:
ALTER procedure usr_sp_Search_Room_by_City_Date
#RoomName varchar(100),
#CityId int = 0,
#LandMark varchar(100),
#BookingDate varchar
as
begin
Declare #Query as varchar(max)
set #Query = 'Select * from tblUser tblusr
join tblUserLogIn tblusrL on tblusr.UserId = tblusrL.UserId
join tblRoom tblP on tblP.RoomId = tblusr.UserId
join tblImage tblImg on tblImg.RoomId = tblusr.UserId
join tblCountry on tblP.RoomCountryId = tblCountry.CntryId
join tblState on tblState.StateId = tblP.RoomStateId
join tblCity on tblCity.CityId = tblP.RoomCityId
join tblRoomType on tblRoomType.RoomTypeId = tblP.RoomTypeId
where ''true''=tblImg.IsProfileImage and ''true''=tblusrL.Isconfirmed'
if(#BookingDate != ' ')
set #Query=#Query+'and tblP.RoomId not in (Select RoomId from tblBookings
where Pdate like ''%'+CAST(#BookingDate AS VARCHAR)+'%'''
exec(#Query)
end
If you printed out the query, you would probably find something like this:
where 'true'=tblImg.IsProfileImage and 'true'=tblusrL.Isconfirmedand tblP.RoomId not in (Select RoomId from tblBookings
Notice that the where statement runs into the and, because you have no spacer.
You don't intend for the comparison to be to '%D%', but that is not a syntax error. This is cause because you have omitted lengths on varchar() declarations.
Here are my recommendations:
Always use length with varchar().
If you want to pass a date into a stored procedure, use a date variable, not a varchar().
Don't use like with dates.
Debug this code by printing out #Query to see what is really being generated.
Is not about the date.
This is the output query from your dynamics query
Select * from tblUser tblusr
join tblUserLogIn tblusrL on tblusr.UserId=tblusrL.UserId
join tblRoom tblP on tblP.RoomId=tblusr.UserId join tblImage tblImg
on tblImg.RoomId=tblusr.UserId
join tblCountry on tblP.RoomCountryId=tblCountry.CntryId join tblState
on tblState.StateId=tblP.RoomStateId
join tblCity on tblCity.CityId=tblP.RoomCityId join tblRoomType
on tblRoomType.RoomTypeId=tblP.RoomTypeId
where 'true'=tblImg.IsProfileImage and 'true'=tblusrL.Isconfirmedand tblP.RoomId not in (Select RoomId from tblBookings
where Pdate like '%0%'
You miss the ")" at the end.
where Pdate like ''%'+CAST(#BookingDate AS VARCHAR)+'%'')'
The source of the actual error is due to you needing a final right parenthesis at the end of:
AS VARCHAR)+'%'')'
Also, you need a space at the beginning of the set #Query=#Query+'and statement. Currently the SQL will render as (partially):
'true'=tblusrL.Isconfirmedand tblP.RoomId not
Even better, you don't even need the CAST as the datatype is already VARCHAR, so the SET controlled by the IF should be:
SET #Query = #Query + ' AND tblP.RoomId not in (Select RoomId from tblBookings
where Pdate like ''%'+ #BookingDate + '%'')';
Always specify a size for variable length datatypes. The #BookingDate input parameter and CAST(#BookingDate AS VARCHAR) (which again, should be removed anyway) should both specify VARCHAR(20). The default size for VARCHAR / NVARCHAR / etc, in some situations, is 1. In other situations it is 30. In either case, do not rely upon defaults.
General notes:
What does the actual data in the Pdate field look like? Just wondering why you are using LIKE instead of = for the test.
You should probably use the BIT datatype for IsProfileImage and Isconfirmed, or at least TINYINT. Either one would be incredibly more efficient than a string field.
How do you pass a date parameter? First, specify the datatype as date, not varchar.
Second, you don't need dynamic sql. You can use a case construct for your conditional logic. Specifically, this:
if(#BookingDate!=' ')
set #Query=#Query+'and tblP.RoomId not in (Select RoomId from tblBookings
where Pdate like ''%'+CAST(#BookingDate AS VARCHAR)+'%'''
can be something like this.
where #BookingDate is null
or
(
#BookingDate is not null
and
tblP.RoomId not in
(Select RoomId from tblBookings
where Pdate = #BookingDate)
)

UDF that accepts one parameter and returns a table

Question: Create a UDF that accepts the State Province and returns the associated Sales Tax Rate, StateProvinceCode and CountryRegionCode (Database is AdventureWorks2012)
Name took the place of State Province because there is no column
called 'State Province', and 'Name' contains the needed information.
This is what I did in the code below.
Is there another way to run this?
In this form Ambiguous column name keeps showing up.
CREATE FUNCTION fx_TxSpCr (#Name Nvarchar(50),
#TaxRate Smallmoney,
#StateProvinceCode Nchar(3),
#CountryRegionCode Nvarchar(3)
)
RETURNS TABLE
AS
RETURN (
SELECT Name,TaxRate,StateProvinceCode,CountryRegionCode
FROM Sales.SalesTaxRate s
JOIN Person.StateProvince t
ON s.StateProvinceID=t.StateProvinceID
JOIN Sales.SalesTerritory u
ON t.TerritoryID=u.TerritoryID
)
SELECT s.TaxRate,t.StateProvinceCode,u.CountryRegionCode
FROM fx_TxSpCr
GROUP BY Name
Thank you both for the contribution. This worked:
CREATE FUNCTION fx_TaxStCtry(#StateProvince nvarchar(50))
RETURNS #TaxStCtry TABLE
(TaxRate SmallMoney not null,
StateProvinceCode Nchar(3) not null ,
CountryRegionCode Nvarchar(3) not null)
AS
BEGIN INSERT #TaxStCtry
SELECT tr.TaxRat,sp.StateProvinceCode,sp.CountryRegionCode
FROM Person.StateProvince sp
JOIN Sales.SalesTaxRate tr
ON tr.stateprovinceid = sp.stateprovinceid
WHERE sp.Name=#StateProvince
RETURN
END
The ambiguity is coming from the lack of aliases in the select statement from your function. It seems like you are trying to use the aliases in the execution of the function, but they actually need to be contained within the function itself. (For example, all three tables have a "name" column.)
After correcting that issue you will find that you actually have not used any of the parameters you have set up for your function. Which does not have to be the full return set of the select statement contained within.
The correct path here is to start with a select statement that returns what you're needing and then turn that into a function. If the data is not being returned at a base level, then you're not ready to start creating a function.

How to pass multiple values to single parameter in stored procedure

I'm using SSRS for reporting and executing a stored procedure to generate the data for my reports
DECLARE #return_value int
EXEC #return_value = [dbo].[MYREPORT]
#ComparePeriod = 'Daily',
#OverrideCompareDate = NULL,
#PortfolioId = '5,6',
#OverrideStartDate = NULL,
#NewPositionsOnly = NULL,
#SourceID = 13
SELECT 'Return Value' = #return_value
GO
In the above when I passed #PortfolioId = '5,6' it is giving me wrong inputs
I need all records for portfolio id 5 and 6 also is this correct way to send the multiple values ?
When I execute my reports only giving #PortfolioId = '5' it is giving me 120 records
and when I execute it by giving #PortfolioId = '6' it is giving me 70 records
So when I will give #PortfolioId = '5,6' it should have to give me only 190 records altogether, but it is giving me more no of records I don't understand where I exactly go wrong .
Could anyone help me?
thanks
all code is too huge to paste , i'm pasting relevant code please suggest clue.
CREATE PROCEDURE [dbo].[GENERATE_REPORT]
(
#ComparePeriod VARCHAR(10),
#OverrideCompareDate DATETIME,
#PortfolioId VARCHAR(50) = '2', --this must be multiple
#OverrideStartDate DATETIME = NULL,
#NewPositionsOnly BIT = 0,
#SourceID INT = NULL
) AS
BEGIN
SELECT
Position.Date,
Position.SecurityId,
Position.Level1Industry,
Position.MoodyFacilityRating,
Position.SPFacilityRating,
Position.CompositeFacilityRating,
Position.SecurityType,
Position.FacilityType,
Position.Position
FROM
Fireball_Reporting.dbo.Reporting_DailyNAV_Pricing POSITION WITH (NOLOCK, READUNCOMMITTED)
LEFT JOIN Fireball.dbo.AdditionalSecurityPrice ClosingPrice WITH (NOLOCK, READUNCOMMITTED) ON
ClosingPrice.SecurityID = Position.PricingSecurityID AND
ClosingPrice.Date = Position.Date AND
ClosingPrice.SecurityPriceSourceID = #SourceID AND
ClosingPrice.PortfolioID IN (
SELECT
PARAM
FROM
Fireball_Reporting.dbo.ParseMultiValuedParameter(#PortfolioId, ',') )
This can not be done easily. There's no way to make an NVARCHAR parameter take "more than one value". What I've done before is - as you do already - make the parameter value like a list with comma-separated values. Then, split this string up into its parts in the stored procedure.
Splitting up can be done using string functions. Add every part to a temporary table. Pseudo-code for this could be:
CREATE TABLE #TempTable (ID INT)
WHILE LEN(#PortfolioID) > 0
BEGIN
IF NOT <#PortfolioID contains Comma>
BEGIN
INSERT INTO #TempTable VALUES CAST(#PortfolioID as INT)
SET #PortfolioID = ''
END ELSE
BEGIN
INSERT INTO #Temptable VALUES CAST(<Part until next comma> AS INT)
SET #PortfolioID = <Everything after the next comma>
END
END
Then, change your condition to
WHERE PortfolioId IN (SELECT ID FROM #TempTable)
EDIT
You may be interested in the documentation for multi value parameters in SSRS, which states:
You can define a multivalue parameter for any report parameter that
you create. However, if you want to pass multiple parameter values
back to a data source by using the query, the following requirements
must be satisfied:
The data source must be SQL Server, Oracle, Analysis Services, SAP BI
NetWeaver, or Hyperion Essbase.
The data source cannot be a stored procedure. Reporting Services does
not support passing a multivalue parameter array to a stored
procedure.
The query must use an IN clause to specify the parameter.
This I found here.
I spent time finding a proper way. This may be useful for others.
Create a UDF and refer in the query -
http://www.geekzilla.co.uk/view5C09B52C-4600-4B66-9DD7-DCE840D64CBD.htm
USE THIS
I have had this exact issue for almost 2 weeks, extremely frustrating but I FINALLY found this site and it was a clear walk-through of what to do.
http://blog.summitcloud.com/2010/01/multivalue-parameters-with-stored-procedures-in-ssrs-sql/
I hope this helps people because it was exactly what I was looking for
Either use a User Defined Table
Or you can use CSV by defining your own CSV function as per This Post.
I'd probably recommend the second method, as your stored proc is already written in the correct format and you'll find it handy later on if you need to do this down the road.
Cheers!
I think, below procedure help you to what you are looking for.
CREATE PROCEDURE [dbo].[FindEmployeeRecord]
#EmployeeID nvarchar(Max)
AS
BEGIN
DECLARE #sqLQuery VARCHAR(MAX)
Declare #AnswersTempTable Table
(
EmpId int,
EmployeeName nvarchar (250),
EmployeeAddress nvarchar (250),
PostalCode nvarchar (50),
TelephoneNo nvarchar (50),
Email nvarchar (250),
status nvarchar (50),
Sex nvarchar (50)
)
Set #sqlQuery =
'select e.EmpId,e.EmployeeName,e.Email,e.Sex,ed.EmployeeAddress,ed.PostalCode,ed.TelephoneNo,ed.status
from Employee e
join EmployeeDetail ed on e.Empid = ed.iEmpID
where Convert(nvarchar(Max),e.EmpId) in ('+#EmployeeId+')
order by EmpId'
Insert into #AnswersTempTable
exec (#sqlQuery)
select * from #AnswersTempTable
END