Oracle sql group function issues - sql

Find Melbourne VIP level 4 customers’ first name, last name who have hired the vehicle model as “Ranger ” at least 2 times in database. You write three different queries: one is using operator EXISTS and the other one is using operator IN. The third query with the main filter criteria in FROM clause of the main query or filter criteria in the sub-query. Find one with the better performance.
I Have tried this query;
SELECT c_fname, c_fname FROM rental WHERE
EXISTS(SELECT c_id FROM customer WHERE c_city = 'Melbourne' AND customer.vip_level = '4')
AND EXISTS (SELECT vehicle_reg FROM vehicle WHERE v_model = 'Ranger')
HAVING COUNT(c_id)>=2 GROUP BY c_lname, c_fname;
I am getting error: SQL Error: ORA-00934: group function is not allowed here
00934. 00000 - "group function is not allowed here"
can anyone help me with this question. really struggled to get this done?

You are selecting from the wrong subject table as Rental does not have c_fname or c_lname columns.
You want to "Find Melbourne VIP level 4 customers’ first name, last name" which would be in the customer table:
SELECT c_fname,
c_lname
FROM customer
WHERE c_city = 'Melbourne'
AND vip_level = 4;
Then you want to add an additional filter "who have hired the vehicle model as “Ranger ” at least 2 times in database". That requires you to use EXISTS (for the answer for the first query) and you need to correlate between the outer-query and the sub-query; once you have done that then you do not need a GROUP BY clause and you are aggregating over the entire result set of the sub-query and can just use a HAVING clause.
SELECT c_fname,
c_lname
FROM customer c
WHERE c_city = 'Melbourne'
AND vip_level = 4
AND EXISTS(
SELECT 1
FROM rental r
INNER JOIN vehicle v
ON (r.vehicle_reg = v.vehicle_reg)
WHERE c.c_id = r.c_id
AND v.v_model = 'Ranger'
HAVING COUNT(*) >= 2
);
Then you need to write the same query using IN instead of EXISTS and the same query a third time using JOIN conditions instead of IN or EXISTS and, finally, you need to compare the performance of all three queries.

Related

Connecting multiple queries and passing criteria from one query to another

I am trying to put together a query that will basically run another query on each return.
My current query puts together important info for each client, such as how long an average groom takes and the description of the type of haircut they get:
SELECT Query11.petId AS PetID,
Query11.petName AS PetName,
dbo_Customer.cstLName AS LastName,
Query11.lstValue AS Breed,
qryFindsPetAvgApptTime.TotalAppts,
dbo_vwPetGroom.pgrName AS GroomStyle,
dbo_ListValues.lstValue AS Haircut,
ROUND([AvgPTime]) AS AvgPrep,
ROUND([AvgBTime]) AS AvgBath,
ROUND([AvgDTime]) AS AvgDry,
ROUND([AvgGTime]) AS AvgGroom,
[AvgPrep] + [AvgBath] + [AvgDry] + [AvgGroom] AS AvgMinutes,
qryFindsPetAvgApptTime.AvgHours
FROM((Query11
LEFT JOIN qryFindsPetAvgApptTime ON Query11.petId = qryFindsPetAvgApptTime.PetID)
LEFT JOIN dbo_Customer ON Query11.petCustId = dbo_Customer.cstId)
LEFT JOIN (dbo_vwPetGroom
LEFT JOIN dbo_ListValues ON dbo_vwPetGroom.pgrLengthHairBodyLid = dbo_ListValues.lstId)
ON Query11.petId = dbo_vwPetGroom.pgrPetId;
I want to add in the average length between grooming appts to the above query info. Right now that is done in 2 seperate queries.
The first one pulls days between appts:
SELECT tblTimeLog.PetID,
tblTimeLog.PetName,
[ApptDate] - (SELECT MAX(T.ApptDate)
FROM tblTimeLog T
WHERE T.PetID = tblTimeLog.PetID
AND T.ApptDate < tblTimeLog.ApptDate) AS Diff,
tblTimeLog.ApptDate
FROM tblTimeLog
WHERE (((tblTimeLog.PetID) = [Enter PetID]))
ORDER BY tblTimeLog.ApptDate;
And then averaged out with this:
SELECT qryTimeLogDiffs.PetID,
qryTimeLogDiffs.PetName,
AVG(qryTimeLogDiffs.Diff) AS AvgOfDiff
FROM qryTimeLogDiffs
GROUP BY qryTimeLogDiffs.PetID,
qryTimeLogDiffs.PetName;
Is there a way to pass the PetID criteria from each return into the second query so it adds the average span between appts to the info in the first query??
Consider refactoring your second query to avoid the taxing correlated aggregate subquery. One approach involves first running an aggregate query based on a self join to return last appointment date for each PetID.
Even better, turn this query into an action query to populate a temporary table either with make-table query as shown below using INTO or regularly cleaning out a persistent table via delete and insert-select query:
SELECT curr.PetID,
curr.PetName,
curr.ApptDate,
MAX(prev.[AppDate]) AS MaxPrevDate
INTO lastApptTimeLog
FROM tblTimeLog AS curr
INNER JOIN tblTimeLog AS prev
ON curr.PetID = prev.PetID
WHERE prev.ApptDate < curr.AppDate
GROUP BY curr.PetID,
curr.PetName,
curr.ApptDate;
Then, base third aggregate query on this temp table and run the difference calculation. Finally, incorporate this query into first query.
SELECT PetID,
PetName,
AVG(ApptDate - MaxPrevDate) AS AvgOfDiff
FROM lastApptTimeLog
GROUP BY PetID,
PetName;

