I have this data in a table.
create table pick_max_date
(
student_id int
,date1 datetime
,date2 datetime
,date3 datetime
,date4 datetime
)
insert into pick_max_date
(student_id,date1,date2,date3,date4)values
(1,'2015-06-01','2016-01-01','2014-01-01','2017-01-01')
,(2,'2016-06-01','2017-08-01','2018-01-01','2017-05-06')
,(3,'2013-06-01','2019-08-01','2012-01-01','2012-05-06')
select * from pick_max_date
I need to select the max date for each student as below.
student_id max_date
---------- ----------
1 2017-01-01
2 2018-01-01
3 2019-08-01
what is the most optimised way to select as above. any help is appreciated.
Thanks in advance
Construct a derived table of the columns and select the max from that table,
select student_id,
(
select max(d.d)
from (values(date1),
(date2),
(date3),
(date4)
) as d(d)
) as max_date
from dbo.pick_max_date;
Sergey Gegoyan describes in the following link very efficient four different ways to solve this problem. I would prefer the first one the most:
LINK
Let me know if you found it useful.
SELECT student_id ,
(SELECT Max(v) FROM (VALUES (date1), (date2), (date3)) AS value(v)) as maxdate
FROM pick_max_Date
or
SELECT student_id,b.*
from
pick_max_Date
cross apply
(select max(d)
from
(values(date1),(date2),(date3),(date4))v(d)
)b(maxx)
You can do either the values tables already mentioned, or simply use a case if the columns are static:
select student_id
,(select max(d)
from (values(date1),(date2),(date3),(date4)) as tbl(d)) as MaxDate
,case when date1 >= date2 and date1 >= date3 and date1 >= date4 then date1
when date2 >= date1 and date2 >= date3 and date2 >= date4 then date2
when date3 >= date1 and date3 >= date2 and date3 >= date4 then date3
else date4
end as MaxDate2
from pick_max_date
Related
SELECT TOP 100 *
FROM FactSalesDetail
WHERE TradingDate >= DATEADD(ww, -6, (Select MAX([TradingDate]) From FactSalesDetail))
ORDER BY TradingDate
Can anyone advise how I can convert the above WHERE Clause from retrieving the last 6 weeks data from Max Date in my Fact Table to the last 6 weeks to the Previous Saturday?
So as of Today that would Saturday 1st Jan and then back 6 weeks from that?
Using the current weekday can get you last Saturday.
And if you bring ##DATEFIRST into the equation then it won't depend on the DATEFIRST setting.
SELECT TOP 100 *
FROM FactSalesDetail
WHERE TradingDate >= CONVERT(DATE, DATEADD(WEEK, -6, DATEADD(DAY, -(##DATEFIRST+DATEPART(WEEKDAY,GETDATE()))%7,
GETDATE())))
AND TradingDate <= CONVERT(DATE, DATEADD(DAY, -(##DATEFIRST+DATEPART(WEEKDAY,GETDATE()))%7,
GETDATE()))
ORDER BY TradingDate
Test snippet for date range
SET DATEFIRST 7;
SELECT
datename(weekday, date_now) AS weekday_now, date_now
, datename(weekday, date1) AS wd1, date1
, datename(weekday, date2) AS wd2, date2
FROM
(
SELECT
CAST(GETDATE() AS DATE) AS date_now
, CONVERT(DATE, DATEADD(WEEK, -6, DATEADD(DAY, -(##DATEFIRST+DATEPART(WEEKDAY,GETDATE()))%7,
GETDATE()))) AS date1
, CONVERT(DATE, DATEADD(DAY, -(##DATEFIRST+DATEPART(WEEKDAY,GETDATE()))%7,
GETDATE())) AS date2
) q
weekday_now
date_now
wd1
date1
wd2
date2
Tuesday
2022-01-04
Saturday
2021-11-20
Saturday
2022-01-01
db<>fiddle here
Suppose I have following data in a table
id createdAt
1 2021-02-26T06:29:03.482Z
2 2021-02-27T06:29:03.482Z
3 2021-03-14T06:29:03.482Z
4 2021-03-17T06:29:03.482Z
I want data of current month. ie, if I generate report in march, I need to fetch results of march, so we need only current month data from table.
wanted output is
id createdAt
3 2021-03-14T06:29:03.482Z
4 2021-03-17T06:29:03.482Z
Anyone please help. Thank you.
You can use date_trunc():
select *
from the_table
where date_trunc('month', createdat) = date_trunc('month', current_timestamp);
date_trunc('month', ...) returns the first day of the month.
However, the above is not able to make use of an index on createdat. To improve performance, use a range query:
select *
from the_table
where createdat >= date_trunc('month', current_timestamp)
and createdat < date_trunc('month', current_timestamp) + interval '1 month'
The expression date_trunc('month', current_timestamp) + interval '1 month' returns the start of the next month (that's way this is compared with <)
You can compare the month and year of a date with the current one. But the index by field will not be used, you can build a separate index by year and month for this.
select *
from your_table
where extract(YEAR FROM createdAt) = extract(YEAR FROM now())
and extract(MONTH FROM createdAt) = extract(MONTH FROM now())
I would like to update the contents of the Date1 column to reflect the oldest date in each row, unless the date has already passed (Date1 < current date), in which case i'd like Date1 to be populated with the 2nd oldest date in the row.
ID
Date 1
Date 2
Date 3
Date 4
001
01/14/2022
01/14/2022
01/15/2022
01/16/2022
002
04/15/2019
04/15/2019
01/10/2021
01/10/2021
I am currently using
update mytable t
set date1 = (
select min(date)
from (values (date2), (date3), (date4)) d(dt)
where dt >= current_date
)
The only problem I run into is when all available dates are prior to the current date. In this case it overwrites the value in the date1 column with null, which is not ideal. I'd like the query to leave the date1 field intact in these instances.
Figured it out:
update mytable t
set date1 = coalesce ((
select min(date)
from (values (date2), (date3), (date4)) d(dt)
where dt >= current_date
), date 1);
I want to get greater date from four date columns and fields can be NULL.
Please help me to write a query for this.
Example:
select max(date1, date2, date3, date4) from table A where tag_id='xxxxx'
You can work with unions which combine your query results and then get the max date of the combined columns
Here is the same question asked in another post
Hope that helps you
select max(max_date) from
(select date1 max_date from table A where tag_id='xxxxx'
union all
select date2 from table A where tag_id='xxxxx'
union all
select date3 from table A where tag_id='xxxxx'
union all
select date4 from table A where tag_id='xxxxx')
Here you have:
SELECT
CASE
WHEN date1 >= date2 AND date1 >= date3 THEN date1
WHEN date2 >= date1 AND date2 >= date3 THEN date2
WHEN date3 >= date1 AND date3 >= date2 THEN date3
ELSE date1
END AS RecentDate
FROM table A
WHERE A.tag_id='xxxxx'
Hope it helps,
Did you try your example query?
MAX() (and MIN() for that matter) are a bit unusual....they exists as both an aggregate function operating on multiple rows and a scalar function operating on multiple columns.
The works fine for me on DB2 for IBM i:
select max(dte1,dte2,dte3,dte4) from qtemp.test
Here is my code but its showing null while today is friday. But I would like to get last working day.
-- Insert statements for procedure here
--Below is the param you would pass
DECLARE #dateToEvaluate date=GETDATE();
--Routine
DECLARE #startDate date=CAST('1/1/'+CAST(YEAR(#dateToEvaluate) AS char(4)) AS date); -- let's get the first of the year
WITH
tally(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1 FROM sys.all_columns),
dates AS (
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS dt_id,
DATEADD(DAY,n,#startDate) AS dt,
DATENAME(WEEKDAY,DATEADD(DAY,n,#startdate)) AS dt_name
FROM tally
WHERE n<366 --arbitrary
AND DATEPART(WEEKDAY,DATEADD(DAY,n,#startDate)) NOT IN (6)
AND DATEADD(DAY,n,#startDate) NOT IN (SELECT CAST(HolidayDate AS date) FROM Holiday)),
curr_id(id) AS (SELECT dt_id FROM dates WHERE dt=#dateToEvaluate)
SELECT d.dt
FROM dates AS d
CROSS JOIN
curr_id c
WHERE d.dt_id+1=c.id
The code below will take any date and "walk backward" to find the previous week day (M-F) which is not in the #holidays table.
declare #currentdate datetime = '2015-03-22'
declare #holidays table (holiday datetime)
insert #holidays values ('2015-03-20')
;with cte as (
select
#currentdate k
union all
select
dateadd(day, -1, k)
from cte
where
k = #currentdate
or ((datepart(dw, k) + ##DATEFIRST - 1 - 1) % 7) + 1 > 5 --determine day of week independent of culture
or k in (select holiday from #holidays)
)
select min(k) from cte
The dates table doesn't have any FRIDAY dates in it. Change the NOT IN (6) to NOT IN (1, 7). This will remove Saturday and Sundays from the dates table.