Select and group multiple range of dates in oracle SQL - sql

I want to Select the same range of dates and group them by year. In this case I want the total of the bills of a customer per year from September and October.
My Code right now:
SELECT c.name, c.telefonnumber, TO_CHAR(b.billdate, 'YYYY'), sum(b.sume)
FROM customer c, bill b
WHERE b.customerId = c.id
AND b.datum BETWEEN '01.10.2016' AND '30.09.2016'
GROUP BY c.name, c.telefonnumber, TO_CHAR(b.billdate, 'YYYY');
This Query works perfectly but when I want to add another year the result is an endless loop:
AND b.datum BETWEEN '01.10.2016' AND '30.09.2016'
OR b.datum BETWEEN '01.10.2015' AND '30.09.2015'
I also tried to do it in a String way. In this case when I only look for the results of September it works perfectly, but again as soon as I add the OR it becomes again an endless loop:
AND TO_CHAR(kp.tmstmp) LIKE '%.09.%'
OR TO_CHAR(kp.tmstmp) LIKE '%.10.%'
I know I am somehow missing something in the OR operator, but since this is only happening me with dates I am a bit confused.

This query works fine and return 0 rows, I guess - exactly the number of dates between 01.10.2016 and 30.09.2016 :)
If you wish to check several ranges, you should enclose them into braces:
... and
(
b.datum between date '2016-10-01' and date '2017-09-30' or
b.datum between date '2015-10-01' and date '2016-09-30' or
...
) and
...

It looks like your date criteria in the WHERE clause are being phrased incorrectly. Try this instead:
SELECT c.name, c.telefonnumber, TO_CHAR(b.billdate, 'YYYY'), sum(b.sume)
FROM customer c, bill b
WHERE b.customerId = c.id AND
(b.datum BETWEEN TO_DATE('01.10.2016', 'DD.MM.YYYY') AND
TO_DATE('30.09.2016', 'DD.MM.YYYY') OR
b.datum BETWEEN TO_DATE('01.10.2015', 'DD.MM.YYYY') AND
TO_DATE('30.09.2015', 'DD.MM.YYYY'));
I made two changes, namely making certain that the date checks occur in one logical place, surrounded by outer parentheses, and that we use bona fide dates when comparing against the datum column.

Related

To_char ,To_date

how do you become conform with this code, only dates of 2019 appear to me? You are not changing To_char.
SELECT GUEST.GNO, GUEST.GLASTNAME, GUEST.GFIRSTNAME, BOOKING.gNO, BOOKING.GINDATE
FROM GUEST, BOOKING
WHERE GUEST.GNO = BOOKING.gNO AND BOOKING.GINDATE = TO_CHAR (GINDATE,'DD/MM/YYYY');
I am interpreting your query as you want bookings in 2019. If so, then query should look more like this:
SELECT g.GNO, g.GLASTNAME, g.GFIRSTNAME, b.gNO, b.GINDATE
FROM GUEST g JOIN
BOOKING b
ON g.GNO = b.gNO
WHERE b.GINDATE >= DATE '2019-01-01' AND
b.GINDATE < DATE '2020-01-01';
Of course, there might be slight variations depending on your database.

Can someone help me with this join

