Use Case Statement Based on input Parameters in Sql server - sql

I have need to apply certain logic in one of our stored procedures.
We have a parameter #season in the sp.
If #season = 0, then i have to entire years budget value.
if #season = 1, then i have to take tax-season budget values
if #season = 2, then i have to take pre-season budget values.
i derived startdate and enddate of each season
as #SeasonStrt , #SeasonEnd
#SeasonStart is from January 1 to April 30 and #SeasonEnd from May 1 to December 30
I have tried something like below,
SELECT SUM(ISNULL(lab.BudgetAmt,0)),
SUM(ISNULL(lab.ProjectedHours,0))
FROM [dbo].[Budget] bud
WHERE [Year] = #taxyear
AND ((#season = 0) OR (Season= #season))
AND CASE WHEN #season in (1,2)
THEN bud.[week] >= CASE WHEN #season in (1,2)THEN #SeasonStrt ELSE bud.[week] END
AND bud.[week] <= CASE WHEN #season in (1,2)THEN #SeasonStrt ELSE bud.[week] END
Sql server gives syntax error. What will be solution which meets my requirement?
thanks for the help

Try this:
SELECT SUM(ISNULL(lab.BudgetAmt,0)),
SUM(ISNULL(lab.ProjectedHours,0))
FROM [dbo].[Budget] bud
WHERE [Year] = #taxyear
AND
(
((#season = 0) AND (Season = #season))
OR ((#season = 1) AND (bud.[week] >= #SeasonStrt))
OR ((#season = 2) AND (bud.[week] <= #SeasonStrt))
)
So, idea is simple: combine your conditions with OR and specific #season value

Related

Move Functions from Where Clause to Select Statement

I have a union query that runs abysmally slow I believe mostly because there are two functions in the where clause of each union. I am pretty sure that there is no getting around the unions, but there may be a way to move the functions from the where of each. I won't post ALL of the union sections because I don't think it is necessary as they are all almost identical with the exception of one table in each. The first function was created by someone else but it takes a date, and uses the "frequency" value like "years, months, days, etc." and the "interval" value like 3, 4, 90 to calculate the new "Due Date". For instance, a date of today with a frequency of years, and an interval of 3, would produce the date 4/21/2025. Here is the actual function:
ALTER FUNCTION [dbo].[ReturnExpiration_IntervalxFreq](#Date datetime2,#int int, #freq int)
RETURNS datetime2
AS
BEGIN
declare #d datetime2;
SELECT #d = case when #int = 1 then null-- '12-31-9999'
when #int = 2 then dateadd(day,#freq,#date)
when #int = 3 then dateadd(week,#freq,#date)
when #int = 4 then dateadd(month,#freq,#date)
when #int = 5 then dateadd(quarter,#freq,#date)
when #int = 6 then dateadd(year,#freq,#date)
end
RETURN #d;
The query itself is supposed to find and identify records whose Due Date has past or is within 90 days of the current date. Here is what each section of the union looks like
SELECT
R.RequirementId
, EC.EmployeeCompanyId
, EC.CompanyId
, DaysOverdue =
CASE WHEN
R.DueDate IS NULL
THEN
CASE WHEN
EXISTS(SELECT 1 FROM tbl_Training_Requirement_Compliance RC WHERE RC.EmployeeCompanyId = EC.EmployeeCompanyId AND RC.RequirementId = R.RequirementId AND RC.Active = 1 AND ((DATEDIFF(DAY, R.DueDate, GETDATE()) > -91 OR R.DueDate Is Null ) OR (DATEDIFF(DAY, dbo.ReturnExpiration_IntervalxFreq(TRC.EffectiveDate, R.IntervalId, R.Frequency), GETDATE()) > -91)) OR R.IntervalId IS NULL)
THEN
DateDiff(day,ISNULL(dbo.ReturnExpiration_IntervalxFreq(TRC.EffectiveDate, R.IntervalId, R.Frequency), '12/31/9999'),getdate())
ELSE
0
END
ELSE
DATEDIFF(day,R.DueDate,getdate())
END
,CASE WHEN
EXISTS(SELECT 1 FROM tbl_Training_Requirement_Compliance RC WHERE RC.EmployeeCompanyId = EC.EmployeeCompanyId AND RC.RequirementId = R.RequirementId AND RC.Active=1 AND (GETDATE() > dbo.ReturnExpiration_IntervalxFreq(RC.EffectiveDate, R.IntervalId, R.Frequency) OR R.IntervalId IS NULL))
THEN
CONVERT(VARCHAR(12),dbo.ReturnExpiration_IntervalxFreq(TRC.EffectiveDate, R.IntervalId, R.Frequency), 101)
ELSE
CONVERT(VARCHAR(12),R.DueDate,101)
END As DateDue
FROM
#Employees AS EC
INNER JOIN dbo.tbl_Training_Requirement_To_Position TRP ON TRP.PositionId = EC.PositionId
INNER JOIN #CompanyReqs R ON R.RequirementId = TRP.RequirementId
LEFT OUTER JOIN tbl_Training_Requirement_Compliance TRC ON TRC.EmployeeCompanyId = EC.EmployeeCompanyId AND TRC.RequirementId = R.RequirementId AND TRC.Active = 1
WHERE
NOT EXISTS(SELECT 1
FROM tbl_Training_Requirement_Compliance RC
WHERE RC.EmployeeCompanyId = EC.EmployeeCompanyId
AND RC.RequirementId = R.RequirementId
AND RC.Active = 1
)
OR (
(DATEDIFF(DAY, R.DueDate, GETDATE()) > -91
OR R.DueDate Is Null )
OR (DATEDIFF(DAY, dbo.ReturnExpiration_IntervalxFreq(TRC.EffectiveDate, R.IntervalId, R.Frequency), GETDATE()) > -91))
UNION...
It is supposed to exclude records that either don't exist at all on the tbl_Training_Requirement_Compliance table, or if they do exist, once the frequency an intervals have been calculated, would have a new due date that is within 90 days of the current date. I am hoping that someone with much more experience and expertise in SQL Server can show me a way, if possible, to remove the functions from the WHERE clause and help the performance of this stored procedure.

Use IF statement within a calulated field

I am trying to determine all sales within the current financial year and wanted to incorporate an If statement as a calculated field to do so. Please see my code below.
SELECT RtnUserId, COUNT(*) AS Returns_, RtnDt, COUNT(RtnDt) AS DtRet,
IF
BEGIN
YEAR(RtnDt) = YEAR(GETDATE()) AND MONTH(RtnDt) >= 4
RETURN 'INDATE'
END as Financial_Period
FROM dbo.vw_AN_Admin_VendorReturns
WHERE (RtnUserId = 'BEND1') OR
(RtnUserId = 'DEENA') OR
(RtnUserId = 'RICHARDK2')
GROUP BY RtnUserId, RtnDt,
IF
BEGIN
YEAR(RtnDt) = YEAR(GETDATE()) AND MONTH(RtnDt) >= 4
RETURN'INDATE'
END

correct count of grouped results

I have a procedure:
ALTER PROCEDURE [dbo].[GetActualFeedbackQueueTree]
#dtNow datetime
as
BEGIN
select
count(f.Id) as [Total],
f.AccountCode,
f.AccountName,
f.Utc,
f2.CityCode,
f2.CityName
from
InnerPortal.Feedback.QueueFeedback f
left join
InnerPortal.Feedback.QueueFeedback f2
on
f2.AccountCode = f.AccountCode
where
(f.Done is null or f.Done = 0) and
(f.Busy is NULL or f.Busy = 0) and
((DATEPART(hour, DATEADD(HOUR, f.Utc, #dtNow)) >= 9 ) and
(DATEPART(hour, DATEADD(HOUR, f.Utc, #dtNow)) <= 20))
group by
f.AccountCode, f2.CityCode,
f2.CityName, f.AccountName, f.Utc
END
I group rows by AccountName and by CityName. As result we have something like a tree. The problem is the [Total] not calculates correctly.
Then I get a select for a special AccountCode the count if much less then get me as result the procedure. For example:
select count(f.Id) from Feedback.QueueFeedback f where f.AccountCode = '01507'
returns 16 rows but the procedure result is 256.
The target is to get a count of collected rows with the same account. How to make it work correctly?
Thanks.
Software: T-Sql, Ms Sql server 2012
Pretty sure you want
count(distinct(f.Id))

How to add check for January in SQL statement

I'm creating a report using SQL to pull logged labor hours from our labor database for the previous month. I have it working great, but need to add logic to prevent it from breaking when it runs in January. I've tried adding If/Then statements and CASE logic, but I don't know if I'm just not doing it right, or if our system can't process it. Here's the snippet that pulls the date range:
SELECT
...
FROM
...
WHERE
...
AND
YEAR(ENTERDATE) = YEAR(current date) AND MONTH(ENTERDATE) = (MONTH(current date)-1)
Just use AND as a barrier like this. In January, the second clause will be executed instead of the first one:
SELECT
...
FROM
...
WHERE
...
AND
(
(
(MONTH(current date) > 1) AND
(YEAR(ENTERDATE) = YEAR(current date) AND MONTH(ENTERDATE) = (MONTH(current date)-1))
-- this one gets used from Feb-Dec
)
OR
(
(MONTH(current date) = 1) AND
(YEAR(ENTERDATE) = YEAR(current date) - 1 AND MONTH(ENTERDATE) = 12)
-- alternatively, in Jan only this one gets used
)
)
If your report is always going to be for the previous month, then I think the simplest idea is to declare the year and month of the previous month and then reference those in the Where clause. For example:
Declare LastMo_Month Integer = MONTH(DATEADD(MONTH,-1,getdate()));
Declare LastMo_Year Integer = YEAR(DATEADD(MONTH,-1,getdate()));
Select ...
Where MONTH(EnterDate) = #LastMo_Month
and YEAR(EnterDate) = #LastMo_Year
You could even take it a step further and allow the report to be created for any number of months ago:
Declare Delay Integer = -1;
Declare LastMo_Month Integer = MONTH(DATEADD(MONTH,#Delay,getdate()));
Declare LastMo_Year Integer = YEAR(DATEADD(MONTH,#Delay,getdate()));
Select ...
Where MONTH(EnterDate) = #LastMo_Month
and YEAR(EnterDate) = #LastMo_Year
Hope this helps.
PS - This is my first answer on StackOverflow, so sorry if the formatting isn't right!
if(month(getdate()) = 1)
begin
your jan logic
end
else
begin
your logic
end
The above answer with the Case is ok, but running a CASE on a huge result set would be pretty costly
WHERE
...
AND
DATEPART(yy,ENTERDATE) = DATEPART(yy,DATEADD(m,-1,ENTERDATE))
AND DATEPART(m,ENTERDATE) = DATEPART(m,DATEADD(m,-1,ENTERDATE))
Which Dialect of SQL are you speaking?
As opposed to doing it all with case statements, just use the built it date / time functions to subtract a month from the current date, which should handle crossing year boundaries.
TransACT
WHERE
YEAR(ENTERDATE) = year(dateadd(MONTH,-1, CURRENT_TIMESTAMP))
AND MONTH(ENTERDATE) = month(dateadd(MONTH,-1, CURRENT_TIMESTAMP))
Mysql
WHERE
YEAR(ENTERDATE) = YEAR(date_sub(curdate(),INTERVAL 1 MONTH))
AND MONTH(ENTERDATE) = MONTH(date_sub(curdate(),INTERVAL 1 MONTH) )
Try adding the previous month and year to your SELECT statement:
SELECT
...
,CASE MONTH(current date)
WHEN 1 THEN 12
ELSE MONTH(current date)-1
END AS previous_month
,CASE MONTH(current date)
WHEN 1 THEN YEAR(current date)-1
ELSE YEAR(current date)
END AS previous_year
FROM
...
WHERE
...
AND YEAR(ENTERDATE) = previous_year
AND MONTH(ENTERDATE) = previous_month
This should allow you to set the value before the WHERE comparison. This should be the most performant way to perform this procedure, as it avoids creating two entirely separate clauses or using OR.

Find the difference between two fields in the same table

I have a table which stores monthly billing information.
CREATE TABLE [dbo].[billing_history](
[id] [numeric](18, 0) IDENTITY(1,1) NOT NULL,
[reading_date] [date] NOT NULL,
[reading] [numeric](18, 0) NOT NULL,
[consumer_id] [int] NOT NULL)
The consumer_id is a foreign key referencing the consumer details table.
What i want is to subtract every customer current reading from the reading of the previous month. This would generate the current bill. Any ideas.
You could use something similar to this, where you would replace the values of the month/year that you want to return:
select b1.consumer_id,
sum(b1.reading - isnull(b2.reading, 0)) Total
from billing_history b1
left join billing_history b2
on b1.consumer_id = b2.consumer_id
and month(b2.reading_date) =12
and year(b2.reading_date) = 2012
where month(b1.reading_date) = 1
and year(b1.reading_date) = 2013
group by b1.consumer_id;
See SQL Fiddle with Demo.
If you don't want to pass in the values of the month and year to search and you only want the current/previous month, then you could use something similar to this using a CTE:
;with cur as
(
select consumer_id,
reading,
month(getdate()) curMonth,
year(getdate()) curYear,
case when month(getdate()) = 1 then 12 else month(getdate()) -1 end preMonth,
case when month(getdate()) = 1 then year(getdate())-1 else year(getdate()) end preYear
from billing_history
where month(reading_date) = month(getdate())
and year(reading_date) = year(getdate())
)
select c.consumer_id,
sum(c.reading - isnull(pre.reading, 0)) TotalReading
from cur c
left join billing_history pre
on c.consumer_id = pre.consumer_id
and month(pre.reading_date) = c.preMonth
and year(pre.reading_date) = c.preYear
group by c.consumer_id
See SQL Fiddle with Demo
This version gets both the current/previous month and year values to be used. If you are not familiar with CTE syntax, this can also be written as:
select c.consumer_id,
sum(c.reading - isnull(pre.reading, 0)) TotalReading
from
(
select consumer_id,
reading,
month(getdate()) curMonth,
year(getdate()) curYear,
case when month(getdate()) = 1 then 12 else month(getdate()) -1 end preMonth,
case when month(getdate()) = 1 then year(getdate())-1 else year(getdate()) end preYear
from billing_history
where month(reading_date) = month(getdate())
and year(reading_date) = year(getdate())
) c
left join billing_history pre
on c.consumer_id = pre.consumer_id
and month(pre.reading_date) = c.preMonth
and year(pre.reading_date) = c.preYear
group by c.consumer_id;
See SQL Fiddle with Demo.
As you can see in my queries I used the aggregate function SUM() and a GROUP BY on the consumer_id. I did this in the event you had more than one reading per customer. If you know you will only have one reading per month, then you could remove the aggregate.