Match partial date in SQL query? - sql

I am looking for a way to match a date, with the one related to records on my db.
I know how to match strings with the LIKE operator, but it doesn't work for dates; unless I search just for a number (say all records at 10, all records from the 21st and so on). As soon as I put minutes for example, the search with LIKE return no records.
How do you actually search for partial date? My objective is to find all records newer than a partial date; in the current day.
select * from CLIENTS where CLOSING like '%12:30%'
This won't match anything; but if I use just 12 or 30, it works....although it is not doing what I want.
Do I have to convert date in strings? I get a partial date from another process, and I would like to match all the records newer than the partial date.

Try this query
select * from CLIENTS where
TO_CHAR(CLOSING , 'dd-mm-yy hh24:mi:ss') like '%12:30%'
or
select * from CLIENTS where
TO_CHAR(CLOSING , 'hh24:mi') = '12:30'

If you want loans more recent than today at 12:30pm, you are best served to use date arithmetic rather than relying on string conversion
SELECT *
FROM clients
WHERE closing >= trunc(sysdate) + interval '12' hour + interval '30' minute;
or
SELECT *
FROM clients
WHERE closing >= trunc(sysdate) + 12.5/24
Here, trunc(sysdate) returns today at midnight. Then you can either add a fractional number of days (1/24 adds one hour so 12.5/24 takes you to 12:30pm) or you can add one or more intervals (you could use to_dsinterval as well to create the interval).

Related

How does date manipulation/comparison/grouping work in SQL queries?