I need it to give me me a total of 0 for week 33 - 39, but I'm really bad with joining 3 tables and I cant figure it out
Right now it only gives me an answer for dates that there are actual records in the tracker_weld_table.
SELECT SUM(tracker_parts_archive.weight),
WEEK(mycal.dt) as week
FROM
tracker_parts_archive, tracker_weld_archive
RIGHT JOIN
(SELECT dt FROM calendar_table WHERE dt >= '2018-7-1' AND dt <= '2018-10-1') as mycal
ON
weld_worker = '133'AND date(weld_dateandtime) = mycal.dt
WHERE
tracker_weld_archive.tracker_partsID = tracker_parts_archive.id
GROUP BY week
I think you are trying for something like this:
SELECT WEEK(c.dt) as week, COALESCE(SUM(tpa.weight), 0)
FROM calendar_table c left join
tracker_weld_archive tw
on date(tw.weld_dateandtime) = c.dt left join
tracker_parts_archive tp
on tw.tracker_partsID = tp.id and tp.weld_worker = 133
WHERE c.dt >= '2018-07-01' AND c.dt <= '2018-10-01'
GROUP BY week
ORDER BY week;
Notes:
You want to keep all (matching) rows in the calendar table, so it should be first.
All subsequent joins should be LEFT JOINs.
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
Write out the full proper date constant -- YYYY-MM-DD. This is an ISO-standard format.
I am guessing that weld_worker is a number, so single quotes are not needed for the comparison.
First, lets start with understanding what you want.. You want totals per week. This means there will be a "GROUP BY" clause (also for any MIN(), MAX(), AVG(), SUM(), COUNT(), etc. aggregates). What is the group BY basis. In this scenario, you want per week. Leading to the next part that you want for a specific date range qualified per your calendar table.
I would start in order what WHAT filtering criteria first. Also, ALWAYS TRY to identify all table( or alias).column in your queries so anyone after you knows where the columns are coming from, especially when multiple tables. In this case "ct" is the ALIAS for "Calendar_Table"
SELECT
ct.dt
from
calendar_table ct
where
ct.dt >= '2018-07-01'
AND ct.dt <= '2018-10-01'
Now, the above date looks to be INCLUSIVE of October 1 and looks like you are trying to generate a quarterly sum from July, Aug, Sept. I would change to LESS than Oct 1.
Now, your calendar has many days and you want it grouped by week, so the WEEK() function gets you that distinct reference without explicitly checking every date. Also, try NOT to use reserved keywords as final column names... makes for confusion later on sometimes.
I have aliased the column name as "WeekBasis". Here, I did a COUNT(*) just to show the total days and the group by showing it in context.
SELECT
WEEK( ct.dt ) WeekBasis,
MIN( ct.dt ) as FirstDayOfThisWeek,
MAX( ct.dt ) as LastDayOfThisWeek,
COUNT(*) as DaysInThisWeek
from
calendar_table ct
where
ct.dt >= '2018-07-01'
AND ct.dt <= '2018-10-01'
group by
WEEK( ct.dt )
So, at this point, we have 1 record per week within the date period you are concerned,
but I also grabbed the earliest and latest dates just to show other components too.
Now, lets get back to your extra tables. We know the dates in question, now need to
get the details from the other tables (which is lacking in the post. You should post
critical components such as how tables are related via common / joined column basis.
How is tracker_part_archive related to tracker_weld_archive??
To simplify your query, you dont even NEED your calendar table as the welding
table HAS a date field and you know your range. Just query against that directly.
IF your worker's ID is numeric, don't add quotes around it, just leave as a number.
SELECT
WEEK( twa.Weld_DateAndTime ) WeekBasis,
COUNT(*) WeldingEntriesDone,
SUM(tpa.weight) TotalWeight
from
tracker_weld_archive twa
JOIN tracker_parts_archive tpa
-- GUESSING on therelationship here.
-- may also be on a given date too???
-- all pieces welded by a person on a given date
ON twa.weld_worker = tpa.weld_worker
AND twa.Weld_DateAndTime = tpa.Weld_DateAndTime
where
twa.Weld_Worker = 133
AND twa.Weld_DateAndTime >= '2018-07-01'
AND twa.Weld_DateAndTime <= '2018-10-01'
group by
WEEK( twa.Weld_DateAndTime )
IF you provide the table structures AND sample data, this can be refined a bit more for you.

ORA-00907: missing right parenthesis using count with expression inside it

SELECT Hotel_Name, COUNT(H_CHECK.Hotel_checkIn >= 'JUL-1-2016' AND H_CHECK.Hotel_checkIn <= 'JUL-31-2016') FROM HOTEL, H_CHECK
GROUP BY Hotel_Name
ORA-00907: missing right parenthesis
I have tried putting Parenthesis in many ways, but I couldn't find the solution. I'm using Oracle Application Express 11G.
This is the query:
Display the hotel name that has more than 2 customers checked in on July 2016.
Once you fix your immediate syntax problem, you need proper JOIN syntax.
One way to fix the problem is simply to move the conditions to a WHERE clause, resulting in a query like this:
SELECT Hotel_Name, COUNT(hc.hotel_id)
FROM HOTEL h LEFT JOIN
H_CHECK hc
ON h.hotel_id = hc.hotel_id -- I don't know what the right join condition is
WHERE hc.Hotel_checkIn >= DATE '2016-07-01' AND
hc.Hotel_checkIn <= DATE '2016-07-31'
GROUP BY Hotel_Name;
You cannot count based on condition in Select statement of your sql query.
COUNT (
H_CHECK.Hotel_checkIn >= 'JUL-1-2016'
AND H_CHECK.Hotel_checkIn <= 'JUL-31-2016')
This is wrong. You can do it like>
SELECT Hotel_Name,
COUNT (1)
FROM HOTEL
join H_CHECK
ON H_CHECK.Hotel_checkIn >= 'JUL-1-2016'
AND H_CHECK.Hotel_checkIn <= 'JUL-31-2016'
GROUP BY Hotel_Name
having count(1) > 2;
You're missing the CASE ... END from your conditions inside your count. You're after something like:
SELECT Hotel_Name,
COUNT(case when H_CHECK.Hotel_checkIn >= 'JUL-1-2016'
AND H_CHECK.Hotel_checkIn <= 'JUL-31-2016'
then 1
end)
FROM HOTEL, H_CHECK
GROUP BY Hotel_Name;
However, there are a number of concerns I have regarding your query:
if your hotel_checkin column is of DATE datatype, then you should be comparing it to DATEs not strings. I.e. H_CHECK.Hotel_checkIn >= to_date('07-01-2016', 'mm-dd-yyyy') - this way, you avoid relying on implicit conversion of the string into a date, which relies on your NLS_DATE_FORMAT parameter setting. This could be changed and may cause your query to fail.
FROM HOTEL, H_CHECK Don't use the old-style method of joining; instead, use the ANSI style method: FROM hotel cross join h_check
Did you really mean the join to be a cross join or did you forget to add the join conditions?
You should alias the hotel_name column to aid maintainability.
You should also give your count column a name.
Since you're only counting rows with a checkin between 1st and 31st July 2016, you should move this condition into the where clause (as XING has shown in their answer) *unless* you need to also show hotels that don't have any checkins within that time period.
Your condition assumes that there are no time elements to the hotel_checkin column - ie. everything is set to midnight. If, however, you could have a date with a time, bear in mind that your count will ignore all rows with a checkin date of 31st July 2016 that are after midnight. In which case, your upper bound needs to change to: H_CHECK.Hotel_checkIn < to_date('08-01-2016', 'mm-dd-yyyy')

working with a date in 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).

Show data that is only from a specific quarter

I need to show the data that is only from the 2nd quarter of any year. I am trying to use to_date in the where clause but it is giving me an error. Not sure what I am doing wrong. (Using Oracle 10g)
Code:
SELECT product_name, name
FROM a_product p JOIN a_item i
ON p.product_id=i.product_id
JOIN a_sales_order so ON i.order_id=so.order_id
JOIN a_customer c ON so.customer_id=c.customer_id
WHERE regexp_like(product_name, 'Transducer') AND order_date=to_date(2, 'Q')
The AND portion is where I am having trouble, it is giving me a "format code cannot appear in date input format" order_date is the field within the table that I use to find out what sales were done in quarter 2 of any year.
You have the arguments backwards. You want that to be:
AND to_char(order_date, 'Q') = '2'
The function to_char() (in this context) takes a date and formats it as a string. What string? A string with the quarter in it. You then want to compare it to the value you care about.