Comparing dates using SQL - sql

I have a date that looks like this: 2014-10-01 12:35:29.440
the table looks like this:
ORDER 1 | 2014-07-31 00:00:00.000
ORDER 2 | 2015-07-31 00:00:00.000
sorry i wanted ORDER 2 to show up.. As my get date returns todays date and that is GREATER than 2014-07-31 00:00:00.000
Here is what i have tried:
SELECT TOP 1 NAME
FROM ORDER_DATES
WHERE GETDATE() > ORDER_DATE
ORDER BY NAME DESC

Your question still isn't quite worded in a way that is conducive to what you need... but I think I understand what you want now based on the comments.
Based on the comment:
IF it doesnt match the date then it needs to return the next row.
Which is ORDER 2
Something like this should work:
SELECT TOP 1 name
FROM ORDER_DATES o
INNER JOIN (
-- This subquery finds the first date that occurs *after* the current date
SELECT MIN(ORDER_DATE) AS ORDER_DATE
FROM ORDER_DATES
WHERE ORDER_DATE > GETDATE()
) minDateAfterToday ON o.ORDER_DATE = minDateAfterToday.ORDER_DATE
ORDER BY name
This would work a lot better if you had an ID field in the table, but this should work with the given data, you'll potentially run into issues if you have two orders on the exact same date.
EDIT:
here's a fiddle showing the query in action:
http://sqlfiddle.com/#!6/f3057/1

DATEDIFF will come handy, also you have to order by ORDER_DATE:
SELECT TOP 1 NAME
FROM ORDER_DATES
WHERE DATEDIFF(DAY,ORDER_DATE,GETDATE())>0
ORDER BY ORDER_DATE DESC

You can write as:
SELECT NAME
FROM ORDER_DATES
WHERE cast(GETDATE()as date) > cast (ORDER_DATE as date)
ORDER BY NAME DESC
Demo

