Lookup value in Query - sql

I'm trying to replace the local variables i've declared below to capture them in calculated columns.
So the [YTD] column would look up Today's Date - 1 and return the [FiscalDayOfYear] making everything in that column less than that "YTD" and anything greater "NA"
DECLARE #ytd FLOAT = 124
DECLARE #monthly FLOAT = 4
SELECT *
FROM(
SELECT [Date]
,[FiscalDayOfYear]
,[FiscalYear]
,[FiscalMonthNumber]
,[FiscalWeekNumber]
,[YTD] = IIF([FiscalDayOfYear] <= #ytd, 'YTD','NA')
,[MTD] = IIF(([FiscalDayOfYear] <= #ytd) AND ([FiscalMonthNumber] = #monthly), 'MTD','NA')
FROM [DL].[Date]
WHERE CONVERT(date,Date) >= '2018-01-01') AS DT
UNPIVOT
(
[FLAG] FOR FLAGS IN ([YTD], [MTD])
) AS pivoted_tbl
WHERE [FLAG] != 'NA'
Because of our fiscal calendar I can't just use the Date column I've got to compare to day of year in our calendar.

Related

Invalid Column Name When Setting New Variable Equal to Expression

I need to calculate a percentage based off of two columns in my query and store that number in a new variable. When I set the variable equal to the expression I get an "Invalid column name" error.
SELECT
Count(Case When HMC_Place_Position is null Then 0 end) as Parts,
COUNT(*) AS Total_Parts, /*Total Parts */
COUNT(CASE
WHEN Outfeed_Place_Time IS NOT NULL THEN 1
END) AS Total_Good_Parts /*Total Good Parts */
FROM PartData_GKN05_C
WHERE Infeed_Pick_Time >= DATEADD(day,-7, GETDATE())
ALTER TABLE PartData_GKN05_C Add Total_Good_Parts int
DECLARE #Total_Good_Percent AS float = ((Total_Good_Parts / Total_Parts)*100)
I believe you are looking to get the percentage of "good" parts from the total count of part recordss in PartData_GKN05_C.
So using your definition of " good parts " (Outfeed_Place_Time IS NOT NULL), the query below counts those and then divides by the count of all the part records in the table.
Since "count()" returns an integer value, we have to cast one of the "count()" as float BEFORE we divide them so that SQL does not return a zero (Since an "int / int" does not return decimals while a float does).
We only have to convert one of the "Count()" because SQL will implicitly convert the other one but feel free to convert both to float explicitly if you'd like.
Here is the code :
DECLARE
#Total_Good_Percent float
SELECT
#Total_Good_Percent = (
COUNT(
CASE
WHEN Outfeed_Place_Time IS NOT NULL
THEN 1
END
)
/convert(float,count(*))
)*100
FROM
PartData_GKN05_C
WHERE
Infeed_Pick_Time >= DATEADD(day, -7, GETDATE());
select
#Total_Good_Percent
try this code:
DECLARE #Total_Good_Parts INT, #Total_Parts INT;
SELECT
--Count(Case When HMC_Place_Position is null Then 0 end) as Parts,
#Total_Parts = COUNT(*),
#Total_Good_Parts = COUNT(CASE
WHEN Outfeed_Place_Time IS NOT NULL
THEN 1
END)
FROM PartData_GKN05_C
WHERE Infeed_Pick_Time >= DATEADD(day, -7, GETDATE());
ALTER TABLE PartData_GKN05_C
ADD Total_Good_Parts INT;
DECLARE #Total_Good_Percent AS FLOAT= ((#Total_Good_Parts / #Total_Parts) * 100.00);

Count Business Days Between Start Date and Current Date

I am trying to use a predefined INT value giving 1 or 0 as being a business day or not to count the rolling business days sequence. I have tried a lot of different code and checked out different posts here but none are specific enough to work with mine.
The predefined INT value is "business_day_flag_int". This comes from converting the calculations giving me "day_business_day_flag" which is a bit value. Currently Saturday/Sunday and Banking holidays trigger a 0 for "day_business_day_flag" and Mon-Fri being non holiday give it a 1 value.
How can I get this to work in an Update table that I can add to the rest of my table generation file? If more information is needed let me know.
I've tried a bunch of different alterations and variations of what I have here. If I remove date values it gives me an int value for all rows in the column of roughly 12600 business days. If I use with the date range it gives me
DECLARE #StartDate DATETIME = '01/01/2000' --Starting value of Date Range
DECLARE #EndDate DATETIME = '01/01/2050' --End Value of Date Range
DECLARE
#DayOfWeekInMonth INT,
#DayOfWeekInYear INT,
#DayOfQuarter INT,
#WeekOfMonth INT,
#CurrentYear INT,
#CurrentMonth INT,
#CurrentQuarter INT
DECLARE #CurrentDate AS DATETIME = #startDate
SET #CurrentMonth = DATEPART(MM, #CurrentDate)
SET #CurrentYear = DATEPART(YY, #CurrentDate)
SET #CurrentQuarter = DATEPART(QQ, #CurrentDate)
UPDATE [EDW_MDM].[dbo].[CALENDAR_DIM] SET
business_day_flag_int = Convert(INT, day_business_day_flag)
UPDATE [EDW_MDM].[dbo].[CALENDAR_DIM] SET
rolling_business_day_sequence = (SELECT count(business_day_flag_int) FROM [EDW_MDM].[dbo].[CALENDAR_DIM]
WHERE business_day_flag_int = 1 and
day_date between #StartDate and #CurrentDate)
I want the column "rolling_business_day_sequence" to count sequentially business days past. For example row 1 = 1, row 2 = 2, etc. Until the end of my calendar.
Update 1: Edited the line of code to
UPDATE [EDW_MDM].[dbo].[FCFCU_CALENDAR_DIM] SET
rolling_business_day_sequence = datediff(day,#StartDate,day_date) WHERE day_business_day_flag = 1
This gave me counting days and set rolling_business_day_sequence row values to null where not having day_busienss_day_flag = 1 and still counting them instead of not counting them. How can I make it not add the day?
Consider a window function sum on your WHERE conditions to cumulatively count all instances of business_day_flag_int = 1 within specified date range. However, to use window functions in UPDATE, a CTE or subquery is required.
WITH CTE AS
(
SELECT ID, SUM(CASE WHEN day_date BETWEEN #StartDate AND #CurrentDate
AND business_day_flag_int = 1
THEN 1
ELSE 0
END) OVER (ORDER BY day_date) AS running_sequence
FROM [EDW_MDM].[dbo].[CALENDAR_DIM]
)
UPDATE t
FROM [EDW_MDM].[dbo].[CALENDAR_DIM] t
JOIN CTE ON t.ID = CTE.ID
SET t.rolling_business_day_sequence = CTE.running_sequence

Get date range between dates having only month and day every year

I need to get date range between 1st July till 31st October every year. Based on that I have to update another column.
Date field is datetime. Should be like this below:
Select Cash = Case When date between '1st July' and '31st October' Then (Cash * 2) End
From MytTable
Note: this range should work for each and every year.
This is one way:
SELECT Cash = CASE WHEN RIGHT(CONVERT(VARCHAR(8),[date],112),4)
BETWEEN '0701' AND '1031' THEN Cash*2
ELSE Cash END --I added this
For your case you could just use the month and make sure it falls between 7 to 10.
This is how your query will be:
select Cash = case when month([Date]) in (7, 8, 9, 10) then (Cash * 2) else Cash end
or
select Cash = case when month([Date]) between 7 and 10 then (Cash * 2) else Cash end
This solution worked for me to get some themes that have been recurring scheduled by month and day. It handles spanning multiple years for example an item scheduled from Nov 1 to March 1.
My data is stored like this:
ThemeName, StartMonth, StartDay, EndMonth, EndDay
Christmas, 12,1,12,26
Winter, 11, 1, 3, 1
Spring, 3,1,5,1
Sports, 0,0,0,0 //continuous
Here is the query:
SELECT
DISTINCT ThemeName
FROM (
SELECT
CASE WHEN EndDate < StartDate AND ((Current Between StartDate AND 1231) OR (Current Between 0101 AND EndDate) ) THEN -- span multiple year between dates
ThemeName
WHEN StartDate < EndDate AND Current Between StartDate AND EndDate THEN -- normal between dates
ThemeName
WHEN StartDate = 0 AND EndDate = 0 THEN -- continuous
ThemeName
ELSE
'NG'
END as ThemeName
FROM (
SELECT
ThemeName, StartDate, EndDate, Current
FROM (
SELECT
ThemeName,
CAST(Concat(LPAD(CONVERT(StartMonth , CHAR(2)),2,'0'), LPAD(CONVERT(StartDay , CHAR(2)),2,'0') ) as DECIMAL) as StartDate,
CAST(Concat(LPAD(CONVERT(EndMonth , CHAR(2)),2,'0'), LPAD(CONVERT(EndDay , CHAR(2)),2,'0') ) as DECIMAL) as EndDate,
CAST(Concat(LPAD(CONVERT(MONTH(CURRENT_DATE) , CHAR(2)),2,'0'), LPAD(CONVERT(DAY(CURRENT_DATE) , CHAR(2)),2,'0') ) as DECIMAL) as current
FROM
companythemeschedules
WHERE
companyid = 221
) a
) b
) c
WHERE
ThemeName != 'NG'
TRY THIS ONE:
DECLARE #DT DATE = GETUTCDATE() , #START_DATE VARCHAR(10) = '07-01' , #END_DATE VARCHAR(10) = '10-31'
SELECT
CASE
WHEN RIGHT(#DT,5) BETWEEN #START_DATE AND #END_DATE
THEN
(CASH * 2)
ELSE
'NO MATCH'
END AS CASH

Select date + 3 days, not including weekends and holidays

I've found a number of answers to the problem of doing a date-diff, in SQL, not including weekends and holidays. My problem is that I need to do a date comparison - how many child records are there whose work date is within three days of the parent record's send date?
Most of the date-diff answers involve a calendar table, and I think if I can build a sub-select that returns the date+3, I can work out the rest. But I can't figure out how to return a date+3.
So:
CREATE TABLE calendar
(
thedate DATETIME NOT NULL,
isweekday SMALLINT NULL,
isholiday SMALLINT NULL
);
And:
SELECT thedate AS fromdate, xxx AS todate
FROM calendar
What I want is for todate to be fromdate + 72 hours, not counting weekends and holidays. Doing a COUNT(*) where isweekday and not isholiday is simple enough, but doing a DATEADD() is another matter.
I'm not sure where to start.
EDIT:
Changed to include non-workdays as valid fromDates.
WITH rankedDates AS
(
SELECT
thedate
, ROW_NUMBER()
OVER(
ORDER BY thedate
) dateRank
FROM
calendar c
WHERE
c.isweekday = 1
AND
c.isholiday = 0
)
SELECT
c1.fromdate
, rd2.thedate todate
FROM
(
SELECT
c.thedate fromDate
,
(
SELECT
TOP 1 daterank
FROM
rankedDates rd
WHERE
rd.thedate <= c.thedate
ORDER BY
thedate DESC
) dateRank
FROM
calendar c
) c1
LEFT JOIN
rankedDates rd2
ON
c1.dateRank + 3 = rd2.dateRank
You could put a date rank column on the calendar table to simplify this and avoid the CTE:
CREATE TABLE
calendar
(
TheDate DATETIME PRIMARY KEY
, isweekday BIT NOT NULL
, isHoliday BIT NOT NULL DEFAULT 0
, dateRank INT NOT NULL
);
Then you'd set the daterank column only where it's a non-holiday weekday.
This should do the trick, change the number in the "top" to the number of days you want to include.
declare #date as datetime
set #date = '5/23/13'
select
max(_businessDates.thedate)
from (
select
top 3 _Calendar.thedate
from calendar _Calendar
where _Calendar.isWeekday = 1
and _Calendar.isholiday = 0
and _Calendar.thedate >= #date
order by
_Calendar.thedate
) as _businessDates
For a dynamic version that can go forward or backward a certain number of days try this:
declare #date as datetime
declare #DayOffset as int
set #date = '5/28/13'
set #DayOffset = -3
select
(case when #DayOffset >= 0 then
max(_businessDates.thedate)
else
min(_businessDates.thedate)
end)
from (
select
top (abs(#DayOffset) + (case when #DayOffset >= 0 then 1 else 0 end)) _Calendar.thedate
from calendar _Calendar
where _Calendar.isWeekday = 1
and _Calendar.isholiday = 0
and ( (#DayOffset >= 0 and _Calendar.thedate >= #date)
or (#DayOffset < 0 and _Calendar.thedate < #date) )
order by
cast(_Calendar.thedate as int) * (case when #DayOffset >=0 then 1 else -1 end)
) as _businessDates
You can set #DayOffset to a positive or negative number.
You just need DATEADD, unless I'm not understanding your question.
DATEADD(DAY,3,fromdate)
Edit: I see, not counting weekends or Holidays, will update momentarily.
Update: Well looks like Jason nailed it, but on the off chance you're using SQL2012, here's the simple version:
SELECT todate = thedate
fromdate = LEAD(thedate,3) OVER (ORDER BY thedate)
FROM calendar
WHERE isweekday = 1
AND isHoliday = 0
Try this if you need it as a query with dateAdd:
SELECT
allDates.thedate fromDate
,min(nonWeekendHoliday.thedate) toDate
FROM (
SELECT
thedate
FROM
calendar _calendar
) allDates
LEFT JOIN (
SELECT
thedate
FROM
calendar _calendar
WHERE
_calendar.isweekday = 1
AND
_calendar.isholiday = 0
) nonWeekendHoliday
on dateadd(d,3,allDates.thedate) <= nonWeekendHoliday.thedate
where allDates.thedate between '5/20/13' and '5/31/13'
group by
allDates.thedate

How to fill date gaps in MySQL?

How i can fill date gaps in MySQL? Here is my query:
SELECT DATE(posted_at) AS date,
COUNT(*) AS total,
SUM(attitude = 'positive') AS positive,
SUM(attitude = 'neutral') AS neutral,
SUM(attitude = 'negative') AS negative
FROM `messages`
WHERE (`messages`.brand_id = 1)
AND (`messages`.`spam` = 0
AND `messages`.`duplicate` = 0
AND `messages`.`ignore` = 0)
GROUP BY date ORDER BY date
It returns proper result set - but i want to fill gaps between dates start and end by zeros. How i can do this?
You'll need to create a helper table and fill it with all dates from start to end, then just LEFT JOIN with that table:
SELECT d.dt AS date,
COUNT(*) AS total,
SUM(attitude = 'positive') AS positive,
SUM(attitude = 'neutral') AS neutral,
SUM(attitude = 'negative') AS negative
FROM dates d
LEFT JOIN
messages m
ON m.posted_at >= d.dt
AND m.posted_at < d.dt + INTERVAL 1 DAYS
AND spam = 0
AND duplicate = 0
AND ignore = 0
GROUP BY
d.dt
ORDER BY
d.dt
Basically, what you need here is a dummy rowsource.
MySQL is the only major system which lacks a way to generate it.
PostgreSQL implements a special function generate_series to do that, while Oracle and SQL Server can use recursion (CONNECT BY and recursive CTEs, accordingly).
I don't know whether MySQL will support the following/similar syntax; but if not, then you could just create and drop a temporary table.
--Inputs
declare #FromDate datetime, /*Inclusive*/
#ToDate datetime /*Inclusive*/
set #FromDate = '20091101'
set #ToDate = '20091130'
--Query
declare #Dates table (
DateValue datetime NOT NULL
)
set NOCOUNT ON
while #FromDate <= #ToDate /*Inclusive*/
begin
insert into #Dates(DateValue) values(#FromDate)
set #FromDate = #FromDate + 1
end
set NOCOUNT OFF
select dates.DateValue,
Col1...
from #Dates dates
left outer join SourceTableOrView data on
data.DateValue >= dates.DateValue
and data.DateValue < dates.DateValue + 1 /*NB: Exclusive*/
where ...?