working with a date in SQL - sql

i know this query is not right, and kind of jumbled. but it sort of displays what i want to do. what I'm trying to figure out is how to use the current date in a query. basically i want to subtract a stored date from the current date and if the result is < 30 do something. but i obviously don't know how to work with dates.... i am assuming that it shouldn't be a char value, but if i just use sys date oracle gives me a table error.
select e.STUDENT_ID
from COURSES c, CLASS_ENROLLMENT e, (SELECT TO_CHAR (SYSDATE, 'MM-DD-YYYY') as now
FROM DUAL) t
where t - c.END_DATE <= 30;

Assuming the rest of your query is correct this should solve your date problem:
select e.STUDENT_ID
from COURSES c, CLASS_ENROLLMENT e
where to_date(to_char(sysdate, 'DD-MON-RR')) - c.END_DATE <= 30;
You don't need to select sysdate from dual unless you just want to display it for one reason or another without querying something else. You can just specify it as sysdate as part of a any query anywhere.
The reason I converted it to a character and then to a date in this case is just to remove the time from sysdate, this way it will be 30 days from the given day, regardless of time. If you didn't care about time you could just say sysdate - c.end_date <=30
As an fyi - you probably need to add join conditions between the COURSES and CLASS_ENROLLMENT tables. The above should not result in a sql error and should do you want with respect to the date of the records, but it's unlikely to be what you want (in full).

Related

How to Group by Current day and Count Rows?

Hello I have table "os_txn.pay_link" and inside there are many columns.
What I want to do is that I want to count the row numbers by looking at "merchant_id" column for the current day.
So for example what I am looking for an output is that today one of "merchant_id" has
"8" rows. So I want to know the number of rows of the "merchant_id" column for current day.
I think I should use count(*) in view with select statement but couldnt succeed about syntax. So I am open your suggestions thank you.
If I understood you correctly, a simple option would be
select merchant_id, count(*)
from os_txn.pay_link
where date_column = trunc(sysdate)
group by merchant_id;
presuming that date_column contains date only (i.e. for today, 8th of October 2022, that's its value - no hours, minutes or seconds).
If date column contains time component, again - a simple option - would be
select merchant_id, count(*)
from os_txn.pay_link
where trunc(date_column) = trunc(sysdate)
group by merchant_id;
If there's an index on date_column, then such a code wouldn't use it (unless it is a function-based index) so you'd rather modify it to
where date_column >= trunc(sysdate)
and date_column < trunc(sysdate + 1)
If that's not it, do post sample data and desired result.

Optimization on large tables

I have the following query that joins two large tables. I am trying to join on patient_id and records that are not older than 30 days.
select * from
chairs c
join data id
on c.patient_id = id.patient_id
and to_date(c.from_date, 'YYYYMMDD') - to_date(id.from_date, 'YYYYMMDD') >= 0
and to_date (c.from_date, 'YYYYMMDD') - to_date(id.from_date, 'YYYYMMDD') < 30
Currently, this query takes 2 hours to run. What indexes can I create on these tables for this query to run faster.
I will take a shot in the dark, because as others said it depends on what the table structure, indices, and the output of the planner is.
The most obvious thing here is that as long as it is possible, you want to represent dates as some date datatype instead of strings. That is the first and most important change you should make here. No index can save you if you transform strings. Because very likely, the problem is not the patient_id, it's your date calculation.
Other than that, forcing hash joins on the patient_id and then doing the filtering could help if for some reason the planner decided to do nested loops for that condition. But that is for after you fixed your date representation AND you still have a problem AND you see that the planner does nested loops on that attribute.
Some observations if you are stuck with string fields for the dates:
YYYYMMDD date strings are ordered and can be used for <,> and =.
Building strings from the data in chairs to use to JOIN on data will make good use of an index like one on data for patient_id, from_date.
So my suggestion would be to write expressions that build the date strings you want to use in the JOIN. Or to put it another way: do not transform the child table data from a string to something else.
Example expression that takes 30 days off a string date and returns a string date:
select to_char(to_date('20200112', 'YYYYMMDD') - INTERVAL '30 DAYS','YYYYMMDD')
Untested:
select * from
chairs c
join data id
on c.patient_id = id.patient_id
and id.from_date between to_char(to_date(c.from_date, 'YYYYMMDD') - INTERVAL '30 DAYS','YYYYMMDD')
and c.from_date
For this query:
select *
from chairs c join data
id
on c.patient_id = id.patient_id and
to_date(c.from_date, 'YYYYMMDD') - to_date(id.from_date, 'YYYYMMDD') >= 0 and
to_date (c.from_date, 'YYYYMMDD') - to_date(id.from_date, 'YYYYMMDD') < 30;
You should start with indexes on (patient_id, from_date) -- you can put them in both tables.
The date comparisons are problematic. Storing the values as actual dates can help. But it is not a 100% solution because comparison operations are still needed.
Depending on what you are actually trying to accomplish there might be other ways of writing the query. I might encourage you to ask a new question, providing sample data, desired results, and a clear explanation of what you really want. For instance, this query is likely to return a lot of rows. And that just takes time as well.
Your query have a non SERGABLE predicate because it uses functions that are iteratively executed. You need to discard such functions and replace them by a direct access to the columns. As an exemple :
SELECT *
FROM chairs AS c
JOIN data AS id
ON c.patient_id = id.patient_id
AND c.from_date BETWEEN id.from_date AND id.from_date + INTERVAL '1 day'
Will run faster with those two indexes :
CREATE X_SQLpro_001 ON chairs (patient_id, from_date);
CREATE X_SQLpro_002 ON data (patient_id, from_date) ;
Also try to avoid
SELECT *
And list only the necessary columns

Oracle Count number of records each hour [duplicate]

This question already has answers here:
Counting number of records hour by hour between two dates in oracle
(5 answers)
Closed 8 years ago.
I'm trying to get the number of records created each hour but running into trouble with getting the results to group correctly. The idea is similiar to: How to count number of records per day?
However, the field I'm using to Group by is a Date-time field that records down to the second. This seems to be causing trouble with the Group By statement, as when the query returns, there is one row for each second in the specified time period, which is way too much data and will make the work I want to do with the results more difficult than it needs to be (if for no other reason that it's too many rows to fit on one Excel sheet).
My current code is:
SELECT ASD, Count(ASD) Num_CR
From DB_Name.Table_Name fcr
Where trunc(fcr.ASD) > to_Char('31-DEC-2014')
And trunc(fcr.ASD) < to_Char('31-JAN-2015')
And fcr.Status_Code = 'C'
Group By ASD
Order By ASD;
I've tried changing the Group By to be trunc(ASD), but that results in Toad throwing this error: ORA-00979: not a GROUP BY expression.
Thanks in advance!
When you use aggregation anything in the select and order by clauses must match what's in the group by clause:
SELECT trunc(ASD,'hh'), Count(ASD) Num_CR
From DB_Name.Table_Name fcr
Where trunc(fcr.ASD) > to_date('31-DEC-2014')
And trunc(fcr.ASD) < to_date('31-JAN-2015')
And fcr.Status_Code = 'C'
Group By trunc(ASD,'hh')
Order By trunc(ASD,'hh');
When applied to a date, trunc will truncate to the day. To truncate to a different level, specify the format of the element you'd like to truncate to as the second argument (e.g. 'hh' will truncate to the hour; 'mm' will truncate to the month).
SELECT to_char(ASD,'DD-MM-YYYY HH'), Count(ASD) Num_CR
From DB_Name.Table_Name fcr
Where trunc(fcr.ASD) > to_Char('31-DEC-2014')
And trunc(fcr.ASD) < to_Char('31-JAN-2015')
And fcr.Status_Code = 'C'
Group By to_char(ASD,'DD-MM-YYYY HH')
Order By to_char(ASD,'DD-MM-YYYY HH');
Quick and dirty :)
First off, why are you doing to_char on something that's already a string? Secondly, why are you trying to compare something that's (presumably) a DATE column to a string? That way lies madness...
I think you're after something like:
SELECT trunc(ASD, 'hh') asd_hr, Count(ASD) Num_CR
From DB_Name.Table_Name fcr
Where trunc(fcr.ASD) > to_date('31/12/2014', 'dd/mm/yyyy')
And trunc(fcr.ASD) < to_date('31/01/2015', 'dd/mm/yyyy')
And fcr.Status_Code = 'C'
Group By trunc(ASD, 'hh')
Order By trunc(ASD, 'hh');
Also worth noting, did you mean to exclude the last day of January from your query? If so, then fine, but if not, then perhaps you should change it to to_date('01/02/2015', 'dd/mm/yyyy')

