My TO_DATE seeming not to function properly - sql

So I am trying to get the section id and the amount of students in that section who enrolled on 02/10/2007. The query returns no results when it should return 6 rows.
The date format its in already is DD-MON-YY.
This is what I have so far:
I took the TO_DATE from another query I did and it worked properly on. The query works without it so im sure its somthing to do with the TO_DATE
SELECT section_id, COUNT(student_id) "ENROLLED"
FROM enrollment
WHERE enroll_date = TO_DATE('2/10/2007', 'MM/DD/YYYY')
GROUP BY section_id
ORDER BY ENROLLED;

Most probably the issue is that there is a fractional date component that you are not taking into account. You can ignore that fractional date component by truncating the column in your query:
SELECT section_id, COUNT(student_id) "ENROLLED"
FROM enrollment
WHERE TRUNC(enroll_date) = TO_DATE('2/10/2007', 'MM/DD/YYYY')
GROUP BY section_id
ORDER BY ENROLLED;
I am assuming that the column enroll_date is of the data type DATE.
Some explanation: Oracle stores dates as described here, it does NOT store a date as you state "The date format its in already is DD-MON-YY.". That is only the format you see the date in, which is determined by the parameter NLS_DATE_FORMAT for your session.
Lets do a quick test with a test table. Create table and check the NLS_DATE_FORMAT form my session.
create table DATE_TST
( id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
test_date DATE
);
INSERT INTO date_tst (test_date) VALUES (SYSDATE);
SELECT value
FROM nls_session_parameters
WHERE parameter = 'NLS_DATE_FORMAT';
DD-MON-YYYY
This is how I will see my dates.
SELECT * FROM date_tst;
04-OCT-2020
So I have todays date. Cool. Now lets see if I can query using that date:
SELECT * FROM date_tst WHERE test_date = TO_DATE('04-OCT-2020','DD-MON-YYYY');
no rows.
No rows are shown because the date format I get my date in does not have a time component. DATE has Year, month, day, hour, minute and seconds. The format only has year, month and day. Lets query the data to check if there is a time component.
SELECT TO_CHAR(test_date,'DD-MON-YYYY HH24:MI:SS') FROM date_tst;
4-OCT-2020 21:12:39
Ah there it is... SYSDATE is the current time up to the second. Now lets try that query again with a more precise date format:
SELECT * FROM date_tst WHERE test_date = TO_DATE('04-OCT-2020 21:12:39','DD-MON-YYYY HH24:MI:SS');
04-OCT-2020
And there is our row. The TRUNC command will cut off the time component:
SELECT TO_CHAR(TRUNC(test_date),'DD-MON-YYYY HH24:MI:SS') FROM date_tst;
04-OCT-2020 00:00:00
So you can simplify your query:
SELECT * FROM date_tst WHERE TRUNC(test_date) = TO_DATE('04-OCT-2020','DD-MON-YYYY');
04-OCT-2020

TO_DATE('2/10/2007', 'MM/DD/YYYY') gives you a date at midnight; however,this will only match values at that instant. What you need to do is either:
TRUNCate the dates in your column back to midnight so that your value matches (however, this will prevent you using an index on the column and you would need to use a function-based index); or
A better solution is to use a date range starting at midnight of the day you want to match and going up-to, but not including, midnight of the next day.
You can do this using TO_DATE or using a date literal:
SELECT section_id,
COUNT(student_id) "ENROLLED"
FROM enrollment
WHERE enroll_date >= DATE '2007-02-10'
AND enroll_date < DATE '2007-02-11'
GROUP BY section_id
ORDER BY ENROLLED;
As an aside:
The date format its in already is DD-MON-YY.
Assuming that the enroll_date column has a DATE data type then this has no format; it is a binary data type consisting of 7 bytes (for century, year-of-century, month, day, hour, minute and second).
What you are seeing is the default date format the user interface applies when it displays the binary date value to the user and you can change it using:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD"T"HH24:MI:SS';
(or to whatever format you want.)
This does not change the binary data stored in the column.

Related

SQL Query required ot get records count on hourly basis

