This is MyTable structure
MyTable : ID, Date
Select ID, Date from MyTable
ID Date
50 2013-01-01 00:00:00.000
51 2013-01-02 00:00:00.000
52 2013-01-02 00:00:00.000
I need to get the result like this.
ID Date
50 2013-01-01 00:00:00.000
50 2013-01-02 00:00:00.000
50 2013-01-03 00:00:00.000
51 2013-01-02 00:00:00.000
51 2013-01-03 00:00:00.000
52 2013-01-03 00:00:00.000
How do i get the results ?
Seems like you want to get a list of dates. Of so, then you can use a recursive CTE to get the list of dates:
;with data(id, date) as
(
select id, date
from mytable
union all
select id, dateadd(day, 1, date)
from data
where dateadd(day, 1, date) <= '1/3/2013'
)
select *
from data
order by id
See SQL Fiddle with Demo. This will generate the list of dates for each ID between the current date in your table and the end date that you provide. In my example it is 1/3/2013
I think this will work a bit faster ONLY if there is a CLUSTERED INDEX on the ID column, else bluefeet's solution is fantastic!
SELECT T1.ID
,Date = DATEADD(DAY, -ROW_NUMBER() OVER (PARTITION BY T1.ID ORDER BY (SELECT NULL))+1, '2013-01-03')
FROM MyTable T1
JOIN MyTable T2 ON T1.ID <= T2.ID
Related
I have a table like below
AID BID CDate
-----------------------------------------------------
1 2 2018-11-01 00:00:00.000
8 1 2018-11-08 00:00:00.000
1 3 2018-11-09 00:00:00.000
7 1 2018-11-15 00:00:00.000
6 1 2018-12-24 00:00:00.000
2 5 2018-11-02 00:00:00.000
2 7 2018-12-15 00:00:00.000
And I am trying to get a result set as follows
ID MaxDate
-------------------
1 2018-12-24 00:00:00.000
2 2018-12-15 00:00:00.000
Each value in the id columns(AID,BID) should return the max of CDate .
ex: in the case of 1, its max CDate is 2018-12-24 00:00:00.000 (here 1 appears under BID)
in the case of 2 , max date is 2018-12-15 00:00:00.000 . (here 2 is under AID)
I tried the following.
1.
select
g.AID,g.BID,
max(g.CDate) as 'LastDate'
from dbo.TT g
inner join
(select AID,BID,max(CDate) as maxdate
from dbo.TT
group by AID,BID)a
on (a.AID=g.AID or a.BID=g.BID)
and a.maxdate=g.CDate
group by g.AID,g.BID
and 2.
SELECT
AID,
CDate
FROM (
SELECT
*,
max_date = MAX(CDate) OVER (PARTITION BY [AID])
FROM dbo.TT
) AS s
WHERE CDate= max_date
Please suggest a 3rd solution.
You can assemble the data in a table expression first, and the compute the max for each value is simple. For example:
select
id, max(cdate)
from (
select aid as id, cdate from t
union all
select bid, cdate from t
) x
group by id
You seem to only care about values that are in both columns. If this interpretation is correct, then:
select id, max(cdate)
from ((select aid as id, cdate, 1 as is_a, 0 as is_b
from t
) union all
(select bid as id, cdate, 1 as is_a, 0 as is_b
from t
)
) ab
group by id
having max(is_a) = 1 and max(is_b) = 1;
Attached the image how the data looks like. In my table I have 3 columns id, start date, and end date, and values like this:
id start date end date
-------------------------------
100 2015-01-01 2015-12-31
100 2016-01-10 2018-12-31
200 2015-02-15 2016-03-15
200 2016-03-15 2016-12-31
300 2016-01-01 2016-12-31
400 2017-01-01 2017-12-31
500 2017-02-01 2017-12-31
600 2017-01-15 2017-03-05
600 2017-02-01 2018-12-31
I want my output to be
id start date end date
--------------------------------
100 2015-01-01 2015-12-31
100 2016-01-10 2018-12-31
200 2015-02-15 2016-12-31
300 2016-01-01 2016-12-31
400 2017-01-01 2017-12-31
500 2017-02-01 2017-12-31
600 2017-01-15 2018-12-31
Query:
select
id, *
from
dbo.test_sl
where
id in (select id
from dbo.test_sl
where end_date >= start_date
group by id)
Please help me get the output I am looking for.
This is an example of a gaps-and-islands problem. In this case, you want to find adjacent rows that do not overlap for the same id. These are the starts of groups. A cumulative sum of the starts of a group providing a grouping number, which can be used for aggregation.
In a query, this looks like:
select id, min(startdate), max(enddate)
from (select t.*,
sum(isstart) over (partition by id order by startdate) as grp
from (select t.*,
(case when exists (select 1
from test_sl t2
where t2.id = t.id and
t2.startdate < t.startdate and
t2.enddate >= t.startdate
)
then 0 else 1
end) as isstart
from test_sl t
) t
) t
group by id, grp;
Assuming that only two records can be combined together, you can LEFT JOIN the table with itself and then use a CASE to display the end date of the self-joined record, if available.
SELECT
t1.id,
min(t1.start_date),
CASE WHEN t2.end_date IS NULL THEN t1.end_date ELSE t2.end_date END
FROM
table t1
LEFT JOIN table t2
ON t1.id = t2.id
AND t2.start_date > t1.start_date
AND t2.start_date <= t1.end_date
GROUP BY
t1.id,
CASE WHEN t2.end_date IS NULL THEN t1.end_date ELSE t2.end_date END
ORDER BY 1
Tested in this SQL Fiddle
Here's a solution that uses a Recursive CTE.
It basically loops through the dates per id, and keeps the smallest start_date for the overlapping end_date/start_date.
Then the result is grouped so there are no more overlaps.
Test here on rextester.
WITH SRC AS
(
SELECT id, start_date, end_date,
row_number() over (partition by id order by start_date) as rn
FROM test_sl
)
, RCTE AS
(
SELECT id, rn, start_date, end_date
FROM SRC
WHERE rn = 1
UNION ALL
SELECT t.id, t.rn, iif(r.end_date >= t.start_date, r.start_date, t.start_date), t.end_date
FROM RCTE r
JOIN SRC t ON t.id = r.id AND t.rn = r.rn + 1
)
SELECT id, start_date, max(end_date) as end_date
FROM RCTE
GROUP BY id, start_date
ORDER BY id, start_date;
I have a table in Db2 called myTable.
It has several columns:
a | b | date1 | date2
---------------------------------------------
1 abc <null> 2014-09-02
2 aax 2015-12-30 2016-09-02
2 bax 2015-10-20 <null>
2 ayx 2014-12-10 2016-02-12
As seen from values above, date1 and date2 can have null values as well.
How can I get the max of both date1 and date2 together ?
i.e. the output of the query should be 2016-09-02 as that is the max date of all the dates present in date1 and date2.
I am using Db2-9.
Thanks for reading!
How about using a UNION query:
SELECT MAX(t.newDate)
FROM
(
SELECT date1 AS newDate
FROM myTable
UNION
SELECT date2 AS newDate
FROM myTable
) t
Another option:
SELECT CASE WHEN t.date1 > t.date2 THEN t.date1 ELSE t.date2 END
FROM
(
SELECT (SELECT MAX(date1) FROM myTable) AS date1,
(SELECT MAX(date2) FROM myTable) AS date2
FROM SYSIBM.SYSDUMMY1
) t
MAX() is an interesting beast...
It's available as both a scalar function and an aggregate one.
So all you really need is
select max(max(coalesce(date1,'0001-01-01')
,coalesce(date2,'0001-01-01')
)
)
from mytable
The outer MAX() is the aggregate version, the inner is the scalar one.
I have a SQL statement.
SELECT ID, LOCATION, CODE,MAX(DATE) FROM TABLE1 WHERE
DATE <= CONVERT(DATETIME,'11-11-2012') AND
EXISTS(SELECT * FROM #TEMP_CODE WHERE TABLE1.CODE =#TEMP_CODE.CODE)
AND ID IN (14,279)
GROUP BY ID, LOCATION, CODE,(DATE)
I need rows with the nearest date to the 11-11-2012, but the table returns all the values. What am I doing wrong. Thanks
ID LOCATION CODE DATE
-------------------------------------------------------------------
14 CAR STREET,UDUPI 234 2012-08-08 00:00:00.000
14 CAR STREET,UDUPI 234 2012-08-10 00:00:00.000
14 CAR STREET,UDUPI 234 2012-08-14 00:00:00.000
279 MADHUGIRI 234 2012-08-08 00:00:00.000
279 MADHUGIRI 234 2012-08-11 00:00:00.000
I need to select the row with the max date. The required result is
ID LOCATION CODE DATE
-------------------------------------------------------------------
14 CAR STREET,UDUPI 234 2012-08-10 00:00:00.000
279 MADHUGIRI 234 2012-08-11 00:00:00.000
Remove (DATE) from the GROUP BY Clause.
Change
SELECT ID, LOCATION, CODE,MAX(DATE) FROM TABLE1 WHERE
DATE <= CONVERT(DATETIME,'11-11-2012') AND
EXISTS(SELECT * FROM #TEMP_CODE WHERETABLE1.CODE =#TEMP_CODE.CODE)
AND ID IN ('KBL01005','KBL05020')
GROUP BY ID, LOCATION, CODE,(DATE)
to
SELECT ID, LOCATION, CODE,MAX(DATE) FROM TABLE1 WHERE
DATE <= CONVERT(DATETIME,'11-11-2012') AND
EXISTS(SELECT * FROM #TEMP_CODE WHERETABLE1.CODE =#TEMP_CODE.CODE)
AND ID IN ('KBL01005','KBL05020')
GROUP BY ID, LOCATION, CODE
Try using unambigious date format
SELECT ID, LOCATION, CODE,MAX(DATE) FROM TABLE1
WHERE DATE <= '20121111' AND
EXISTS(SELECT * FROM #TEMP_CODE WHERETABLE1.CODE =#TEMP_CODE.CODE)
AND ID IN ('KBL01005','KBL05020')
GROUP BY ID, LOCATION, CODE
Also see why you need to use unambigious date formats http://beyondrelational.com/modules/2/blogs/70/posts/10898/understanding-datetime-column-part-ii.aspx
No need to use Group by (Date). Try this:
SELECT ID, LOCATION, CODE,MAX(DATE) FROM TABLE1
WHERE DATE <= CONVERT(DATETIME,'11-11-2012') AND
EXISTS(SELECT * FROM #TEMP_CODE WHERE TABLE1.CODE =#TEMP_CODE.CODE)
AND ID IN (14,279)
GROUP BY ID, LOCATION, CODE
I have a table with many IDs and many dates associated with each ID, and even a few IDs with no date. For each ID and date combination, I want to select the ID, date, and the next largest date also associated with that same ID, or null as next date if none exists.
Sample Table:
ID Date
1 5/1/10
1 6/1/10
1 7/1/10
2 6/15/10
3 8/15/10
3 8/15/10
4 4/1/10
4 4/15/10
4
Desired Output:
ID Date Next_Date
1 5/1/10 6/1/10
1 6/1/10 7/1/10
1 7/1/10
2 6/15/10
3 8/15/10
3 8/15/10
4 4/1/10 4/15/10
4 4/15/10
SELECT
mytable.id,
mytable.date,
(
SELECT
MIN(mytablemin.date)
FROM mytable AS mytablemin
WHERE mytablemin.date > mytable.date
AND mytable.id = mytablemin.id
) AS NextDate
FROM mytable
This has been tested on SQL Server 2008 R2 (but it should work on other DBMSs) and produces the following output:
id date NextDate
----------- ----------------------- -----------------------
1 2010-05-01 00:00:00.000 2010-06-01 00:00:00.000
1 2010-06-01 00:00:00.000 2010-06-15 00:00:00.000
1 2010-07-01 00:00:00.000 2010-08-15 00:00:00.000
2 2010-06-15 00:00:00.000 2010-07-01 00:00:00.000
3 2010-08-15 00:00:00.000 NULL
3 2010-08-15 00:00:00.000 NULL
4 2010-04-01 00:00:00.000 2010-04-15 00:00:00.000
4 2010-04-15 00:00:00.000 2010-05-01 00:00:00.000
4 NULL NULL
Update 1:
For those that are interested, I've compared the performance of the two variants in SQL Server 2008 R2 (one uses MIN aggregate and the other uses TOP 1 with an ORDER BY):
Without an index on the date column, the MIN version had a cost of 0.0187916 and the TOP/ORDER BY version had a cost of 0.115073 so the MIN version was "better".
With an index on the date column, they performed identically.
Note that this was testing with just these 9 records so the results could be (very) spurious...
Update 2:
The results hold for 10,000 uniformly distributed random records. The TOP/ORDER BY query takes so long to run at 100,000 records I had to cancel it and give up.
If your db is oracle, you can use lead() and lag() functions.
SELECT id, date,
LEAD(date, 1, 0) OVER (PARTITION BY ID ORDER BY Date DESC NULLS LAST) NEXT_DATE,
FROM Your_table
ORDER BY ID;
SELECT
id,
date,
( SELECT date
FROM table t1
WHERE t1.date > t2.date
ORDER BY t1.date LIMIT 1 )
FROM table t2
I think self JOIN would be faster than subselect.
WITH dates AS (
SELECT 1 AS ID, '2010-05-01' AS Date
UNION ALL SELECT 1, '2010-06-01'
UNION ALL SELECT 1, '2010-07-01'
UNION ALL SELECT 2, '2010-06-15'
UNION ALL SELECT 3, '2010-08-15'
UNION ALL SELECT 3, '2010-08-15'
UNION ALL SELECT 4, '2010-04-01'
UNION ALL SELECT 4, '2010-04-15'
UNION ALL SELECT 4, ''
)
SELECT
dates.ID,
dates.Date,
nextDates.Date AS Next_Date
FROM
dates
LEFT JOIN
dates nextDates
ON nextDates.ID = dates.ID
AND nextDates.Date > dates.Date
LEFT JOIN
dates noLower
ON noLower.ID = nextDates.ID
AND noLower.Date < nextDates.Date
AND noLower.Date > dates.Date
WHERE
dates.Date > 0
AND noLower.ID IS NULL
https://www.db-fiddle.com/f/4sWRLt2hxjik5HqiJ21ez8/1