I want to get the query result (e.g. to populate table) of last 7 dates (without times). I know that we can select some scalars without FROM statement. So I ended up with following solution:
select DATEADD (DAY, 0, CONVERT(date, GetDate()))
Union
select DATEADD (DAY,-1, CONVERT(date, GetDate()))
Union
select DATEADD (DAY,-2, CONVERT(date, GetDate()))
Union
select DATEADD (DAY,-3, CONVERT(date, GetDate()))
Union
select DATEADD (DAY,-4, CONVERT(date, GetDate()))
Union
select DATEADD (DAY,-5, CONVERT(date, GetDate()))
Union
select DATEADD (DAY,-6, CONVERT(date, GetDate()))
Please point me to better (and more elegant) solution if there is one.
The VALUES, table value constructor, is a little more concise.
select dateadd(day, x.num, convert(date, getdate()))
from (
values (0), (-1), (-2), (-3), (-4), (-5), (-6)
) x (num)
order by x.num;
Returns:
Date
2021-11-18
2021-11-19
2021-11-20
2021-11-21
2021-11-22
2021-11-23
2021-11-24
You can also expand on the values table by using either a permanent numbers/tally table (always handy) or by generating an artibrary list of numbers from any suitable table, you can then create a list of dates for any period
select dateadd(day, n.v, convert(date, getdate()))
from (
select top (30) v=-1 * Row_Number() over(order by (select 1))
from master.dbo.spt_values
)n
order by n.v;
Related
I need to find out the date 360 times from today. How to use SQL Server to implement it efficiently?
If today is May 13, 2021. Then I need to get dates like May 18, 2020, May 24, 2019, May 29, 2018, etc. The difference between these dates and today is a multiple of 360.
My current query is:
select *
from table
where dateDIFF(dd,effective_time,#{today}) in (360,720,1080,1440....)
New addition:
And I hope this query can conform to SARGable expression.
At present, we need to support the multiple time to the top ten 360.
If there is a query format that can support any 360 times of time and conform to SARGable expression. Thank you very much.
The query can take advantage of an index on effective_time column when effective_time is not a part of an expression in a condition. For example
with nmbrs (n) as (
select 360 union all
select 720 union all
select 1080 union all
select 1440
),
dates as (
select dateAdd(dd, n, #start) dt
from nmbrs
)
select t.*
from table t
join dates d on t.effective_time = d.dt
For a sargable expression, you would use:
where effective_time in (dateadd(day, 360, convert(date, getdate())),
dateadd(day, 720, convert(date, getdate())),
dateadd(day, 1080, convert(date, getdate())),
dateadd(day, 1440, convert(date, getdate()))
)
Note: If effective_time has a time component, you will need convert(date, effective_time). SQL Server can still use an index with this expression.
#Serg's answer can be made more concise, by using a VALUES clause
with dates as (
select dateAdd(dd, n, #start) dt
from (values (360), (720), (1080), (1440)) nmbrs(n)
)
select t.*
from table t
join dates d on t.effective_time = d.dt;
If, for example, you also wanted to filter how many rows based on another column, you could add a join condition:
with dates as (
select n,
dateAdd(dd, n, #start) dt
from (values (360), (720), (1080), (1440)) nmbrs(n)
)
select t.*
from table t
join dates d on t.effective_time = d.dt and d.n > t.max_dates;
I am not a SQL expert at all...we are trying to us the following to pull data from the previous week. I am fairly certain the 4 is incorrect, as we want data from Sunday through Saturday. The statement that was created was:
SELECT * FROM Table
Where [Date] Between DATEADD(wk,DATEDIFF(wk,7,GETDATE()),0) AND
DATEADD(wk,DATEDIFF(wk,7,GETDATE()),4)
Assuming you are working on Sql Server, you can use cte structure like below, set regarding data into cte and filter in your main query:
;with cte (ID) as ( --data from previous week only
Select Id from table
Where [Date] >= DATEADD(WEEK,-1,DATEADD(week,datediff(week,0,getdate()),0))
AND [Date] < DATEADD(week,datediff(week,0,getdate()),0)
)
select *
from table t
inner join cte on t.Id = cte.ID
where DATEPART(DW, [Date]) >= 0 --sunday
and DATEPART(DW, [Date]) <= 6 --saturday
In the filter, edit 0 and 6 to filter your data based on date as you wish.
If you use this, it returns previous Saturday and Sunday:
SELECT DATENAME(DW,(DATEADD(day, -6, getdate()))) ,DATENAME(DW,(DATEADD(day, -5,
getdate())))
[![Day Name][1]][1]
So, for example, you can use DATEADD(day, -6, getdate()) to get Saturday.
how can I get the last recorded data of the time 23:59 from yesterday and the day before?
my code doesn't have a filter of the time yet so it only shows all the data from yesterday and the day before.
select *
from tbl_Total
where date between DATEADD(day, -3, GETDATE()) AND DATEADD(day, -1, GETDATE())
In your case,
select * from tbl_Total as of timestamp timestamp '2017-07-19 23:59:59'
and
select * from tbl_Total as of timestamp timestamp '2017-07-18 23:59:59'
Try this
select *
from tbl_Total
where date between dateadd(day,-3,convert(varchar(10),getdate(),112)) AND dateadd(day,-3,convert(varchar(10),getdate(),112)+ ' 23:59:59:997' )
This query will return yestarday date with time 23:59:59.
SELECT CAST(CAST(CAST(DATEADD(day, -1, GETDATE()) as DATE) as varchar(12)) +' 23:59:59' as datetime2)
So you can use it in your query:
select *
from tbl_Total
where date between DATEADD(day, -3, GETDATE()) AND CAST(CAST(CAST(DATEADD(day, -1, GETDATE()) as DATE) as varchar(12)) +' 23:59:59' as datetime2)
EDIT: More elegant way:
SELECT DATEADD(second, -1, DATEADD(dd, DATEDIFF(dd,0,GETDATE()),0))
This query returns yesterday date with time 23:59:59.
EDIT2: If you want to return the day before with time 23:59:59 you need to use this query:
SELECT DATEADD(second, -1, DATEADD(dd, DATEDIFF(dd,1,GETDATE()),0))
If you want to obtain any other day you can change number 2 and test it.
Assuming you don't know the exact time you can get the latest rows using ROW_NUMBER:
with cte as
( select *,
row_number() -- for each day sorted descending
over (partition by DATEADD(dd, DATEDIFF(dd,0,GETDATE()),0)
order by date desc) as rn
from tbl_Total
where -- yesterday between 23:59 and 23:59:99.999
( date >= DATEADD(dd, DATEDIFF(dd,0,GETDATE()),0) - (1.0/1440)
and date < DATEADD(dd, DATEDIFF(dd,0,GETDATE()),0)
)
or -- day before yesterday between 23:59 and 23:59:99.999
( date >= DATEADD(dd, DATEDIFF(dd,1,GETDATE()),0) - (1.0/1440)
and date < DATEADD(dd, DATEDIFF(dd,1,GETDATE()),0)
)
)
select * from cte
where rn = 1 --latest row only
i have table with DOB column ('2012-05-29 00:00:00.000') and few other fields , i need to select the data for DOB between 6 months to 6 Years. I tried using the below SQL but this is not giving me the right data. any help will be appreciated.
select * from dbo.xyz
where ( FLOOR(DATEDIFF(MONTH, birth_date , GETDATE()) % 12) >=6
AND FLOOR(DATEDIFF(DAY, birth_date , GETDATE()) / 365.25) <= 6
)
When using dates, the advice is to use functions only on the non-column values. In other words, modify getdate(), not birth_date:
select *
from dbo.xyz
where birth_date between dateadd(year, -6, getdate()) and dateadd(month, -6, getdate())
This has two advantages. First, it makes the where clause "sargable", which means an index can be used on the comparison. More importantly, the alternative of using datediff() doesn't quite work as expected. datediff() counts the number of calendar boundaries between two values. So, 2014-12-31 and 2015-01-01 are one day apart, one month apart, and even one year apart.
Try this
select * from dbo.xyz
where DATEDIFF(MONTH, birth_date , GETDATE()) between 6 and 72
Here is another option that will allow indexing on birthdate.
select *
from dbo.xyz
where birthdate > DATEADD(YEAR, -6, GETDATE())
and birthdate < DATEADD(MONTH, -6, GETDATE())
I want to write a select that aggregates over data (which has a DATETIME column as ID) with ANY interval theoretically possible (like 1hr, 1hr and 22seconds, 1year and 3minutes, etc. ).
This select should be able to aggregate by 1hr, 12min, 14seconds and should return 3 rows
SELECT DATEPART(YEAR,id) as year,
DATEPART(MONTH,id) as month,
DATEPART(DAY,id) as day,
DATEPART(HOUR,id) as hour,
DATEPART(MINUTE,id) as minute,
AVG([Open]),
AVG([Close]),
AVG([Min]),
AVG([Max])
FROM QuoteHistory
where id between '2000-02-06 17:00:00.000' and '2000-02-06 20:36:42.000'
GROUP BY
DATEPART(YEAR,id),
DATEPART(MONTH,id),
DATEPART(DAY,id),
DATEPART(HOUR,id),
DATEPART(MINUTE,id)
ORDER BY 1,2,3,4,5;
I am kind of stuck here and can't get my head around this problem.. For "simple intervals" like "30 minutes" i could just add a modulo
DATEPART(MINUTE,id)%2
but when the interval "touches" more than 1 part of the date, I'm stuck.
Any help appreciated, thx!
Assuming some parameters here:
;WITH Date_Ranges AS (
SELECT
#min_datetime AS start_datetime,
DATEADD(SECOND, #seconds,
DATEADD(MINUTE, #minutes,
DATEADD(HOUR, #hours,
DATEADD(DAY, #days,
DATEADD(WEEK, #weeks,
DATEADD(MONTH, #months,
DATEADD(YEAR, #years, #min_datetime))))))) AS end_datetime
UNION ALL
SELECT
DATEADD(SECOND, 1, end_datetime),
DATEADD(SECOND, #seconds,
DATEADD(MINUTE, #minutes,
DATEADD(HOUR, #hours,
DATEADD(DAY, #days,
DATEADD(WEEK, #weeks,
DATEADD(MONTH, #months,
DATEADD(YEAR, #years, end_datetime)))))))
FROM
Date_Ranges
WHERE
DATEADD(SECOND, 1, end_datetime) < #max_datetime
)
SELECT
DR.min_datetime,
DR.max_datetime,
AVG([Open]),
AVG([Close]),
AVG([Min]),
AVG([Max])
FROM
Date_Ranges DR
LEFT OUTER JOIN Quote_History QH ON
QH.id BETWEEN DR.min_datetime AND DR.max_datetime
GROUP BY
DR.min_datetime,
DR.max_datetime
ORDER BY
DR.min_datetime,
DR.max_datetime
You might need to fiddle with how to handle the edge cases (that 1 second range between date ranges could be a problem depending on your data). This should hopefully point you in the right direction though.