SQL - Returning fields based on where clause then joining same table to return max value?

I have a table named Ticket Numbers, which (for this example) contain the columns:
Ticket_Number
Assigned_Group
Assigned_Group_Sequence_No
Reported_Date
Each ticket number could contain 4 rows, depending on how many times the ticket changed assigned groups. Some of these rows could contain an assigned group of "Desktop Support," but some may not. Here is an example:
Example of raw data
What I am trying to accomplish is to get the an output that contains any ticket numbers that contain 'Desktop Support', but also the assigned group of the max sequence number. Here is what I am trying to accomplish with SQL:
Queried Data
I'm trying to use SQL with the following query but have no clue what I'm doing wrong:
select ih.incident_number,ih.assigned_group, incident_history2.maxseq, incident_history2.assigned_group
from incident_history_public as ih
left join
(
select max(assigned_group_seq_no) maxseq, incident_number, assigned_group
from incident_history_public
group by incident_number, assigned_group
) incident_history2
on ih.incident_number = incident_history2.incident_number
and ih.assigned_group_seq_no = incident_history2.maxseq
where ih.ASSIGNED_GROUP LIKE '%DS%'
Does anyone know what I am doing wrong?
You might want to create a proper alias for incident_history. e.g.
from incident_history as incident_history1
and
on incident_history1.ticket_number = incident_history2.ticket_number
and incident_history1.assigned_group_seq_no = incident_history2.maxseq
In my humble opinion a first error could be that I don't see any column named "incident_history2.assigned_group".
I would try to use common table expression, to get only ticket number that contains "Desktop_support":
WITH desktop as (
SELECT distinct Ticket_Number
FROM incident_history
WHERE Assigned_Group = "Desktop Support"
),
Than an Inner Join of the result with your inner table to get ticket number and maxSeq, so in a second moment you can get also the "MAXGroup":
WITH tmp AS (
SELECT i2.Ticket_Number, i2.maxseq
FROM desktop D inner join
(SELECT Ticket_number, max(assigned_group_seq_no) as maxseq
FROM incident_history
GROUP BY ticket_number) as i2
ON D.Ticket_Number = i2.Ticket_Number
)
SELECT i.Ticket_Number, i.Assigned_Group as MAX_Group, T.maxseq, i.Reported_Date
FROM tmp T inner join incident_history i
ON T.Ticket_Number = i.Ticket_Number and i.assigned_group_seq_no = T.maxseq
I think there are several different method to resolve this question, but I really hope it's helpful for you!
For more information about Common Table Expression: https://www.essentialsql.com/introduction-common-table-expressions-ctes/

How to select all rows that are related to satisfied condition in ms ACCESS

