Select X Most Recent Non-Consecutive Days Worth of Data - sql

Anyone got any insight as to select x number of non-consecutive days worth of data? Dates are standard sql datetime. So for example I'd like to select 5 most recent days worth of data, but there could be many days gap between records, so just selecting records from 5 days ago and more recent will not do.

Following the approach Tony Andrews suggested, here is a way of doing it in T-SQL:
SELECT
Value,
ValueDate
FROM
Data
WHERE
ValueDate >=
(
SELECT
CONVERT(DATETIME, MIN(TruncatedDate))
FROM
(
SELECT DISTINCT TOP 5
CONVERT(VARCHAR, ValueDate, 102) TruncatedDate
FROM
Event
ORDER BY
TruncatedDate DESC
) d
)
ORDER BY
ValueDate DESC

I don't know the SQL Server syntax, but you need to:
1) Select the dates (with time component truncated) in descending order
2) Pick off top 5
3) Obtain 5th value
4) Select data where the datetime >= 5th value
Something like this "pseudo-SQL":
select *
from data
where datetime >=
( select top 1 date
from
( select top 5 date from
( select truncated(datetime) as date
from data
order by truncated(datetime) desc
)
order by date
)
)

This should do it and be reasonably good from a performance standpoint. You didn't mention how to handle ties, so you can add the WITH TIES clause if you need to do that.
SELECT TOP (#number_to_return)
* -- Write out your columns here
FROM
dbo.MyTable
ORDER BY
MyDateColumn DESC

Related

SQL server: Get record with date closest to given date

I have a table dbo.studies with datetime column studydate
I want to query the database using the datetime variable givendate to find the record closest to the datetime in column studydate
Using:
SELECT TOP 1 *
FROM studies
WHERE studies.studydate < givendate
ORDER BY studies.studydate DESC
Will result in the record that is less and closest to givendate, but I need the record closest to givendate, regardless of whether it's less or more then studydate
Any thoughts on how to find it?
One method is:
SELECT TOP 1 s.*
FROM studies s
ORDER BY ABS(DATEDIFF(day, s.studydate, #givendate));
This uses DATEDIFF() to get the closest date. Note that this is using day for the difference. If your "dates" have a time component, you might want a different date part.
Note that this will not take advantage of indexes. A faster method (if you have the indexes) is a bit more complicated:
SELECT TOP (1) s.*
FROM ((SELECT TOP 1 s.*
FROM studies s
WHERE s.studydate <= #givendate
ORDER BY s.studydate DESC
) UNION ALL
(SELECT TOP 1 s.*
FROM studies s
WHERE s.studydate > #givendate
ORDER BY s.studydate ASC
)
) s
ORDER BY DATEDIFF(day, s.studydate, #givendate));
Although this is more complicated, each subquery can use an index on studydate. The final sort would have only two rows, so it should be really fast.
SELECT TOP 1 *
FROM studies
ORDER BY ABS(DATEDIFF(second, #givendate, studies.studydate))
use datediff function in order by it will always return the nearest 1
SELECT TOP 1 *
FROM studies
ORDER BY DATEDIFF(dd,studies.studydate, givendate) ASC
Order By ABS(DATEDIFF(day, YourDate, GetDate()))
Is The Best Method For Get Distinct and unique Recod When Your Table is Many Row and one column different
SELECT * FROM
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY ColumnName ORDER BY ABS(DATEDIFF(day, YourDate, GetDate()))) RowNumber
FROM [tableName]
)A
WHERE RowNumber = 1

How to query database for rows from next 5 days

How can I make a query in SQL Server to query for all rows for the next 5 days.
The problem is that it has to be days with records, so the next 5 days, might become something like, Today, Tomorrow, some day in next month, etc...
Basically I want to query the database for the records for the next non empty X days.
The table has a column called Date, which is what I want to filter.
Why not split the search into 2 queries. First one searches for the date part, the second uses that result to search for records IN the dates returned by the first query.
#Anagha is close, just a little modification and it is OK.
SELECT *
FROM TABLE
WHERE DATE IN (
SELECT DISTINCT TOP 5 DATE
FROM TABLE
WHERE DATE >= referenceDate
ORDER BY DATE
)
You can use following SQL query where 5 different dates are fetched at first then all rows for those selected dates are displayed
declare #n int = 5;
select *
from myData
where
datecol in (
SELECT distinct top (#n) cast(datecol as date) as datecol
FROM myData
WHERE datecol >= '20180101'
ORDER BY datecol
)
Try this:
select date from table where date in (select distinct top 5 date
from table where date >= getdate() order by date)
If your values are dates, you can use `dense_rank():
select t.*
from (select t.*, dense_rank() over (order by datecol) as seqnum
from t
where datecol >= cast(getdate() as date)
) t
where seqnum <= 5;
If the column has a time component and you still want to define days by midnight-to-midnight (as suggested by the question), just convert to date:
select t.*
from (select t.*,
dense_rank() over (order by cast(datetimecol as date)) as seqnum
from t
where datetimecol >= cast(getdate() as date)
) t
where seqnum <= 5;

How to get latest record based on date and time in Sql server

I am trying to get latest record based on date and time , but column contains time is in 12 Hours AM/PM format.
Suppose my records in
2015-09-07 12:50:37.1983315 PM - Coming this record
2015-09-07 03:12:15.1983315 PM - Actually I need to get this record.
The above result came by below query..
SELECT top 10 * FROM SHAdminMessageIndex where Appid='62001308607984608300' and
PolicyNumber='0081317' order by BeginTime desc
So how to get the result by using 12 hours format with AM and PM. Thanks in Advance
Try this
SELECT top 10 * FROM SHAdminMessageIndex
where Appid='62001308607984608300' and PolicyNumber='0081317'
order by
cast(BeginTime as datetime2) desc
OR
SELECT top 10 * FROM SHAdminMessageIndex
where Appid='62001308607984608300' and PolicyNumber='0081317'
order by
cast(left(BeginTime,charindex('.',BeginTime)-1)+right(BeginTime,2) as datetime) desc
Try this
SELECT top 10 * FROM SHAdminMessageIndex where Appid='62001308607984608300'
and PolicyNumber='0081317' order by stuff(convert(varchar(19), BeginTime,
126),11,1,' ') desc
You want the first record of each day? You can group by date and take the first of each group. Therefore use a ranking function like ROW_NUMBER and a CTE:
WITH CTE AS
(
SELECT t.*,
RN = ROW_NUMBER() OVER (PARTITION BY CAST(BeginTime AS Date) ORDER BY BeginTime )
FROM SHAdminMessageIndex t
WHERE Appid='62001308607984608300'
AND PolicyNumber='0081317'
)
SELECT TOP 10 CTE.*
FROM CTE
WHERE RN = 1
ORDER BY BeginTime DESC
This is why we should always use proper datatype to store the data. Try Casting the BeginTime to DATETIME2
SELECT top 10 *
FROM SHAdminMessageIndex
where Appid='62001308607984608300'
and PolicyNumber='0081317'
order by Cast(BeginTime AS DATETIME2) DESC
Use PARSE to convert your string to DATETIME2.
select top 10 *
from SHAdminMessageIndex
where Appid='62001308607984608300' and PolicyNumber='0081317'
order by parse(BeginTime as datetime2 using 'en-US') desc;
Make sure to specify the language such as not to be dependent from session settings - your datetime string may not be a valid datetime in another language (in many languages PM and AM are not valid).
SQL fiddle: http://www.sqlfiddle.com/#!3/9eecb7d/366.

SQL Server : select the minimum value from table

I know it's simple question, but I still can't figure it out.
I want to find the date which is the closest date from now.
Here is my product table:
P_INDATE
----------
2013-11-03
2013-12-13
2013-11-13
Basically, it should show 2013-12-13.
I type this SELECT Max( P_INDATE) FROM product and it work.
Then, I try to use MIN((GETDATE()- P_INDATE)) in the where condition, but I fail.
Use MAX and WHERE clause along with function GETDATE():
SELECT MAX(P_INDATE)
FROM product
WHERE P_INDATE < GETDATE()
The above query gives you maximum date, which is less than current date, which you get using function GETDATE()
One way to go about this is to order the query by the difference between the stored date and the current date and take the first rows only. Using abs will allow you to find the closest date regardless of whether its before or after the current date.
SELECT TOP 1 p_indate
FROM mytable
ORDER BY ABS(GETDATE() - p_indate) ASC
Assuming you have a column which stores data and you want to show only recent one every time,why cant you use
select max(date) from yourtable which will always give you recent date
If you have an index on the column, the most efficient method is probably a bit more complicated:
SELECT TOP 1 P_INDATE
FROM ((SELECT TOP 1 P_INDATE
FROM product
WHERE P_INDATE < GETDATE()
ORDER BY P_INDATE DESC
) UNION ALL
(SELECT TOP 1 P_INDATE
FROM product
WHERE P.INDATE >= GETDATE()
ORDER BY P.INDATE
)
)
ORDER BY ABS(DATEDIFF(second, P_INDATE, GETDATE()))
The subqueries will use the index to get (at most) one row earlier and later than the current date. The outer ORDER BY then just needs to sort two rows.
Well you can try this:
SELECT TOP(1) P_INDATE
FROM [product table]
ORDER BY CASE
WHEN DATEDIFF(day,P_INDATE,GETDATE()) < 0
THEN DATEDIFF(day,GETDATE(),P_INDATE)
ELSE DATEDIFF(day,P_INDATE,GETDATE())
END ASC

Last day of the month with a twist in SQLPLUS

I would appreciate a little expert help please.
in an SQL SELECT statement I am trying to get the last day with data per month for the last year.
Example, I am easily able to get the last day of each month and join that to my data table, but the problem is, if the last day of the month does not have data, then there is no returned data. What I need is for the SELECT to return the last day with data for the month.
This is probably easy to do, but to be honest, my brain fart is starting to hurt.
I've attached the select below that works for returning the data for only the last day of the month for the last 12 months.
Thanks in advance for your help!
SELECT fd.cust_id,fd.server_name,fd.instance_name,
TRUNC(fd.coll_date) AS coll_date,fd.column_name
FROM super_table fd,
(SELECT TRUNC(daterange,'MM')-1 first_of_month
FROM (
select TRUNC(sysdate-365,'MM') + level as DateRange
from dual
connect by level<=365)
GROUP BY TRUNC(daterange,'MM')) fom
WHERE fd.cust_id = :CUST_ID
AND fd.coll_date > SYSDATE-400
AND TRUNC(fd.coll_date) = fom.first_of_month
GROUP BY fd.cust_id,fd.server_name,fd.instance_name,
TRUNC(fd.coll_date),fd.column_name
ORDER BY fd.server_name,fd.instance_name,TRUNC(fd.coll_date)
You probably need to group your data so that each month's data is in the group, and then within the group select the maximum date present. The sub-query might be:
SELECT MAX(coll_date) AS last_day_of_month
FROM Super_Table AS fd
GROUP BY YEAR(coll_date) * 100 + MONTH(coll_date);
This presumes that the functions YEAR() and MONTH() exist to extract the year and month from a date as an integer value. Clearly, this doesn't constrain the range of dates - you can do that, too. If you don't have the functions in Oracle, then you do some sort of manipulation to get the equivalent result.
Using information from Rhose (thanks):
SELECT MAX(coll_date) AS last_day_of_month
FROM Super_Table AS fd
GROUP BY TO_CHAR(coll_date, 'YYYYMM');
This achieves the same net result, putting all dates from the same calendar month into a group and then determining the maximum value present within that group.
Here's another approach, if ANSI row_number() is supported:
with RevDayRanked(itemDate,rn) as (
select
cast(coll_date as date),
row_number() over (
partition by datediff(month,coll_date,'2000-01-01') -- rewrite datediff as needed for your platform
order by coll_date desc
)
from super_table
)
select itemDate
from RevDayRanked
where rn = 1;
Rows numbered 1 will be nondeterministically chosen among rows on the last active date of the month, so you don't need distinct. If you want information out of the table for all rows on these dates, use rank() over days instead of row_number() over coll_date values, so a value of 1 appears for any row on the last active date of the month, and select the additional columns you need:
with RevDayRanked(cust_id, server_name, coll_date, rk) as (
select
cust_id, server_name, coll_date,
rank() over (
partition by datediff(month,coll_date,'2000-01-01')
order by cast(coll_date as date) desc
)
from super_table
)
select cust_id, server_name, coll_date
from RevDayRanked
where rk = 1;
If row_number() and rank() aren't supported, another approach is this (for the second query above). Select all rows from your table for which there's no row in the table from a later day in the same month.
select
cust_id, server_name, coll_date
from super_table as ST1
where not exists (
select *
from super_table as ST2
where datediff(month,ST1.coll_date,ST2.coll_date) = 0
and cast(ST2.coll_date as date) > cast(ST1.coll_date as date)
)
If you have to do this kind of thing a lot, see if you can create an index over computed columns that hold cast(coll_date as date) and a month indicator like datediff(month,'2001-01-01',coll_date). That'll make more of the predicates SARGs.
Putting the above pieces together, would something like this work for you?
SELECT fd.cust_id,
fd.server_name,
fd.instance_name,
TRUNC(fd.coll_date) AS coll_date,
fd.column_name
FROM super_table fd,
WHERE fd.cust_id = :CUST_ID
AND TRUNC(fd.coll_date) IN (
SELECT MAX(TRUNC(coll_date))
FROM super_table
WHERE coll_date > SYSDATE - 400
AND cust_id = :CUST_ID
GROUP BY TO_CHAR(coll_date,'YYYYMM')
)
GROUP BY fd.cust_id,fd.server_name,fd.instance_name,TRUNC(fd.coll_date),fd.column_name
ORDER BY fd.server_name,fd.instance_name,TRUNC(fd.coll_date)