SQL count for the current 7 days

I want to get a list of the number of orders entered to our database for the last 7 days. I've tried repeating the below but it becomes some error messages about incorrect format, so I'm wondering what's the correct method.
To get order amount for current day I use SELECT COUNT(order_number) FROM orders WHERE created = TO_CHAR(sysdate, 'DD-MON-YYYY');
I want a table like:
Date Total Orders
sysdate 500
sysdate-1 400
sysdate-2 300
etc. for the last 7 days. Is it possible?
I believe the following would work for you:
Select created, count(ordernumber)
From orders
Where to_date(created, 'DD-MON-YYYY') between trunc(sysdate-7) and trunc(sysdate)
Group by created
Order by to_date(created, 'DD-MON-YYYY') desc
Note, if you can change it I would seriously consider using a DATE column for created.
You should have mentioned the specific error. I guess created is a date field and you are trying to compare it with a string. If this is the case, here is the statement needed. TRUNC removes the time part from the date.
SELECT TRUNC(created), COUNT(order_number)
FROM orders
WHERE TRUNC(created) BETWEEN TRUNC(sysdate) - 6 AND TRUNC(sysdate)
GROUP BY TRUNC(created)
ORDER BY TRUNC(created);

PLSQL - trunc function - booking due within 24 hours

I was just wondering how would I go about checking to see if, for example, a booking is due within 24 hours?
My bookings table will have the important fields that may help in finding the solution: studiono, title, date, time, hour
At the moment, I have tried the following:
select StudioNo
from Bookings
where sysdate - "DATE" <1
and "TIME" - trunc("Time") + trunc(systimestamp) > systimestamp;
However, I don't think this works. Am I doing this correctly?
Any help is appreciated.
Without knowing what your database structure is:
select StudioNo
from Bookings
where to_date(date || time, 'dd-mon-yyyyhh24:mi:ss') < sysdate +1
and to_date(date || time, 'dd-mon-yyyyhh24:mi:ss') > sysdate
basically, create a single date/time field from your 2 seperate date and time columns (which I'm assuming here are strings), and then compare that to sysdate + 1
Firstly, is there any particular reason why your Bookings table has separate columns for date and time? The Oracle datatype DATE will include both of these in a single column. This will then make the required query much more straight forward:
SELECT StudioNo
FROM Bookings
WHERE BookingDate BETWEEN SYSDATE AND SYSDATE+1;