I have the following data in table VehiclesAccSummary:
I am not sure how to do this but what I want is a query that would return all rows where there where only two car in the accident and it was a head on crash so in both cars PointOfImpact was 'Front' i know in need to do some inner join on the same table but i don' want to join same car with it self. Any idea ?
The end result should be something like this
You can use a subquery to count the number of "Front' records for each AccRef.
SELECT *
FROM VehiclesAccSummary INNER JOIN
(SELECT VehiclesAccSummary.AccRef, Count(VehiclesAccSummary.PointOfImpact) AS CountOfPointOfImpact FROM VehiclesAccSummary GROUP BY VehiclesAccSummary.AccRef, VehiclesAccSummary.PointOfImpact HAVING VehiclesAccSummary.PointOfImpact="Front") AS FrontCount
ON VehiclesAccSummary.AccRef = FrontCount.AccRef
WHERE VehiclesAccSummary.NumCars = 2 AND CountOfPointOfImpact = 2;
This will limit the records to AccRefs with NumCar = 2 and the count of Front records = 2.
Edit: Since the same car can be listed in multiple records, we need a new approach. Try this:
SELECT VehiclesAccSummary.*, Subquery.CountOfPointOfImpact
FROM VehiclesAccSummary LEFT JOIN (SELECT VehiclesAccSummary.AccRef, Count(VehiclesAccSummary.PointOfImpact) AS CountOfPointOfImpact
FROM VehiclesAccSummary
WHERE (((VehiclesAccSummary.PointOfImpact)<>"Front"))
GROUP BY VehiclesAccSummary.AccRef) AS Subquery ON VehiclesAccSummary.AccRef = Subquery.AccRef
WHERE (((Subquery.CountOfPointOfImpact) Is Null));
Instead of confirming that the count of front accidents is 2, this confirms that the count of non-front accidents is 0.

SQL Math Operation In Correlated Subquery

I am working with three tables, basically, one is a bill of materials, one contains part inventory, and the last one contains work orders or jobs. I am trying to find out if it is possible to have a correlated subquery that can perform a math operation using a value from the outer query. Here's an example of what I'm trying to do:
SELECT A.work_order,A.assembly,A.job_quantity,
(SELECT COUNT(X.part_number)
FROM bom X
WHERE X.assembly = A.assembly
AND (X.quantity_required * A.job_quantity) >= (SELECT Y.quantity_available FROM inventory Y WHERE
Y.part_number = X.part_number)) AS negatives
FROM work_orders A
ORDER BY A.assembly ASC
I am attempting to find out, for a given work order, if there are parts that we do not have enough of to build the assembly. I'm currently getting an "Error correlating fields" error. Is it possible to do this kind of operation in a single query?
Try moving the subquery to a join, something like this:
SELECT a.work_order, a.assembly, a.job_quantity, n.negatives
FROM work_orders a JOIN (SELECT x.part_number, COUNT(x.part_number) as negatives
FROM bom x JOIN work_orders b
ON x.assembly = b.assembly
WHERE (x.quantity_required * b.job_quantity) >= (SELECT y.quantity_available
FROM inventory y WHERE
y.part_number = x.part_number)
GROUP BY x.part_number) n
ON a.part_number = n.part_number
ORDER BY a.assembly ASC
Or create a temporary cursor with the subquery and then use it to join the main table.
Hope this helps.
Luis

Only a single result allowed for a SELECT that is part of an expression

I have the following SQL statement. It's throws the following error: "Only a single result allowed for a SELECT that is part of an expression". The goal of my sql statement is to get the name of the employee who made the 'cheapest' bribe.
The part between the brackets return the employee_id and the money it costs a day (of the relative cheapest bribe). These are two results while I only want the employee_id. So I just want to use the MIN part to get the right employee_id. How can I do this?
SELECT Voornaam, Achternaam
FROM Medewerker m JOIN
(
SELECT Medewerker_id
FROM Steekpenning
ORDER BY -1*Bedrag/(julianday(Begindatum) - julianday(Einddatum))
limit 1
) s
on m.Medewerker_id = s.Medewerker_id;
EDITED the answer. How can I expand this query to only show the bribes started this month? I think I need to use something like this? (julianday(Begindatum) - julianday('now')) > 31 but where?
Regards.
Cas
I think the following will work in SQLite:
select Firstname, Surname
from Employee e join
(select employee_id
from bribe
order by -1*Amount/(julianday(Startdate) - julianday(Enddate))
limit 1
) b
on e.employee_id = b.employee_id;