SQL: Declaring multiple variables that will not all be used at the same time - sql

I'm writing a query that multiple variables will need to be set for but not all used at the same time. It looks something like this.
Declare #SuveryID as Int
Declare #StateAbbrev as Varchar
Declare #InvStart as Date
Declare #InvEnd as Date
Set #SuveryID = ''
Set #StateAbbrev = ''
Set #InvStart = ''
Set #InvEnd = ''
What I'm wanting it to do is whenever survey ID has a value in it, the others will be ignored. And whenever #StateAbbrev, #InvStart, and #InvEnd have a value, #SurveryID is ignored.

One way would be like...
if #SuveryID is null
begin
select *
from YourTable
where <all your other variables>
end
else
begin
select *
from YourTable
where Column = #SuveryID
end
Another way would be to set the variables to NULL when #SuveryID is not null and then use a catch all query. These are called Kitchen Sink queries and that article from Aaron Bertrand is worth a read for sure.
if #SuveryID is not null
begin
set #StateAbbrev = null
set #InvStart = null
<set all other variables to null>
end
select *
from YourTable
where (Column = #SuveryID or #SuveryID is null)
and (Col2 = #StateAbbrev or #StateAbbrev is null)
and <continue for all variables>

Related

how to use declared variable to select data from another table in case when condition?

I made select query in which i want to select data based on condition.For this i declared one variable and set value of that variable in else part.I want to use that variable for further select in same else part how can i achieve this?Please Help
declare #stateid int
select CASE WHEN MstCustomerAddressInfo.StateId is null
THEN 24
ELSE set #stateid = MstCustomerAddressInfo.StateId
select mststate.statecode from mststate where MstState.StateId = #stateid
END AS StateCode
No, you can't have SET inside a CASE expression. Even you can't have multiple statements.
Same query you can write as following.
declare #stateid int
select CASE
WHEN MstCustomerAddressInfo.StateId is null THEN 24
ELSE
-- set #stateid = MstCustomerAddressInfo.StateId
(select mststate.statecode
from mststate
where MstState.StateId = MstCustomerAddressInfo.StateId)
END AS StateCode
from [Your_Table]

SQL Table Valued Function in Select Statement

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

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.

SQL SERVER: Check if variable is null and then assign statement for Where Clause

I am trying to achieve something like the below in WHERE clause in sql.
if (#zipCode ==null)
begin
([Portal].[dbo].[Address].Position.Filter(#radiusBuff) = 1)
end
else if(#zipCode !=null)
begin
([Portal].[dbo].[Address].PostalCode=#zipCode )
end
I tried the following:
WHERE ((#zipCode IS NOT NULL AND ([Portal].[dbo].[Address].PostalCode=#zipCode)) OR (#zipCode IS NULL AND ([Portal].[dbo].[Address].Position.Filter(#radiusBuff) = 1)))
which is wrong. Can anyone help in framing the exact statement. Thanks!
is null is the syntax I use for such things, when COALESCE is of no help.
Try:
if (#zipCode is null)
begin
([Portal].[dbo].[Address].Position.Filter(#radiusBuff) = 1)
end
else
begin
([Portal].[dbo].[Address].PostalCode=#zipCode )
end
Isnull() syntax is built in for this kind of thing.
declare #Int int = null;
declare #Values table ( id int, def varchar(8) )
insert into #Values values (8, 'I am 8');
-- fails
select *
from #Values
where id = #Int
-- works fine
select *
from #Values
where id = isnull(#Int, 8);
For your example keep in mind you can change scope to be yet another where predicate off of a different variable for complex boolean logic. Only caveat is you need to cast it differently if you need to examine for a different data type. So if I add another row but wish to specify int of 8 AND also the reference of text similar to 'repeat' I can do that with a reference again back to the 'isnull' of the first variable yet return an entirely different result data type for a different reference to a different field.
declare #Int int = null;
declare #Values table ( id int, def varchar(16) )
insert into #Values values (8, 'I am 8'), (8, 'I am 8 repeat');
select *
from #Values
where id = isnull(#Int, 8)
and def like isnull(cast(#Int as varchar), '%repeat%')
is null can be used to check whether null data is coming from a query as in following example:
declare #Mem varchar(20),#flag int
select #mem=MemberClub from [dbo].[UserMaster] where UserID=#uid
if(#Mem is null)
begin
set #flag= 0;
end
else
begin
set #flag=1;
end
return #flag;
Try a case statement
WHERE
CASE WHEN #zipCode IS NULL THEN 1
ELSE #zipCode
END
Try the following:
if ((select VisitCount from PageImage where PID=#pid and PageNumber=5) is NULL)
begin
update PageImage
set VisitCount=1
where PID=#pid and PageNumber=#pageno
end
else
begin
update PageImage
set VisitCount=VisitCount+1
where PID=#pid and PageNumber=#pageno
end

If Else If In a Sql Server Function

I have this function I am trying to create. When I parse it, it works fine, but to actually create the function in the database it says my column names are invalid. That is not true, I spelled them correctly. Here is the code:
ALTER FUNCTION [dbo].[fnTally] (#SchoolId nvarchar(50))
RETURNS int
AS
BEGIN
DECLARE #Final nvarchar
IF EXISTS (
SELECT
question,
yes_ans,
no_ans,
na_ans,
blank_ans
FROM dbo.qrc_maintally
WHERE school_id = #SchoolId
)
IF yes_ans > no_ans AND yes_ans > na_ans
BEGIN
SET #Final = 'Yes'
END
ELSE IF no_ans > yes_ans AND no_ans > na_ans
BEGIN
SET #Final = 'No'
END
ELSE IF na_ans > yes_ans AND na_ans > no_ans
BEGIN
SET #Final = 'N/A'
END
RETURN #Final
END
ALTER FUNCTION [dbo].[fnTally] (#SchoolId nvarchar(50))
RETURNS nvarchar(3)
AS BEGIN
DECLARE #Final nvarchar(3)
SELECT #Final = CASE
WHEN yes_ans > no_ans AND yes_ans > na_ans THEN 'Yes'
WHEN no_ans > yes_ans AND no_ans > na_ans THEN 'No'
WHEN na_ans > yes_ans AND na_ans > no_ans THEN 'N/A' END
FROM dbo.qrc_maintally
WHERE school_id = #SchoolId
Return #Final
End
As you can see, this simplifies the code a lot. It also makes other errors in your code more obvious: you're returning an nvarchar, but declared the function to return an int (corrected in the code above).
You'll need to create local variables for those columns, assign them during the select and use them for your conditional tests.
declare #yes_ans int,
#no_ans int,
#na_ans int
SELECT #yes_ans = yes_ans, #no_ans = no_ans, #na_ans = na_ans
from dbo.qrc_maintally
where school_id = #SchoolId
If #yes_ans > #no_ans and #yes_ans > #na_ans
begin
Set #Final = 'Yes'
end
-- etc.
No one seems to have picked that if (yes=no)>na or (no=na)>yes or (na=yes)>no, you get NULL as the result. Don't believe this is what you are after.
Here's also a more condensed form of the function, which works even if any of yes, no or na_ans is NULL.
USE [***]
GO
/****** Object: UserDefinedFunction [dbo].[fnActionSq] Script Date: 02/17/2011 10:21:47 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[fnTally] (#SchoolId nvarchar(50))
RETURNS nvarchar(3)
AS
BEGIN
return (select (
select top 1 Result from
(select 'Yes' Result, yes_ans union all
select 'No', no_ans union all
select 'N/A', na_ans) [ ]
order by yes_ans desc, Result desc)
from dbo.qrc_maintally
where school_id = #SchoolId)
End
If yes_ans > no_ans and yes_ans > na_ans
You're using column names in a statement (outside of a query). If you want variables, you must declare and assign them.
I think you'd be better off with a CASE statement, which works a lot more like IF/ELSEIF
DECLARE #this int, #value varchar(10)
SET #this = 200
SET #value = (
SELECT
CASE
WHEN #this between 5 and 10 THEN 'foo'
WHEN #this between 10 and 15 THEN 'bar'
WHEN #this < 0 THEN 'barfoo'
ELSE 'foofoo'
END
)
More info: http://technet.microsoft.com/en-us/library/ms181765.aspx
Look at these lines:
If yes_ans > no_ans and yes_ans > na_ans
and similar. To what do "yes_ans" etc. refer? You're not using these in the context of a query; the "if exists" condition doesn't extend to the column names you're using inside.
Consider assigning those values to variables you can then use for your conditional flow below. Thus,
if exists (some record)
begin
set #var = column, #var2 = column2, ...
if (#var1 > #var2)
-- do something
end
The return type is also mismatched with the declaration. It would help a lot if you indented, used ANSI-standard punctuation (terminate statements with semicolons), and left out superfluous begin/end - you don't need these for single-statement lines executed as the result of a test.