I am trying to create a stored procedure which will use one of the optional parameters provided.
In the code below they are #nStudentId and #nStudentIds set to NULL initially. Only one of them will be sent when the proc is called. When #nStudentIds are sent they will come-in as comma separated values.
CREATE PROCEDURE [dbo].[usp_GetStudentReferrals]
(
#ProfessorId BIGINT,
#nStudentId BIGINT = NULL,
#nStudentIds NVARCHAR(999) = NULL
)
AS
BEGIN
SELECT DISTINCT SR.StudentReferralId
FROM StudentReferral SR WITH(NOLOCK)
INNER JOIN PotentialCandidate PC WITH(NOLOCK) ON PC.PotentialCandidateId = SR.StudentId
WHERE SR.ProfessorId = #nProfessorId
AND -- this is where I am not able to figure out the logic to use either #nStudentId or #nStudentIds, whichever is passed in.
END
So when #nStudentId is sent it should be this in the AND
SR.StudentId = #nStudentId
When #nStudentIds is available I can use 'IN' like so:
SR.StudentId IN (SELECT value FROM STRING_SPLIT #nStudentIds, ','))
The limitation of my knowledge of SQL shows in this IF, which obviously does not work:
AND (if(#nStudentId <> 0 AND #nStudentId <> -1 AND #nStudentId IS NULL)
SR.StudentId = #nStudentId;
else if(#nStudentIds IS NOT NULL)
SR.StudentId IN (SELECT value FROM STRING_SPLIT#nStudentIds,','))
)
Any suggestions are appreciated.
Thanks in advance.
Regards.
There's literally no need for 2 parameters here. Ideally, what you should be using is a table type parameter, as that maintains the strong typing. Then you can just JOIN to said table type parameter:
CREATE TYPE dbo.IDs AS table (ID bigint);
GO
CREATE PROC dbo.usp_GetStudentReferrals #ProfessorId bigint, #StudentIDs dbo.IDs READONLY AS
BEGIN
SELECT DISTINCT SR.StudentReferralId
FROM dbo.StudentReferral SR --WITH(NOLOCK) --Why are you using NOLOCK? You do know what it does, right?
INNER JOIN dbo.PotentialCandidate PC /*WITH(NOLOCK)*/ ON PC.PotentialCandidateId = SR.StudentId --Why are you using NOLOCK? You do know what it does, right?
INNER JOIN #StudentIDs S ON SR.StudentID = S.ID
WHERE SR.ProfessorId = #ProfessorId; --I assumed this should be #ProfessorId not #nProfessorId
END;
GO
Then you would call the procedure with something like:
DECLARE #ProfessorId bigint, #Students dbo.IDs;
SET #ProfessorId = 123456789;
INSERT INTO #Students (ID)
VALUES(987654321),(5643321987342);
EXEC dbo.usp_GetStudentReferrals #ProfessorId, #Students;
why don't you put IF before SELECT
BEGIN
if(#nStudentId <> 0 AND #nStudentId <> -1 AND #nStudentId IS NULL)
SELECT DISTINCT .....
else
SELECT DISTINCT .....
you can using split string from
link
and change this part
AND (if(#nStudentId <> 0 AND #nStudentId <> -1 AND #nStudentId IS NULL)
SR.StudentId = #nStudentId;
else if(#nStudentIds IS NOT NULL)
SR.StudentId IN (SELECT name FROM dbo.splitstring(#nStudentIds))
)
Related
I have a stored procedure. In that where condition, I want to select the not null value if there are any, else select the null value from the table. Anyone Kindly help me..
ALTER PROCEDURE SearchPromotionBYPromotionANDVehicleID
#PromotionCode VARCHAR(100)
,#TypeId INT
,#LocationId INT
,#ClientId INT
AS
BEGIN
SET NOCOUNT ON;
SELECT top 1 tp.PromotionID
,tp.PromotionCode
,tp.ClientID
,tp.StartDate
,tp.EndDate
,tp.VehicleTypeId
,tv.VehicleType
,tp.LocationId
FROM tblstudent tp
LEFT OUTER JOIN tblType tv ON tp.TypeId = tv.TypeId
WHERE tp.PromotionCode = #PromotionCode
AND
( ( #LocationId IS NOT NULL AND tp.LocationId = #LocationId ) OR (tp.LocationId IS NULL) OR (#LocationId IS NULL) or (tp.LocationId = 0 ) )
In this consider 2 records (r1 and r2) with same promotion code and one with all locations (that is location id 0) and another with a location ID. When the parameter #locationId have a value(consider the value equal to the value of the record r2) then it have to return the record 2. Else have to return r1.
WHERE tp.PromotionCode = #PromotionCode
AND (( #LocationId IS NOT NULL AND tp.LocationId = #LocationId ) OR tp.LocationId IS NULL)
This condition selects those values where #LocationId has a not null and not 0 value, And the value needs to match with tp.LocationId, Otherwise it returns those where tp.LocationId is null.
Is it the result what you want? If you want different, let me know
Can't believe I am stuck with this but how can I check that value I am returning is null in select statement
IF EXISTS(SELECT TU.Tagged FROM TopicUser TU
WHERE TU.TopicId = #TopicId and TU.UserId = #UserId)
BEGIN
--do stuff
END
The value of TU.Tagged is NULL but yet it does go into the condition. In mind it does not exist.
It looks like you need something like:
IF EXISTS(SELECT TU.Tagged
FROM TopicUser TU
WHERE TU.TopicId = #TopicId
AND TU.UserId = #UserId
AND TU.Tagged IS NOT NULL)
BEGIN
--do stuff
END
Otherwise, you're checking only if records meeting your criteria exist, but those records could have a NULL value in the TU.Tagged column.
Solution 1 :
Use IsNULL() Function, When below query return null value IsNULL function replace null value with 0 and if condition treated as False.
IF EXISTS (SELECT IsNULL(TU.Tagged,0) FROM TopicUser TU
WHERE TU.TopicId = #TopicId and TU.UserId = #UserId)
BEGIN
END
Solution 2 :
Use (IS NULL OR IS NOT NULL) Property.
IF EXISTS (SELECT TU.Tagged FROM TopicUser TU
WHERE TU.TopicId = #TopicId and TU.UserId = #UserId
AND TU.Tagged IS NOT NULL)
BEGIN
END
To check that something exists you can simply say:
IF EXISTS(SELECT TOP 1 1 FROM TABLE WHERE ID = '2')
This simply returns a 1 if the record exists. For you the record exists but the column is null. You will need to check on the ID of the user. By this I mean even if something is null then it still treats it as existing.
I hope this makes sense.
You can use ISNULL(). when the select query return null for a value and if you want to replace it with O you can use below query.
IF EXISTS(SELECT ISNULL(TU.Tagged,0) FROM TopicUser TU
WHERE TU.TopicId = #TopicId and TU.UserId = #UserId)
BEGIN
--do stuff
END
As Like this You can replace the null with any value you want.
Need help with WHERE clause in this stored procedure.
How to write WHERE with this parameters and if any of these param contains specific value, then I need to get all values from that column ?
Sample if #post1 contains 1 then select values from that columns that are equals to 1.
But if #post1 contains 0 than select all values from that column. And that for all other parameters.
ALTER PROCEDURE [dbo].[spStavke]
#dat1 date,
#dat2 date,
#god int,
#post1 int,
#post2 int,
#post3 int
AS
BEGIN
SET NOCOUNT ON;
SELECT
[test1]
,[test2]
,[test3]
,[test3]
FROM
[PN].[dbo].[Stavke] AS stavke
LEFT JOIN
PN.dbo.Tip AS tip ON stavke.Vrsta = tip.id
LEFT JOIN
PN.dbo.Vrsta AS vrs ON stavke.Jedinica = vrs.id
END
SELECT
[test1]
,[test2]
,[test3]
,[test3]
FROM [PN].[dbo].[Stavke] as stavke
left join PN.dbo.Tip as tip on stavke.Vrsta=tip.id
left join PN.dbo.Vrsta as vrs on stavke.Jedinica = vrs.id
WHERE (#Post1 = 0 OR (#Post1 = 1 AND 1 IN( TEST1,TEST2,TEST3))
AND (#Post2 = 0 OR (#Post2 = 1 AND 1 IN( TEST1,TEST2,TEST3))
SQL is not my best thing but I have been trying to optimize this stored procedure. It had multiple scalar-valued functions that I tried to change to table-valued functions because I read in many places that it's a more efficient way of doing it. And now I have them made but not real sure how to implement or if I maybe just didn't create them correctly.
This is the function I'm calling.
Alter FUNCTION [IsNotSenateActivityTableValue]
(
#ActivityCode int,
#BillId int,
#TextToDisplay varchar(max)
)
returns #T table(result varchar(max))
as
begin
DECLARE #result varchar(max);
declare #countcodes int;
declare #ishousebill int;
select #ishousebill = count(billid)
from BillMaster
where BillID = #BillID and Chamber = 'H'
If (#ishousebill = 0)
begin
SELECT #countcodes = count([ActivityCode])
FROM [HouseCoreData].[dbo].[ActivityCode]
where ActivityDescription not like '%(H)%' and ActivityType = 'S'
and [ActivityCode] = #ActivityCode
if (#countcodes = 0)
begin
set #result = 'test'
end
else
begin
set #result = 'test2'
end
end
else
begin
set #result = #TextToDisplay
end
RETURN
END
And this is how I was trying to call them like this. I would prefer just being able to put them in the top but really anything that works would be good.
SELECT distinct
ActionDates.result as ActionDate
,ActivityDescriptions.result as ActivityDescription
FROM BillWebReporting.vwBillDetailWithSubjectIndex as vw
left outer join [BillWebReporting].[HasHouseSummary] as HasSummary on vw.BillID = HasSummary.BillID
outer APPLY dbo.IsNotSenateActivityDateTableValue(ActivityCode,vw.BillID,[ActionDate]) ActionDates
OUTER APPLY dbo.IsNotSenateActivityTableValue(ActivityCode,vw.BillID,[ActivityDescription]) as ActivityDescriptions
Getting a count just to see if at least one row exists is very expensive. You should use EXISTS instead, which can potentially short circuit without materializing the entire count.
Here is a more efficient way using an inline table-valued function instead of a multi-statement table-valued function.
ALTER FUNCTION dbo.[IsNotSenateActivityTableValue] -- always use schema prefix!
(
#ActivityCode int,
#BillId int,
#TextToDisplay varchar(max)
)
RETURNS TABLE
AS
RETURN (SELECT result = CASE WHEN EXISTS
(SELECT 1 FROM dbo.BillMaster
WHERE BillID = #BillID AND Chamber = 'H'
) THEN #TextToDisplay ELSE CASE WHEN EXISTS
(SELECT 1 FROM [HouseCoreData].[dbo].[ActivityCode]
where ActivityDescription not like '%(H)%'
and ActivityType = 'S'
and [ActivityCode] = #ActivityCode
) THEN 'test2' ELSE 'test' END
END);
GO
Of course it could also just be a scalar UDF...
ALTER FUNCTION dbo.[IsNotSenateActivityScalar] -- always use schema prefix!
(
#ActivityCode int,
#BillId int,
#TextToDisplay varchar(max)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #result VARCHAR(MAX);
SELECT #result = CASE WHEN EXISTS
(SELECT 1 FROM dbo.BillMaster
WHERE BillID = #BillID AND Chamber = 'H'
) THEN #TextToDisplay ELSE CASE WHEN EXISTS
(SELECT 1 FROM [HouseCoreData].[dbo].[ActivityCode]
where ActivityDescription not like '%(H)%'
and ActivityType = 'S'
and [ActivityCode] = #ActivityCode
) THEN 'test2' ELSE 'test' END
END;
RETURN (#result);
END
GO
Table-valued functions return a table, in which, like any other table, rows have to be inserted.
Instead of doing set #result = ....., do:
INSERT INTO #T (result) VALUES ( ..... )
EDIT: As a side note, I don't really understand the reason for this function to be table-valued. You are essentially returning one value.
First of all UDFs generally are very non-performant. I am not sure about MySQL, but in Sql Server a UDF is recompiled every time (FOR EACH ROW OF OUTPUT) it is executed, except for what are called inline UDFs, which only have a single select statement, which is folded into the SQL of the outer query it is included in... and so is only compiled once.
MySQL does have inline table-valued functions, use it instead... in SQL Server, the syntax would be:
CREATE FUNCTION IsNotSenateActivityTableValue
(
#ActivityCode int,
#BillId int,
#TextToDisplay varchar(max)
)
RETURNS TABLE
AS
RETURN
(
Select case
When y.bilCnt + z.actCnt = 0 Then 'test'
when y.bilCnt = 0 then 'test2'
else #TextToDisplay end result
From (Select Count(billId) bilCnt
From BillMaster
Where BillID = #BillID
And Chamber = 'H') y
Full Join
(Select count([ActivityCode]) actCnt
From [HouseCoreData].[dbo].[ActivityCode]
Where ActivityDescription not like '%(H)%'
And ActivityType = 'S'
And [ActivityCode] = #ActivityCode) z
)
GO
I am having some problems with my WHERE clause (using SQL 2008) . I have to create a stored procedure that returns a list of results based on 7 parameters, some of which may be null. The ones which are problematic are #elements, #categories and #edu_id. They can be a list of ids, or they can be null. You can see in my where clause that my particular code works if the parameters are not null. I'm not sure how to code the sql if they are null. The fields are INT in the database.
I hope my question is clear enough. Here is my query below.
BEGIN
DECLARE #elements nvarchar(30)
DECLARE #jobtype_id INT
DECLARE #edu_id nvarchar(30)
DECLARE #categories nvarchar(30)
DECLARE #full_part bit
DECLARE #in_demand bit
DECLARE #lang char(2)
SET #jobtype_id = null
SET #lang = 'en'
SET #full_part = null -- full = 1, part = 0
SET #elements = '1,2,3'
SET #categories = '1,2,3'
SET #edu_id = '3,4,5'
select
jobs.name_en,
parttime.fulltime_only,
jc.cat_id category,
je.element_id elem,
jt.name_en jobtype,
jobs.edu_id minEdu,
education.name_en edu
from jobs
left join job_categories jc
on (jobs.job_id = jc.job_id)
left join job_elements je
on (jobs.job_id = je.job_id)
left join job_type jt
on (jobs.jobtype_id = jt.jobtype_id)
left join education
on (jobs.edu_id = education.edu_id)
left join
(select job_id, case when (jobs.parttime_en IS NULL OR jobs.parttime_en = '') then 1 else 0 end fulltime_only from jobs) as parttime
on jobs.job_id = parttime.job_id
where [disabled] = 0
and jobs.jobtype_id = isnull(#jobtype_id,jobs.jobtype_id)
and fulltime_only = isnull(#full_part,fulltime_only)
-- each of the following clauses should be validated to see if the parameter is null
-- if it is, the clause should not be used, or the SELECT * FROM ListToInt... should be replaced by
-- the field evaluated: ie if #elements is null, je.element_id in (je.element_id)
and je.element_id IN (SELECT * FROM ListToInt(#elements,','))
and jc.cat_id IN (SELECT * FROM ListToInt(#categories,','))
and education.edu_id IN (SELECT * FROM ListToInt(#edu_id,','))
order by case when #lang='fr' then jobs.name_fr else jobs.name_en end;
END
Something like
and (#elements IS NULL OR je.element_id IN
(SELECT * FROM ListToInt(#elements,',')))
and (#categories IS NULL OR
jc.cat_id IN (SELECT * FROM ListToInt(#categories,',')))
....
should do the trick
je.element_id IN (SELECT * FROM ListToInt(#elements,',')) OR #elements IS NULL
that way for each one
Have you tried explicitly comparing to NULL?
and (#elements is null or je.element_id IN (SELECT * FROM ListToInt(#elements,','))
And so on.