I am trying to get records from 29th April,2022 on hourly basis from Oracle DB, however with the below query I am getting records count older than 29th April as well(all previous records count as well). Can you help fine tune the query?
SELECT DISTINCT
COUNT(*),
STATUS,
TO_CHAR(LOAD_DATE,'DD-MON-YY HH24')
FROM
TARGET_HIST
WHERE
STATUS = 'A'
AND TO_CHAR(LOAD_DATE, 'DD-MON-YY HH24:MI:SS') > '29-APR-22 00:00:00'
GROUP BY
STATUS,
TO_CHAR(LOAD_DATE,'DD-MON-YY HH24')
ORDER BY
STATUS,
TO_CHAR(LOAD_DATE,'DD-MON-YY HH24');
Try this. Since you didn't provide any sample data I didn't test it for you
select trunc(load_date,'HH') "HOUR", count(*)
from target_hist
where status='A' AND
load_date between to_date('29/04/2022','DD/MM/YYYY') and to_date('29/04/2022 23:59:59','DD/MM/YYYY HH24:MI:SS');
Group by trunc(load_date,'HH')
Order by trunc(load_date,'HH')
Two problem with the same reason:
In your WHERE clause you look for rows after '29-APR-22 00:00:00', but you get rows before that.
In your ORDER BY clause you get the dates sorted in a mangled order.
This is because you have converted the datetimes to strings where '29-APR-22' comes after '01-MAY-22', but before '30-JAN-22', because '2' comes after '1' and before '3'.
If you want to sort and compare datetimes, then use datetimes. You can truncate them down to the hour with TRUNC(load_date, 'hh').
select
trunc(load_date, 'hh') as load_hour,
status,
count(*)
from target_hist
where status = 'A'
and load_date >= date '2022-04-29'
group by trunc(load_date, 'hh'), status
order by trunc(load_date, 'hh'), status;
Leave it to your app to display the datetime in the format the user wants to see it. If you need a particular format, e.g. for exporting the data into a file, you can apply TO_CHAR on the truncated datetime TO_CHAR(trunc(load_date, 'hh'),'DD-MON-YY HH24') in the select clause (and only there).
Please note that I have removed DISTINCT from the query, because there are no duplicates to remove. And I am using a date literal in the WHERE clause. And >=in order to include midnight.
This query considers all days since April 29. If you want this day only, then add and load_date < date '2022-04-30'.

how to select all entries having date 25-11-20 in oracle 11g?

sql table
here in the table above named carpooling contains a column name start_on which has date time as timestamp i have to write a query to select all the rows having date as 25-11-20 using to_char and to_date.
You write a timestamp literal like this:
timestamp '2020-11-25 00:00:00'
so the full filtering condition will be
where start_on >= timestamp '2020-11-25 00:00:00'
and start_on < timestamp '2020-11-26 00:00:00'
Note that dates and timestamps are different in Oracle, and dates include times down to the second (this is for historical reasons - originally there was only the date type, and timestamp was added much later).
Use the TRUNC function, along with date and interval literals:
SELECT *
FROM CARPOOLING
WHERE START_ON BETWEEN DATE '2020-11-25'
AND (DATE '2020-11-26' - INTERVAL '0.000001' SECOND)
You can simply use to_date, but it's recommended to remove the time when comparing the dates. Otherwise, rows having the same date, but a different time will not be selected. Removing the time can be done using TRUNC.
So you can do something like this:
SELECT * FROM carpooling
WHERE TRUNC(start_on) = TO_DATE('2020-11-25','yyyy.mm.dd');
If you don't want to check the 25th of November 2020, but another data, change the date to match your goal.

Oracle convert Timestamp to Date

I have date like :
2020/05/09T02:40:03
2020/05/16T02:40:03
2020/05/15T02:40:03
I need to convert it into Date format 'dd/mm/yyyy'.
My query
select cast(date_registered as date) as Reg_date from employee
Error:
Literal does not match format string
Note:I have also used TO_Char , TO_Date but not working
First, what you tried to convert to date is not a timestamp, it is a string.
Second, cast(... to date) does not take a format model - it simply relies on your session nls_date_format parameter, which doesn't match the string's date format. (Especially the boilerplate, hard-coded T in the middle, which has no meaning in Oracle.)
You need to_date() with an appropriate format model. Notice the handling of hardcoded string fragments (they appear in double-quotes in the format model).
select to_date(date_registered, 'yyyy/mm/dd"T"hh24:mi:ss') as reg_date
from employee;
In Oracle, a date data type is always stores as 7-bytes consisting of century, year-of-century, month, day, hours, minutes and seconds; so, asking to convert something that has year-to-seconds components to a date does not require you to do anything:
SELECT date_registered AS reg_date FROM employee
Now, if you are storing date_registered as a string data type rather than as a date data type then you need to convert using TO_DATE:
SELECT TO_DATE( date_registered, 'YYYY-MM-DD"T"HH24:MI:SS' ) AS reg_date
FROM employee
However, you should not do this and you should fix the underlying problem that you are storing dates as strings and not dates. You can solve this by converting the data type of the column:
ALTER TABLE employee ADD ( date_registered2 DATE );
UPDATE employee
SET date_registered2 = TO_DATE( date_registered, 'YYYY-MM-DD"T"HH24:MI:SS' );
ALTER TABLE employee DROP COLUMN date_registered;
ALTER TABLE employee RENAME COLUMN date_registered2 TO date_registered;
(Note: The queries below assume that you have "fixed" the table so that the date_registered column has the date data type; if you do not want to do this then you will need to include the TO_DATE conversion as well.)
If you want the output to be a date where the time component is truncated back to midnight then:
SELECT TRUNC( date_registered ) AS reg_date
FROM employee
(Note: The displayed date will still have hours, minutes and seconds components but they will all be zero after being passed through TRUNC.)
If you want it in a specific format, without the time component, then you need to output it as a formatted string (since the date data type does not have an associated format) using TO_CHAR:
SELECT TO_CHAR( date_registered, 'DD/MM/YYYY' ) AS reg_date
FROM employee
db<>fiddle here