Check if you are querying against right table
declare #dt datetime = cast('2014-10-01 12:35:29.440' as datetime), #dt2 datetime= cast('2014-07-31 00:00:00.000' as datetime);
print(case when #dt > #dt2 then 1 else 0 end);
This piece of script shows output 1 i.e. condition should match for ORDER 1.
Verify if you are missing some thing.
Edit as per change to original question:
here the condition needed be reverted as date value is in future which is greater than current date
new query will be as
SELECT TOP 1 NAME
FROM ORDER_DATES
WHERE ORDER_DATE > GETDATE()
ORDER BY NAME DESC

Related

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

SQL -- return 0s if no group exists

I have a rollup table that sums up raw data for a given hour. It looks something like this:
stats_hours:
- obj_id : integer
- start_at : datetime
- count : integer
The obj_id points to a separate table, the start_at field contains a timestamp for the beginning of the hour of the data, and the count contains the sum of the data for that hour.
I would like to build a query that returns a set of data per day, so something like this:
Date | sum_count
2014-06-01 | 2000
2014-06-02 | 3000
2014-06-03 | 0
2014-06-04 | 5000
The query that I built does a grouping on the date column and sums up the count:
SELECT date(start_at) as date, sum(count) as sum_count
FROM stats_hours GROUP BY date;
This works fine unless I have no data for a given date, in which case it obviously leaves out the row:
Date | sum_count
2014-06-01 | 2000
2014-06-02 | 3000
2014-06-04 | 5000
Does anyone know of a good way in SQL to return a zeroed-out row in the case that there is no data for a given date group? Maybe some kind of case statement?
You need a full list of dates first, then connect that list to your available dates and group by that. Try the following:
--define start and end limits
Declare #todate datetime, #fromdate datetime
Select #fromdate='2009-03-01', #todate='2014-06-04'
;With DateSequence( Date ) as
(
Select #fromdate as Date
union all
Select dateadd(day, 1, Date)
from DateSequence
where Date < #todate
)
--select result
SELECT DateSequence.Date, SUM(Stats_Hours.Count) AS Sum_Count
FROM
DateSequence
LEFT JOIN
Stats_Hours ON DateSequence.Date = Stats_Hours.Start_At
GROUP BY DateSequence.Date
option (MaxRecursion 0)
EDIT: CTE code from this post

How to return a default value when no rows are returned from the select statement

I have a select statement that returns two columns, a date column, and a count(value) column. When the count(value) column doesn't have any records, I need it to return a 0. Currently, it just skips that date record all together.
Here is the basics of the query.
select convert(varchar(25), DateTime, 101) as recordDate,
count(Value) as recordCount
from History
where Value < 700
group by convert(varchar(25), DateTime, 101)
Here are some results that I'm getting.
+------------+-------------+
| recordDate | recordCount |
+------------+-------------+
| 02/26/2014 | 143 |
| 02/27/2014 | 541 |
| 03/01/2014 | 21 |
| 03/02/2014 | 60 |
| 03/03/2014 | 113 |
+------------+-------------+
Notice it skips 2/28/2014. This is because the count(value) column doesn't have anything to count. How can I add the record in there that has the date of 2/28/2014, with a recordCount of 0?
To generate rows for missing dates you can join your data to a date dimension table
It would look something like this:
select convert(varchar(25), ddt.DateField, 101) as recordDate,
count(t.Value) as recordCount
from History h
right join dbo.DateDimensionTable ddt
on ddt.DateField = convert(varchar(25), h.DateTime, 101)
where h.Value < 700
group by convert(varchar(25), h.DateTime, 101)
If your table uses the DateTime column to store dates only (meaning the time is always midnight), then you can replace this
right join dbo.DateDimensionTable ddt
on ddt.DateField = convert(varchar(25), h.DateTime, 101)
with this
right join dbo.DateDimensionTable ddt
on ddt.DateField = h.DateTime
You may use COUNT(*). It will return zero if nothing was found for the column. Also you may group result set by value column if it is needed.
select convert(varchar(25), DateTime, 101) as recordDate,
CASE WHEN count(value) =0 THEN 0 ELSE COUNT(value) END recordCount
from History
where Value < 700
group by convert(varchar(25), DateTime, 101)
When you use a group by, it only creates a distinct list of values that exist in your records. Since 20140228 has no records, it will not show up in the group by.
Your best bet is to generate a list of values, dates in your case, and left join or apply that table against your history table.
I can't seem to copy my T-SQL in here so here's a hastebin.
http://hastebin.com/winaqutego.vbs
The best practice would be for you to have a datamart where a separate dimensional table for dates is kept with all dates you might be interested at - even if they lack amounts. DMason's answer shows the query with such a dimensional table.
To keep with the best practices you would have a fact table where you'd keep these historical data already pre-grouped at the granularity level you need (daily, in this case), so you wouldn't need a GROUP BY unless you needed a coarser granularity (weekly, monthly, yearly).
And in both your operational and datamart databases the dates would be stored as dates, not...
But then, since this is real world and you might not be able to change what somebody else made... If you: a) only care about the dates that appear in [History], and b) such dates are never stored with hours/minutes; then following query might be what you'd need:
SELECT MyDates.DateTime, COUNT(*)-1 AS RecordCount
FROM (
SELECT DISTINCT DateTime FROM History
) MyDates
LEFT JOIN History H
ON MyDates.DateTime = H.Datetime
AND H.Value < 700
GROUP BY MyDates.DateTime
Do try to add an index over DateTime and to further constrain the query with an earliest/latest date for better performance results.
I agree that a Dates table (AKA time dimension) is the right solution, but there is a simpler option:
SELECT
CONVERT(VARCHAR(25), DateTime, 101) AS RecordDate,
SUM(CASE WHEN Value < 700 THEN 1 ELSE 0 END) AS RecordCount
FROM
History
GROUP BY
CONVERT(VARCHAR(25), DateTime, 101)
Try this:
DECLARE #Records TABLE (
[RecordDate] DATETIME,
[RecordCount] INT
)
DECLARE #Date DATETIME = '02/26/2014' -- Enter whatever date you want to start with
DECLARE #EndDate DATETIME = '03/31/2014' -- Enter whatever date you want to stop
WHILE (1=1)
BEGIN
-- Insert the date into the temp table along with the count
INSERT INTO #Records (RecordDate, RecordCount)
VALUES (CONVERT(VARCHAR(25), #Date, 101),
(SELECT COUNT(*) FROM dbo.YourTable WHERE RecordDate = #Date))
-- Go to the next day
#Date = DATEADD(d, 1, #Date)
-- If we have surpassed the end date, break out of the loop
IF (#Date > #EndDate) BREAK;
END
SELECT * FROM #Records
If your dates have time components, you would need to modify this to check for start and end of day in the SELECT COUNT(*)... query.

Total number of Events on every date

I am stuck developing a query.
I have a table, structured like this:
[EventId] [Description] [EventName] [ValidFrom] [ValidTo] [Approved]
1 Sample1 1stEvent 2013-01-27 2013-05-10 1
2 Sample2 2stEvent 2013-04-07 2013-06-15 1
3 Sample3 3stEvent 2013-04-07 2013-06-15 1
4 Sample4 4stEvent 2013-03-02 2013-05-29 1
5 Sample5 5stEvent 2013-05-17 2013-07-10 1
6 Sample6 6stEvent 2013-03-20 2013-05-11 1
What i want is the total number of events for every date within a date range, inclusive.
Select distinct
Convert(varchar,ValidFrom,101)as [Date],
case
when count(EventID)>1 then Convert(nvarchar, count(EventID)) +' Events'
else Convert(nvarchar, count(EventID)) + ' Event'
end as CountOf,
Row_Number()
over (Order By Convert(varchar,ValidFrom,101)) as RowNumber
from [Table]
where Approved=1
group by Convert(varchar,ValidFrom,101)
This is the query I have come up with until now, but this shows the total number of events on a particular date without including the events which were continued as per the dates between valid from and valid to dates.
This code sample is not complete - you need to enter the fields you need to display and aggregate upon. It sounds like you're looking for a result that's between two dates, and you don't have that in your query. I'm not sure I comletely understand your question.
DECLARE #pStartDate DATE
DECLARE #pEndDate DATE
SET #pStartDate = [enter your start date for the date range]
SET #pEndDate = [enter your end date for the date range]
SELECT
COUNT(EventId),
ValidFrom,
ValidTo
FROM [Table]
WHERE
ValidFrom >= #pStartDate
AND ValidTo <= #pEndDate
AND Approved = 1
GROUP BY
ValidFrom,
ValidTo
This will do:
declare #dateFrom date
declare #dateTo date
SET #dateFrom = '20130101'
SET #dateTo = '20130501'
;with cte as(Select #dateFrom AS EveryDay
UNION ALL
Select dateadd(dd, 1, EveryDay) FROM cte WHERE EveryDay < #dateTo)
SELECT
EveryDay,
COUNT(DISTINCT [EventName]) AS NoEvents
from cte LEFT JOIN Table1 ON ValidFrom <= EveryDay AND ValidTo >= EveryDay
GROUP BY EveryDay
OPTION (MAXRECURSION 0)
SQL Fiddle
With the above Query i have mentioned gives the result like this :-
Date CountOf RowNumber
01/27/2013 2 Events 1
03/02/2013 1 Event 2
04/07/2013 2 Events 3
05/17/2013 1 Event 4
As you can see i am getting total events only on the base of particular date which is not desired.
i want to show the result as like in valid from =01/27/2013 in valid to 2013-05-10 which means in the case of Date =2013-03-02 the events should be incremented by one or the number of events which are active on that date,so the result for 2013-03-02 should be 6 events, i wish i can present a better picture but because of the complexity it made me blank :(
SELECT t1.EventId,t1.Description,t1.EventName,t1.ValidFrom,t1.ValidTo,t1.Approved,SUM(TotalEvent) FROM
(SELECT EventId,Description,EventName,ValidFrom,ValidTo,Approved,COUNT(EventId) as Total
FROM TABLE
WHERE Approved='1' AND ValidFrom >=(DATE) AND ValidTO<=(DATE)
GROUP BY EventId,Description,EventName,ValidFrom,ValidTo,Approved) AS t1
LEFT JOIN
(SELECT EventId, COUNT(EventId) as TotalEvent
FROM TABLE
WHERE ValidFrom >=(DATE) AND ValidTO<=(DATE)) AS t2
ON t1.EventId=t2.EventId
Group by t1.EventId,t1.Description,t1.EventName,t1.ValidFrom,t1.ValidTo,t1.Approved
Hope this help you.

Select X Most Recent Non-Consecutive Days Worth of Data

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