I need to analyze an SQL query (and construct its equivalent in MDX). I'm not familiar with SQL and can't access the database, so there are 5 simple things I can't figure out:
What does the part WHERE idate BETWEEN trunc(SYSDATE, 'iw')-7 AND trunc(SYSDATE, 'iw')-3 mean? Specifically:
What does subtracting 7 from trunc(SYSDATE, 'iw') do? Subtract 7 weeks or 7 days? I understand the trunc(...) expression is a value 0-53 corresponding to the week of the year, but it seems to clash with the label "previous week" and stated purpose of the query.
How does SQL compare dates? Are the values from trunc(...) evaluated as dates during comparison?
The query seems to group rows together if they happened in the same minute. However, the few rows of output I can see have 10-minute granularity (00:00, 00:10, 00:20, etc.) Is there something in the query that groups rows into 10 minute intervals, or is this a result of the input data?
Why are calls to substr() and to_char() and needed in the group by condition? What would happen if trunc(idate, 'HH24:MI') was used instead?
What does the pm do? There is also a cm that seems to have a similar function. Are these part of the temporary table names?
Finally, how do the hash marks (#) affect this query? I read it might be to signify temporary tables. If so, are these temporary tables created manually, or does something in the query cause them to be created?
For reference here is the query. (On a Oracle database, if it makes any difference.) Its purpose is to "analyze how firewall accept events are trending compared to last week":
SELECT 'Previous Week Average' AS term ,
Substr(To_char(idate, 'HH24:MI'), 0, 4)
|| '0' AS event_time ,
Round(Avg(tot_accept)) AS cnt
FROM (
SELECT *
FROM st_event_100_#yyyymm-1m#
WHERE idate BETWEEN trunc(SYSDATE, 'iw')-7 AND trunc(SYSDATE, 'iw')-3 #stat_monitor_group_query#
UNION ALL
SELECT *
FROM st_event_100_#yyyymm#
WHERE idate BETWEEN trunc(SYSDATE, 'iw')-7 AND trunc(SYSDATE, 'iw')-3 #stat_monitor_group_query# ) pm
GROUP BY substr(to_char(idate, 'HH24:MI'), 0, 4)
|| '0'
UNION ALL
SELECT 'Today' AS term ,
substr(to_char(idate, 'HH24:MI'), 0, 4)
|| '0' AS event_time ,
round(avg(tot_accept)) AS cnt
FROM st_event_100_#yyyymm# cm
WHERE idate >= trunc(SYSDATE) #stat_monitor_group_query#
GROUP BY substr(to_char(idate, 'HH24:MI'), 0, 4)
|| '0'
ORDER BY term DESC,
event_time ASC
iw truncates the date to the first day of the calendar week as defined by the ISO 8601 standard, which is Monday. When you subtract numbers from the date, it is always the number of days. So, idate BETWEEN trunc(SYSDATE, 'iw')-7 AND trunc(SYSDATE, 'iw')-3 gives you those dates that fall between previous week's Monday and Friday.
to_char(idate, 'HH24:MI') gives you the time(hour and minute) part in 24hr format. Ex: 14:33. By using substrin to extract only 4 characters, you are actually getting 14:3. So yes, this groups with a granularity of 10 mins.
You cannot write trunc(idate, 'HH24:MI'). It can only have 1 precision specifier.
If you write trunc(idate,'HH24'), it truncates to the hour. If you use MI, it truncates to the minute. So, to truncate it to 10 mins is a little tricky.
pm is just an alias for the whole subquery.
SELECT *
FROM st_event_100_#yyyymm-1m#
......
WHERE idate BETWEEN trunc(SYSDATE, 'iw')-7 AND trunc(SYSDATE, 'iw')-3 #stat_monitor_group_query#
# is part of the table anme in your query. It has no significance as such. But, it might be project/company specific.

Why am I getting different results when comparing dates two ways?

This query:
select count(*), trim(data_date)
from man
where data_status = 'received' and data_date > sysdate-7
group by trim(data_date);
gives result like:
199 05-APR-16
But this query:
select count(*), trim(data_date)
from man
where data_status = 'received' and trunc(data_date) = date '2016-04-05'
group by trim(data_date);
gives results like:
347 05-APR-16
Why are the queries giving different results for the same day?
Because your man_date_sub values are not all at midnight. If you keep running the first query the number of records returned will (probably) gradually reduce. That is only happening to the count for the 5th as that is a week ago. Your sysdate - 7 is a moving target, not just as you move from day to day, but as time passes during the day.
You can check the times with:
select to_char(man_date_sub, 'YYYY-MM-DD HH24:MI:SS'),
to_char(sysdate - 7, 'YYYY-MM-DD HH24:MI:SS'),
man_date_sub - (sysdate - 7)
from man
where trunc(man_date_sub) = date '2016-04-05';
You'll see that some have times before the current sysdate time, while others have times after it. The third, generated, column will show some positive and some negative values.
In your second query you're comparing trunc(man_date_sub), which sets the time part to midnight, with date '2016-04-05', which is also at midnight; so all the records at any time on that day now match.
You can go back to midnight on your 7-day range, and get an equivalent result, by truncating sysdate:
select count(*), trim(man_date_sub)
from man
where man_status = 'SUBMITTED' and man_date_sub > trunc(sysdate)-7
group by trim(man_date_sub);
Your use of the trim() function is a bit odd; all you're doing is removing leading and trailing whitespace from the string '05-APR-16', which isn't actually doing anything. You're also relying on implcit conversion of the date to a string using your session NLS_DATE_FORMAT. It would be better to specify the format:
select count(*), to_char(man_date_sub, 'YYYY-MM-DD')
from man
where man_status = 'SUBMITTED' and man_date_sub > trunc(sysdate)-7
group by to_char(man_date_sub, 'YYYY-MM-DD');
If you ran your original query in a session that had an NLS_DATE_FORMAT that included time elements then you wouldn't get the result you expect.
I'm not sure if you're confusing it with trunc(), though clearly you're using that elsewhere. Truncating a date sets the time portion to midnight (by default; it can do other things), but leaves it as a date, which would be suitable for grouping but should still be formatted explicitly for display.

VB.net SQL statement to query 1 yr old Timestamp

I want to display in my gridview all data whose timestamp is not older than 1 years from current date.
My timestamp is formatted like so: 20110125-071830 or yyyymmdd-hhmmss
I have tried to reference :
Retrieve rows less than a day old:
Select * from table_name WHERE DATE(timestampVal) > DATE(NOW() - INTERVAL 1 YEAR);
but got missing expression flag
I also tried various others; however, my timestampVal is different simply by how it is formatted.
Like for example: https://community.oracle.com/thread/2207956
With coding: Select * from table_name WHERE timestampVal < sysdate - interval '1' year ;
but get error: literal does not match format string which means sysdate can't read how mine is formatted.
How do I query my timestamp to pull all that are a year or less old?
FYI: timestampVal is string type [varchar]
It looks like the following should work:
Select *
from table_name
WHERE TO_DATE(timestampVal, 'YYYYMMDD-HH24MISS') > sysdate - interval '1' year;
Also note that I reversed the comparison: you indicated that you want rows where timestampVal is not older than 1 year ago - so timestampVal should be greater (newer) than current time minus one year.
Give that a try.
Best of luck.

In MonetDB, how can I get the date as an integer?

I want to be able to do something like
SELECT cast(my_date_col AS int) FROM my_table;
I would like to get the integer which MonetDB uses internally, i.e. the value you'd find if you looked into the BAT structure and got the appropriate element in code in MonetDB's GDK. Now, AFAICT, this internal value is the number of days since the Epoch, being Jan 1st on "Year 0" (so January 3rdt year 2 would be 366+365+2 = 732).
The best I could actually manage is
SELECT my_date_col AS int - cast('1-1-1' AS date) - 366 FROM my_table;
As MonetDB won't accept "Year zero" dates. This is rather an ugly hack, I'd like to do better. Help me?
If you're trying to get the number of days between "my_date_col" and 1970-01-01, in standard SQL you'd just subtract the one from the other. Your platform, monetdb, seems to support this syntax, but I don't have it installed. I wrote these examples in PostgreSQL.
select current_date - date '1970-01-01' as num_days;
num_days
--
16213
Check that result by adding 16213 days to the current date (2014-05-23).
select cast ((date '1970-01-01' + interval '16213' day) as date) as target_date
target_date
--
2014-05-23
The cast is necessary, because the result of this addition is a timestamp, not a date.
In your case, you want a column name instead of "current_date". So you're looking for something along these lines.
select my_date_col - date '1970-01-01' as num_days
from your-table-name;

Compare date + time with timestamp

I have a table with two temporal columns. First (name is DATE) is storing the date (not including the time part) and therefor the datatype is DATE. Second column (name is TIME) is for storing the time in seconds and therefor the datatype is NUMBER.
I need to compare this two dates with a timestamp from another table. How can I calculate the date of the two columns (DATE and TIME) and compare to the timestamp of the other table?
I have tried to calculate the hours out of the time column and add it to the date column, but the output seems not correct:
SELECT to_date(date + (time/3600), 'dd-mm-yy hh24:mi:ss') FROM mytable;
The output is just the date, but not the time component.
You can use the INTERVAL DAY TO SECOND type:
SELECT your_date + NUMTODSINTERVAL(your_time_in_seconds, 'SECOND') FROM dual;
Example:
SELECT TRUNC(SYSDATE) + NUMTODSINTERVAL(39687, 'SECOND') FROM dual;
The calculated date with time is: 10-11-2013 11:01:27
This is a better idea than dividing your value by 3600 in my opinion, as you have an interval in seconds, so it feels natural to use an interval to represent your time, which can then be easily added to a column of DATE datatype.
Oracle Interval in Documentation
NUMTODSINTERVAL Function in documentation
date + (time/3600) is already a DATE, so you don't need to do to_date(). It does have the time part you added though, you just aren't displaying it. If you want to output that as a string in the format you've shown, use to_char() instead:
SELECT to_char(date + (time/3600), 'dd-mm-yy hh24:mi:ss') FROM mytable;
... except that if time is actually in seconds, you need to divide by 86400 (24x60x60), not 3600. At the moment you're relying on your client's default date format, probably NLS_DATE_FORMAT, which doesn't include the time portion from what you've said. That doesn't mean the time isn't there, it just isn't displayed.
But that is just for display. Leave it as a date, by just adding the two values, when comparing against you timestamp, e.g.
WHERE date + (time/86400) < systimestamp
Try like this,
SELECT TO_DATE('11/11/2013','dd/mm/yyyy') + 3600/60/60/24 FROM DUAL;
Your query,
SELECT date + time/60/60/24 FROM mytable;
try using to_timestamp instead of to_date