I got this data from my table:
id arrival_date departure_date
1 2017-10-10 2017-10-15
2 2017-11-16 2017-11-30
3 2017-10-14 2017-10-31
4 2018-05-12 2017-05-22
5 2021-01-16 2021-03-15
6 2018-06-02 2017-07-02
All i want is to explode these date but i only want to show the year only
date
2017
2018
2019
2020
2021
these should be the once that I wanted to see is their any query for these?
Note: if this year is 2018 it should start in 2018, so i will use getdate() in that instance, i want to get the max in departure_date part, can I do that?
You can try a recursive cte
DECLARE #maxYear INT
SELECT #maxYear = MAX(YEAR(departure_date)) FROM YourTable
;WITH cte
AS
(
SELECT YEAR(GETDATE()) AS [Year]
UNION ALL
SELECT [Year] + 1
FROM cte
WHERE [Year] < #maxYear
)
SELECT *
FROM cte
DEMO
Just use YEAR(arrival_date) and YEAR(departure_date)
Related
I have reviewed many posts about how to find gaps in dates and believe that I am close to figuring it out but need just a little extra help. Per my query I am pulling distinct days with a record count for each distinct day. I have added a "Gap_Days" column which should return a zero if no gap from previous date OR the number of days since the previous date. As you can see all of my Gap_Days are zero when in fact I am missing 10/24 and 10/25. Therefore on 10/26 there should be a gap of 2 since the previous date is 10/23.
Thanks in advance for pointing out what I am probably looking right at.
SELECT DISTINCT Run_Date, COUNT(Run_Date) AS Daily_Count,
Gap_Days = Coalesce(DateDiff(Day,Lag(Run_Date) Over (partition by Run_Date order by Run_Date DESC), Run_Date)-1,0)
FROM tblUnitsOfWork
WHERE (Run_Date >= '2022-10-01')
GROUP BY Run_Date
ORDER BY Run_Date DESC;
Run_Date Daily_Count Gap_Days
2022-10-29 00:00:00.000 8431 0
2022-10-28 00:00:00.000 8204 0
2022-10-27 00:00:00.000 8705 0
2022-10-26 00:00:00.000 7885 0
2022-10-23 00:00:00.000 7485 0
2022-10-22 00:00:00.000 8699 0
2022-10-21 00:00:00.000 9212 0
2022-10-20 00:00:00.000 9220 0
First let's set up some demo data:
DECLARE #table TABLE (ID INT IDENTITY, date DATE)
DECLARE #dt DATE
WHILE (SELECT COUNT(*) FROM #table) < 30
BEGIN
SET #dt = DATEADD(DAY,(ROUND(((50 - 1 -1) * RAND() + 1), 0) - 1)-25,CURRENT_TIMESTAMP)
IF NOT EXISTS (SELECT 1 FROM #table WHERE date = #dt) INSERT INTO #table (date) SELECT #dt
END
ID date
--------
1 2022-11-10
2 2022-11-15
3 2022-10-20
...
28 2022-10-14
29 2022-11-13
30 2022-11-21
This gives us a table variable with 30 random dates in a 50 day window. Now let's look for missing dates:
SELECT *, CASE WHEN ROW_NUMBER() OVER (ORDER BY date) > 1 AND LAG(date,1) OVER (ORDER BY date) <> DATEADD(DAY,-1,date) THEN 'GAP! ' + CAST(DATEDIFF(DAY,LAG(date,1) OVER (ORDER BY date),date)-1 AS NVARCHAR) + ' DAYS MISSING!' END
FROM #table
ORDER BY date
All we're doing here is ignoring the first date (since it's expected there wouldn't be one before then) and from then on comparing the last date (using lag ordered by date) to the current date. If it is not a day before the case statement will produce a message with how many days were missing.
ID date MissingDatesFlag
----------------------------
1 2022-10-08 NULL
4 2022-10-09 NULL
25 2022-10-10 NULL
28 2022-10-11 NULL
22 2022-10-15 GAP! 4 DAYS MISSING!
2 2022-10-18 GAP! 3 DAYS MISSING!
12 2022-10-19 NULL
24 2022-10-20 NULL
....
15 2022-11-18 GAP! 3 DAYS MISSING!
29 2022-11-21 GAP! 3 DAYS MISSING!
20 2022-11-22 NULL
Since the demo data is randomly selected your results may vary, but they should be similar.
My table structure in SQL Server looks as below.
id startdate enddate value
---------------------------------------
1 2019-02-06 2019-02-07 11
1 2019-01-22 2019-02-05 10
1 2019-01-15 2019-01-21 14
1 2018-12-13 2018-01-14 15
1 2018-12-09 2018-12-12 14
1 2018-08-13 2018-12-08 17
1 2018-07-19 2018-08-12 19
1 2018-06-13 2018-07-18 20
Now my query needs to display value from highest start date for that month. Which is fine and I know what needs to be done but Not start just highest date value for that month, if no value is there for that start date, we carry forward value from last month. So basically if you notice on above data, after December 2018 values, there are no values for November, October, September etc but I want to return MM/YYYY values for that month in result but value for those months should be what we found on earlier month which is August values which in this example is 17. Please note that enddate will always be as of one day before new start date begins. Probably that can be used for back filling and carry forwarding missing month values?
So my result should look like below.
id date value
----------------------------
1 2019-02 11
1 2019-01 10
1 2018-12 15
1 2018-11 17
1 2018-10 17
1 2018-09 17
1 2018-08 17
1 2018-07 19
1 2018-06 20
Do you think this can be done without using cursor here?
Alexander Volok's answer is solid, so I won't go into too much extra code. But I thought I'd explain the reasoning. In essence, what you need to do is create a skeleton date table containing all the dates and primary keys you want returned. I'm guessing you have more than one id value in your real data, so probably something like this (whether you choose to persist it or not is up to you)
create table #skelly
(
id int,
_year int,
_month int
primary key (id, _year, _month)
)
You can get much more precise if you need to be, by only including dates which fall between the min and max StartDate per id, but that's an exercise I leave up to you.
From there, it's then just a matter of filling in the values you care about against that skeleton table. You can do this in a number of ways; by joining, cross applying or a correlated subquery (as Alexander Volok used).
DECLARE #start DATE, #end DATE;
SELECT #start = '20180601', #end = GETDATE();
;WITH Months AS
(
SELECT EOMONTH(DATEADD(month, n-1, #start)) AS DateValue FROM (
SELECT TOP (DATEDIFF(MONTH, #start, #end) + 1)
n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_objects
) D
)
, InputData AS
(
SELECT 1 AS id, '2019-02-06' startdate, '2019-02-07' as enddate, 11 AS [value] UNION ALL
SELECT 1, '2019-01-22', '2019-01-25', 10 UNION ALL
SELECT 1, '2019-01-15', '2019-01-17', 14 UNION ALL
SELECT 1, '2018-12-13', '2018-12-19', 15 UNION ALL
SELECT 1, '2018-12-09', '2018-12-10', 14 UNION ALL
SELECT 1, '2018-08-13', '2018-12-08', 17 UNION ALL
SELECT 1, '2018-07-19', '2018-07-25', 19 UNION ALL
SELECT 1, '2018-06-13', '2018-07-18', 20
)
SELECT FORMAT(m.DateValue, 'yyyy-MM') AS [Month]
, (SELECT TOP 1 I.value FROM InputData I WHERE I.startdate < M.DateValue ORDER BY I.startdate DESC ) [Value]
FROM months m
ORDER BY M.DateValue DESC
Results to:
Month Value
2019-02 11
2019-01 10
2018-12 15
2018-11 17
2018-10 17
2018-09 17
2018-08 17
2018-07 19
2018-06 20
Name Start_date end_date
aaa 01/02/2017 05/03/2017
bbb 03/05/2017 07/07/2017
ccc 02/01/2017 10/09/2017
I want to write a query that calculates the number of people who exist in the DB in a certain month/year.
Answer:
Jan 2017 1
Feb 2017 2
Mar 2017 3
Apr 2017 3
May 2017 2 (one person - aaa ,ended in May 2017)
Jun 2017 2
Jul 2017 1 (bbb ended in July 2017)
How do I write a PSQL query to get the desired output?
Thanks.
First, get the max and min dates in order to declare the dates range.
Second, with etc select all the month in the range.
Third, sum the number of the records in each dates.
Like:
declare #date date
declare #toDate date
select #date = min(Start_date),
#toDate = max(end_date)
from table_name
;With dt As
(
Select #date As [TheDate]
Union All
Select DateAdd(month, 1, TheDate) From dt Where [TheDate] < #toDate
)
select month(dt.TheDate),
year(dt.TheDate),
sum(case when table_name.Name is not null then 1 else 0 end)
from dt
left join table_name
on table_name.Start_date >= dt.TheDate
and table_name.end_date < dateadd(day,-1,dateAdd(month,1,dt.TheDate))
I have this query that gives me a given date for each of the past 15 years. When my starting date is February 29 it does not return the 29 for year 2012, 2008 and 2004. How can I have this query to return the 29 for those years?
DECLARE #TempDate1 TABLE (Entry_Date Date)
INSERT INTO #TempDate1 values ('2016-02-29')
;WITH
a AS(SELECT DATEADD(yy,-1,Entry_Date) d, DATEADD(yy,-1,Entry_Date) d2,0 i
FROM #TempDate1
UNION all
SELECT DATEADD(yy,-1,d),DATEADD(yy,-1,d2),i+1 FROM a WHERE i<14),
b AS(SELECT d,d2, DATEDIFF(dd,0,d)%7 dd,i FROM a)
SELECT
d AS Entry_Date
FROM b
It returns this:
Entry_Date
2015-02-28
2014-02-28
2013-02-28
2012-02-28
2011-02-28
2010-02-28
2009-02-28
2008-02-28
2007-02-28
2006-02-28
2005-02-28
2004-02-28
2003-02-28
2002-02-28
2001-02-28
While I would like to have this:
Entry_Date
2015-02-28
2014-02-28
2013-02-28
2012-02-29
2011-02-28
2010-02-28
2009-02-28
2008-02-29
2007-02-28
2006-02-28
2005-02-28
2004-02-29
2003-02-28
2002-02-28
2001-02-28
Perhaps DateAdd in concert with an ad-hoc tally table
Example
Declare #YourTable Table ([Entry_Date] date)
Insert Into #YourTable Values
('2016-02-29')
,('2015-07-22')
Select YearNr = N
,Anniv = dateadd(YEAR,N*-1,Entry_Date)
From #YourTable A
Cross Apply (
Select Top 15 N=Row_Number() Over (Order By (Select NULL)) From master..spt_values n1
) B
Returns
Simply by using EOMONTH function (SQL Server 2012 and above):
DECLARE #TempDate1 TABLE (Entry_Date Date)
INSERT INTO #TempDate1 values ('2016-02-29')
;WITH
a AS(SELECT DATEADD(yy,-1,Entry_Date) d, DATEADD(yy,-1,Entry_Date) d2,0 i
FROM #TempDate1
UNION all
SELECT DATEADD(yy,-1,d),DATEADD(yy,-1,d2),i+1 FROM a WHERE i<14),
b AS(SELECT d,d2, DATEDIFF(dd,0,d)%7 dd,i FROM a)
SELECT EOMONTH(d) AS Entry_Date
FROM b;
Rextester Demo
Rewrite tour query like this... Not only will handle leap years without jumping through hoops, it's orders of magnitude more efficient than what you currently have.
DECLARE #BaseDate DATE = '2016-02-29';
SELECT
Entry_Date = DATEADD(YEAR, t.n, #BaseDate)
FROM
(VALUES (-1),(-2),(-3),(-4),(-5),
(-6),(-7),(-8),(-9),(-10),
(-11),(-12),(-13),(-14),(-15) ) t (n);
Results...
Entry_Date
----------
2015-02-28
2014-02-28
2013-02-28
2012-02-29
2011-02-28
2010-02-28
2009-02-28
2008-02-29
2007-02-28
2006-02-28
2005-02-28
2004-02-29
2003-02-28
2002-02-28
2001-02-28
EDIT: Same functionality when used with a table of dates (I stole John's table)
DECLARE #YourTable TABLE (id INT, Entry_Date DATE);
INSERT INTO #YourTable VALUES (1, '2016-02-29'), (2, '2015-07-22');
SELECT
yt.id,
Entry_Date = DATEADD(YEAR, t.n, yt.Entry_Date)
FROM
#YourTable yt
CROSS APPLY (VALUES (-1),(-2),(-3),(-4),(-5),
(-6),(-7),(-8),(-9),(-10),
(-11),(-12),(-13),(-14),(-15) ) t (n);
GO
Results...
id Entry_Date
----------- ----------
1 2015-02-28
1 2014-02-28
1 2013-02-28
1 2012-02-29
1 2011-02-28
1 2010-02-28
1 2009-02-28
1 2008-02-29
1 2007-02-28
1 2006-02-28
1 2005-02-28
1 2004-02-29
1 2003-02-28
1 2002-02-28
1 2001-02-28
2 2014-07-22
2 2013-07-22
2 2012-07-22
2 2011-07-22
2 2010-07-22
2 2009-07-22
2 2008-07-22
2 2007-07-22
2 2006-07-22
2 2005-07-22
2 2004-07-22
2 2003-07-22
2 2002-07-22
2 2001-07-22
2 2000-07-22
I have a list of dates in a YYYYMM format and I am trying to rank them in a Year over Year format that would look like the following:
MonthDisplay YearMonth Rank MonthNumber YearNumber
Aug-2013 201308 1 8 2013
Aug-2012 201208 2 8 2012
Jul-2013 201307 3 7 2013
Jul-2012 201207 4 7 2012
I have been able to get it close by using the following Rank and get the results below:
RANK() OVER(PARTITION BY 1 ORDER BY MonthNumber DESC, YearNumber DESC)
Month YearMonth Rank
Dec-2012 201212 1
Dec-2011 201112 2
Nov-2012 201211 114
Nov-2011 201111 115
Oct-2012 201210 227
Oct-2011 201110 228
However, this starts with Dec-2012 instead of the Aug-2013 (current month). I can't figure out how to get it to start with the current month. I am sure it something super easy and I am just missing it. Thanks!
select
T.YearMonth,
rank() over (order by R.rnk asc, D.YearNumber desc) as [Rank],
D.MonthNumber, D.YearNumber
from Table1 as T
outer apply (
select
month(getdate()) as CurMonthNumber,
cast(right(T.YearMonth, 2) as int) as MonthNumber,
cast(left(T.YearMonth, 4) as int) as YearNumber
) as D
outer apply (
select
case
when D.MonthNumber <= D.CurMonthNumber then
D.CurMonthNumber - D.MonthNumber
else
12 + D.CurMonthNumber - D.MonthNumber
end as rnk
) as R
sql fiddle example