I have a table with 3 columns:
(integer) (integer) (varchar(50))
Month Year Color
1 2019 Blue
1 2019 Yellow
1 2019 Red
2 2019 Blue
2 2019 White
My end goal is to be able to make a query like this:
Select Color from table where (cast(concat(Year,'/',Month,'/1') as date)>='01/Jan/2019' and cast(concat(Year,'/',Month,'/1') as date)<'1/Mar/2019')
What i want is to be able to create a date from the columns i have in order to do a query within a range of dates.
I tried making the date with this query but it gives me this error:
Select cast(concat(Year,'/',Month,'/1') as date) from table
Conversion failed when converting date and/or time from character string.
Solution:
This is the final query that i used to get the dates in a Fiscal Year from Oct-2017 to Sep-2018.
select distinct(DATEFROMPARTS(y,m,1))
from table
where
(DATEFROMPARTS(y, m, 1) >= cast('2017-10-01' as date)) and (DATEFROMPARTS(y, m, 1) < cast('2018-10-01' as date))
order by DATEFROMPARTS(y,m,1)
Edit
Edited to switch cast to datefromparts
select distinct(DATEFROMPARTS(y,m,1))
from table
where
(DATEFROMPARTS(y, m, 1) >= DATEFROMPARTS(2017, 10, 1)) and (DATEFROMPARTS(y,m, 1) < DATEFROMPARTS(2018, 10, 1))
order by DATEFROMPARTS(y,m,1)
You can use datefromparts():
select color
from table
where
datefromparts(year, month, 1) >= cast('20190101' as date)
and datefromparts(year, month, 1) < cast('20190301' as date)
Or:
where
datefromparts(year, month, 1) >= datefromparts(2019, 1, 1)
and datefromparts(year, month, 1) < datefromparts(2019, 3, 1)
Since you are forcing the date to the first date of the month, you could also use between like so:
select color
from table
where datefromparts(year, month, 1)
between cast('20190101' as date) and cast('20190201' as date)
Or:
where datefromparts(year, month, 1)
between datefromparts(2019, 1, 1) and datefromparts(2019, 2, 1)
Note that for this date range, you could as well do simple number comparison:
where year = 2019 and month in (1, 2)
However if your date range spans over multiple years, this will get tedious and require a more complex expression.
Related
I am writing a SQL query to find business working dates of last year equivalent to today's date.
In this query it should fetch :-
For e.g. if today is 5th January, 2021 and it is the second day of second week of the year. So I need to find the exact equivalent date of the second day of second week of the previous year. So it would be 7th January, 2020.
And with this, I need the business working dates of that week of 7th January 2020 (i.e. excluding Saturday & Sunday)
Which will come up as 2020-Jan-06 to 2020-Jan-10 according to the example.
So I will need the report between 6th Jan - 10th Jan, 2020.
I am trying to use this code to find date of last year equivalent to today's date (5th Jan, 2021 viz. second day of second week)
select Convert(date, (DATEADD(year, -1, getdate()+2))) ;
2021-01-05 is the 2nd day of the first week of 2021 according to ISO standards.
If you want the 2nd day of the first week of 2021, then it is either today's date minus 52 weeks or 53 weeks. Based on the Wikipedia page for ISO dates:
[53 week years are those] years in which 1 January or 31 December are Thursdays
So, we want that for the previous year. Hence, I think the following should work:
select dateadd(week,
(case when 'Thursday' in (datename(weekday, datefromparts(year(getdate()) - 1, 1, 1)),
datename(weekday, datefromparts(year(getdate()) - 1, 12, 31))
)
then -53 else -52
end),
convert(date, getdate())
)
Note that this returns 2019-12-31, which is the correct value based on ISO standards.
I have use multiple CTE to show you the step by step calculation. It should be pretty easy to follow.
Basically it find the week_no and day_no_of_week for 2021-01-05 and then use that to find the same date for 2020
declare #input_date date = '2021-01-05',
#year_offset int = -1; -- previous year
with
cte1 as
(
select input_date = #input_date,
week_no = DATEPART(WEEK, #input_date),
first_day_of_week = DATEADD(WEEK, DATEDIFF(WEEK, 0, #input_date), 0)
),
cte2 as
(
select *,
day_no_of_week = DATEDIFF(DAY, first_day_of_week, #input_date) + 1
from cte1
),
cte3 as
(
select *,
first_day_of_the_prev_year = DATEADD(YEAR, DATEDIFF(YEAR, 0, #input_date) + #year_offset, 0)
from cte2
),
cte4 as
(
select *,
first_day_of_week_prev_year = DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEADD(WEEK, week_no - 1, first_day_of_the_prev_year)), 0)
from cte3
)
select *,
DATEADD(DAY, day_no_of_week - 1, first_day_of_week_prev_year) as the_required_date
from cte4
I am trying to update certain fields for employees whose date of joining falls in between 10 Jun and 31 Dec, irrespective of the year. I am trying using 'Between' Operator but it requires year to be included in the dates. Is there a way to generalise it in order to consider Day and Month excluding the Year?
Use the DatePart function - replace thedate with your column, and thetable with the column.
Something like this:
select datepart(MONTH, thedate), datepart(DAY, thedate),*
from thetable
where datepart(MONTH, thedate) between 6 and 12
and datepart(DAY, thedate) between 10 and 31
You may try this:
WITH Emp AS (
SELECT *, DATEPART(MONTH, JoinDate) AS MonthJoin, DATEPART(DAY, JoinDate) AS DayJoin
FROM Employees)
SELECT *
FROM Emp
WHERE (MonthJoin > 1 AND MonthJoin < 12)
OR (MonthJoin = 1 AND DayJoin >= 10)
OR (MonthJoin = 12 AND DayJoin <= 31)
Where Employees is your table and JoinDate is your date of joining in this table
Could you please help in finding the closest February 1st to current date?
The following script works correctly only if it is ran in current year:
select DATEADD(MONTH,1,DATEADD(year, DATEDIFF(year, -1, GETDATE()), 0))
But when it would be ran in January next year it will produce incorrect result.
Thank you in advance!
Your question can be interpreted two different ways: the first being to find the next closest Feb 1 (i.e. Feb 2 2016 will return Feb 1 2017), and the second being to find the closest Feb 1 to the current date (i.e. Feb 2 2016 will return Feb 1 2016).
Prdp has already supplied an answer for the former, so this approach (which I'm sure can be simplified) will be for the latter.
This will consider the current year's Feb 1 and the next year's Feb 1, and compute the DateDiff() in days from both, and select the closest one.
;With Dates As
(
Select ThisFeb = DateFromParts(Year(GetDate()), 2, 1),
NextFeb = DateFromParts(Year(GetDate()) + 1, 2, 1)
), Distance (Date, Distance) As
(
Select ThisFeb, Abs(DateDiff(Day, GetDate(), ThisFeb)) As ThisFebDiff
From Dates
Union All
Select NextFeb, Abs(DateDiff(Day, GetDate(), NextFeb)) As NextFebDiff
From Dates
)
Select Top 1 Date
From Distance
Order By Distance Asc
Try something like this using IIF and DATEFROMPARTS
select IIF(month(getdate()) > 2,
DATEFROMPARTS(YEAR(Getdate()),2,1),DATEFROMPARTS(YEAR(Getdate())-1,2,1) )
If you are using older versions then
select Case When month(getdate()) > 2
then CAST(CAST(YEAR(getdate()) as char(4))+'-02-01' as date)
else CAST(CAST(YEAR(getdate()) - 1 as char(4))+'-02-01' as date)
end
Try This:
SELECT
CASE WHEN
DATEDIFF(dd,CAST(CONCAT(year(GETDATE()),'-02-01') AS DATE),GETDATE()) < 183
THEN CAST(CONCAT(year(GETDATE()),'-02-01') AS DATE)
ELSE CAST(CONCAT(year(GETDATE())+1,'-02-01') AS DATE) END as ClosestFebFirst
This is another possible solution...
DECLARE #SomeDate DATE = '2017-06-30';
SELECT TOP 1
ClosestFebFirst = CASE WHEN dd.Diff1 < dd.Diff2 THEN pd.D1 ELSE pd.D2 END
FROM
( VALUES (
DATEFROMPARTS(YEAR(#SomeDate), 2, 1),
DATEFROMPARTS(YEAR(#SomeDate) + 1, 2, 1)
)
) pd (D1, D2)
CROSS APPLY ( VALUES (
ABS(DATEDIFF(dd, #SomeDate, pd.D1)),
ABS(DATEDIFF(dd, #SomeDate, pd.D2))
)
) dd (Diff1, Diff2);
This gives me the year and quarter from any date:
CONCAT(STRING(YEAR(mydate)),'-Q',STRING(QUARTER(mydate))) as quarter
Result: 2016-Q2, 2016-Q3, 2016-Q4, 2017-Q1, etc
What should I write to get the half year? (2017-S1, 2017-S2, etc)
S1 (Semester 1) is between Jan 1st-Jun 30th;
S2 (Semester 2) is between Jul 1st-Dec 31st.
Had no problem making dates into quarters and then connecting other tables data to the right quarter, but don't know how to do half years (i know the direct formula does not exist in sql). Thanks!
Try below (it is in Legacy SQL as I see you still using it)
#legacySQL
SELECT
CONCAT(STRING(YEAR(mydate)),'-Q',STRING(QUARTER(mydate))) as quarter,
CONCAT(STRING(YEAR(mydate)),'-S',STRING(IF(QUARTER(mydate) < 3, 1, 2))) as semester
FROM
(SELECT CURRENT_DATE() AS mydate),
(SELECT '2016-02-02' AS mydate),
(SELECT '2016-09-02' AS mydate)
In case if you will be migrating to Standard SQL (which is highly recommended) - check respective version
#standardSQL
WITH yourTable AS (
SELECT CURRENT_DATE() AS mydate UNION ALL
SELECT '2016-02-02' UNION ALL
SELECT '2016-09-02'
)
SELECT
mydate,
CONCAT(FORMAT_DATE("%Y", mydate), '-Q', CAST(EXTRACT(QUARTER FROM mydate) AS STRING)) AS quarter,
CONCAT(FORMAT_DATE("%Y", mydate), IF(EXTRACT(QUARTER FROM mydate) < 3, '-S1', '-S2')) AS semester
FROM yourTable
Given a From Date, To Date and a Fiscal Year system, I want to get all the split-up duration within the
given From & To Date based on the Fiscal Year system. Explained below with examples:
Example 1:
Fiscal Year system: Apr to Mar
From Date: Jan-05-2008
To Date: May-15-2008
Based on Fiscal Year system, duration should be splitted into:
Jan-05-2008 to Mar-31-2008
Apr-01-2008 to May-15-2008
Example 2:
Fiscal Year system: Apr to Mar
From Date: Jan-17-2008
To Date: May-20-2009
Based on Fiscal Year system, duration should be splitted into:
Jan-17-2008 to Mar-31-2008
Apr-01-2008 to Mar-31-2009
Apr-01-2009 to May-20-2009
Am looking for approach/algorithm to solve this in PostgreSQL 8.2.
Regards,
Gnanam
I actually favor Andomar's solution (with the addition of a processes that automatically fills the Periods table), but for fun here's a solution that doesn't require it.
CREATE TABLE your_table (start_date date, end_date date);
INSERT INTO your_table VALUES ('Jan-17-2008', 'May-20-2009');
SELECT
GREATEST(start_date, ('04-01-'||series.year)::date) AS year_start,
LEAST(end_date, ('03-31-'||series.year + 1)::date) AS year_end
FROM
(SELECT
start_date,
end_date,
generate_series(
date_part('year', your_table.start_date - INTERVAL '3 months')::int,
date_part('year', your_table.end_date - INTERVAL '3 months')::int)
FROM your_table) AS series(start_date, end_date, year)
ORDER BY
start_date;
You could create a table containing the start and end of all fiscal years, f.e.
Periods (PeriodStartDt, PeriodEndDt)
Then you can join the tables together if they at least partly overlap. Use a case statement to select the end of the period or the end of the row, depending on which is later. For example (not tested):
select case when yt.StartDt < p.PeriodStartDt then p.PeriodStartDt
else yt.StartDt
end as SplitStart
, case when yt.EndDt > p.PeriodEndDt then p.PeriodEndDt
else yt.EndDt
end as SplitEnd
, yt.*
from YourTable yt
inner join Periods p
on yt.StartDt < p.PeriodEndDate
and yt.EndDt >= p.PeriodStartDate
CREATE TABLE your_table (start_date date, end_date date);
INSERT INTO your_table VALUES (CONVERT (date, GETDATE()),CONVERT (date, DATEADD(year, -1, GETDATE())) );
WITH mycte AS
(
SELECT 1 as id
UNION ALL
SELECT id + 1
FROM mycte
WHERE id + 1 < = 12
),
cte_distribution as
(
SELECT *,
DATEPART (month,DATEADD(month, mycte.id - 1, your_table.start_date)) as month_number ,
DATEPART (YEAR,DATEADD(month, mycte.id - 1, your_table.start_date)) as cal_year,
12000/12 as cash
FROM your_table
CROSS JOIN mycte
)
select
*,
(CASE WHEN month_number between 1 and 3 THEN '1st quarter' WHEN month_number between 4 and 6 THEN '2nd quarter' WHEN month_number between 7 and 9 THEN '3rd quarter' WHEN month_number between 9 and 12 THEN '4th quarter' END) as Quarter,
CASE WHEN month_number between 1 and 6 THEN CAST(CAST((cal_year - 1) as CHAR(4)) + '-' + CAST(cal_year as CHAR(4)) AS CHAR(9)) WHEN month_number between 6 and 12 THEN CAST(CAST((cal_year) as CHAR(4)) + '-' + CAST((cal_year + 1) as CHAR(4)) AS CHAR(9)) ELSE NULL END as fin_year
from cte_distribution;