PostgreSQL - subtract 'days' from a returned 'date' value without also returning timestamp

I'm querying a table to get some date, like so:
SELECT date - INTERVAL '10 day' AS date
FROM example_table
WHERE username = 'Bob'
LIMIT 1;
The date column in the example_table does not have a timestamp. All dates in the column are stored in the following manner:
YYYY-MM-DD
The query above will return a result like so:
2016-11-20 00:00:00.000000
It takes the date found, goes back 10 days, and returns that date. But I want it to return the date without adding the timestamp, like so:
2016-11-20
If I use INTERVAL it always seems to add a timestamp. Is there a way to only get the date?
Your query is fine (but can be simplified, as demonstrated by a_horse_with_no_name). What you are seeing is a display issue. You can format your date to a string in the relevant format using to_char():
SELECT to_char("date" - INTERVAL '10 day', 'yyyy-mm-dd') AS "date"
FROM example_table
WHERE username = 'Bob'
LIMIT 1;
Note: LIMIT without an ORDER BY does not make sense: if there is more than one record in the resultset, you actually get a random record out of them.
You can use the interval notation and convert back to a date:
SELECT (date - INTERVAL '10 day')::date AS date
You can subtract (or add) an integer from a date. That integer represents the number of days:
SELECT "date" - 10 AS "date"
FROM example_table
WHERE username = 'Bob'
LIMIT 1;

YYYYMMDD to YYYYMM in oracle

I have a column with DATE datatype in a table.
I am trying to retrieve the column values in YYYYMM format. My select query looks like below
select *
from tablename
where date column = to_char(to_date('12/31/4000','MM/DD/YYYY'),'YYYYMM');
I am getting below exception.
ORA-01847: day of month must be between 1 and last day of month
Appreciate any input on this.
I think the simplest method is:
where to_char(datecolumn, 'YYYYMM') = '400012'
Or, if you prefer:
where to_char(datecolumn, 'YYYYMM') = to_char(to_date('12/31/4000', 'MM/DD/YYYY'), 'YYYYMM');
Syntax-wise, the right hand date (to the right of the equals) is OK. But you are doing a character comparison, not a date comparison.
This works for me in multiple databases:
select to_char (to_date('12/31/4000','MM/DD/YYYY'),'YYYYMM')
from dual;
Even though your column is named DATE_COLUMN, you are comparing based on characters in the query.
So, try this instead - this compares based on dates (NOT a character comparison) and truncates off the hour, minute, ETC. so you are only comparing the DAY:
select * from DATE_TAB
where TRUNC(DATE1, 'DDD') = TRUNC(to_date('12/31/4000','MM/DD/YYYY'),'DDD');
NOTE: The DATE1 field above is a DATE field. If you're DATE_COLUMN is not a DATE field, you must
convert it to a DATE datatype first (using TO_DATE, ETC.)
Assuming that "date_column" is actually a date, and that you have an index on date_column, you can do something like this to return the data quickly (without truncating dates in all rows to do a comparison):
with dat as (
select level as id, sysdate - (level*10) as date_column
from dual
connect by level <= 100
)
select id, date_column
from dat
where date_column between to_date('11/1/2013', 'MM/DD/YYYY') and last_day(to_date('11/2013 23:59:59', 'MM/YYYY HH24:MI:SS'))
Here I just dummy up some data with dates going back a few years. This example picks all rows that have a date in the month of November 2013.
If your date_column's data-type is DATE, then use
select *
from tablename
where TO_CHAR(date_column,'YYYYMM') = to_char (to_date('12/31/4000','MM/DD/YYYY'),'YYYYMM');
If your date_column's data-type is VARCHAR, then use:
select *
from tablename
where date_column = to_char (to_date('12/31/4000','MM/DD/YYYY'),'YYYYMM');
I somehow feel your error is because you have a space between date and column as
"date column". If the field name in the table is "COLUMN", then just removing the word "DATE" from your original query would suffice, as:
select *
from tablename
where column = to_char(to_date('12/31/4000','MM/DD/YYYY'),'YYYYMM');
If your column (YYYYMMDD) is in number format, the simplest way to get YYYYMM would be
select floor(DATE/100)
from tablename;