Derrick Rose
Derrick Rose

Reputation: 674

How to have my subquery return the AVG?

I am brand new to subquerys and I wanted to have a better understanding of them. I tried to make a statement where my output would be (vehicles that have a price which is greater than the average vehicle price):

Model
-------------
Q60
Q70

However I am currently getting no lines returned and am not sure as to why. I do wish for this to be in a subquery rather than not.

Here is my statement:

SELECT t1.MODELNAME AS "Model"
FROM TBLMODEL t1
FULL JOIN TBLVEHICLE t2 ON t1.MODELID = t2.MODELID
WHERE t2.VEHICLEPRICE IN
(
  SELECT AVG(VEHICLEPRICE)    
  FROM TBLVEHICLE    
  GROUP BY VEHICLEPRICE
  HAVING AVG(VEHICLEPRICE) < VEHICLEPRICE  
);

And here is the file to which this pertains:

DROP TABLE  tblOptionDetail;
DROP TABLE  tblOption;
DROP TABLE  tblVehicle;
DROP TABLE  tblModel;
DROP TABLE  tblBrand;
DROP TABLE  tblManufacture;


CREATE TABLE tblManufacture
(
ManufactureID NUMBER(38) PRIMARY KEY,
ManufactureName CHAR(40)
);

CREATE TABLE tblBrand
(
BrandID NUMBER(38) PRIMARY KEY,
ManufactureID NUMBER(38),
BrandName CHAR(40),
FOREIGN KEY (ManufactureID) REFERENCES tblManufacture(ManufactureID)
);

CREATE TABLE tblModel
(
ModelID NUMBER(38) PRIMARY KEY,
BrandID NUMBER(38),
ModelName CHAR(40),
FOREIGN KEY (BrandID) REFERENCES tblBrand(BrandID)
);

CREATE TABLE tblVehicle
(
VehicleID NUMBER(38) PRIMARY KEY,
ModelID NUMBER(38),
VehicleYear NUMBER(38) CHECK (VehicleYear BETWEEN 1900 and 3000),
VehicleKM NUMBER(38) CHECK (VehicleKM BETWEEN 0 and 100000000),
VehiclePrice NUMBER(38) CONSTRAINT carprice CHECK (VehiclePrice BETWEEN 0 and 1000000),
FOREIGN KEY (ModelID) REFERENCES tblModel(ModelID)
);

CREATE TABLE tblOption
(
OptionID NUMBER(38) PRIMARY KEY,
OptionDesc CHAR(40)
);

CREATE TABLE tblOptionDetail
(
OptionID NUMBER(38),
VehicleID NUMBER(38),
PRIMARY KEY (OptionID, VehicleID),
FOREIGN KEY (OptionID) REFERENCES tblOption(OptionID),
FOREIGN KEY (VehicleID) REFERENCES tblVehicle(VehicleID)
);


-- populate the Manufacture table

INSERT ALL 
INTO tblManufacture (ManufactureID, ManufactureName) VALUES (1,'Chrysler Corp.')
INTO tblManufacture (ManufactureID, ManufactureName) VALUES(2,'General Motors')
INTO tblManufacture (ManufactureID, ManufactureName) VALUES(3,'Ford Motor Company')
INTO tblManufacture (ManufactureID, ManufactureName) VALUES(4,'Toyota')
INTO tblManufacture (ManufactureID, ManufactureName) VALUES (5,'Honda')
INTO tblManufacture (ManufactureID, ManufactureName) VALUES (6,'Nisan')
SELECT * FROM dual;

-- populate the Brand table

INSERT ALL
INTO tblBrand (BrandID, ManufactureID, BrandName) VALUES (1,1, 'Chrysler')
INTO tblBrand (BrandID, ManufactureID, BrandName) VALUES (2,1, 'Dodge')
INTO tblBrand (BrandID, ManufactureID, BrandName) VALUES (3,1, 'Jeep')
INTO tblBrand (BrandID, ManufactureID, BrandName) VALUES (4,2, 'Chevrolet')
INTO tblBrand (BrandID, ManufactureID, BrandName) VALUES (5,2, 'Buick')
INTO tblBrand (BrandID, ManufactureID, BrandName) VALUES (6,2, 'Cadillac')
INTO tblBrand (BrandID, ManufactureID, BrandName) VALUES (7,2, 'GMC')
INTO tblBrand (BrandID, ManufactureID, BrandName) VALUES (8,4, 'Toyota')
INTO tblBrand (BrandID, ManufactureID, BrandName) VALUES (9,6, 'Nissan')
INTO tblBrand (BrandID, ManufactureID, BrandName) VALUES (10,6,'Infiniti')
SELECT * FROM dual;

-- populate the Model table

INSERT ALL
INTO tblModel (ModelID, BrandID, ModelName) VALUES (1,1, '200')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (2,1, '200 Convertible')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (3,1, '300')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (4,1, 'Town'||' & '||'Country')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (5,2, 'Durango')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (6,2, 'Avenger')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (7,2, 'Challenger')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (8,2, 'Charger')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (9,2, 'Caliber')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (10,2, 'Grand Caravan')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (11,2, 'Journey')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (12,4, 'Sonic')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (13,4, 'Cruze')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (14,4, 'Orlando')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (15,4, 'Colorado')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (16,4, 'Malibu')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (17,8, '4Runner')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (18,8, 'Prius')
INTO tblModel (ModelID, BrandID, ModelName) VALUES  (19,8, 'Camry')
INTO tblModel (ModelID, BrandID, ModelName) VALUES  (20,8, 'Corolla')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (21,9,'Rogue SL')
INTO tblModel (ModelID, BrandID, ModelName) VALUES  (22,9, 'Versa Note')
INTO tblModel (ModelID, BrandID, ModelName) VALUES  (23,9, 'Pathfinder')
INTO tblModel (ModelID, BrandID, ModelName) VALUES  (24,9, 'Altima')
INTO tblModel (ModelID, BrandID, ModelName) VALUES (25,10, 'Q70')
INTO tblModel (ModelID, BrandID, ModelName) VALUES  (26,10, 'Q50')
INTO tblModel (ModelID, BrandID, ModelName) VALUES  (27,10, 'Q60')
INTO tblModel (ModelID, BrandID, ModelName) VALUES  (28,10, 'EX37')
SELECT * FROM dual;

-- populate Option table

INSERT ALL 
INTO tblOption (OptionID,OptionDesc) VALUES (1,'Power locks')
INTO tblOption (OptionID,OptionDesc) VALUES (2,'Power windows')
INTO tblOption (OptionID,OptionDesc) VALUES (3,'Air conditioning')
INTO tblOption (OptionID,OptionDesc) VALUES (4,'Heated mirrors')
INTO tblOption (OptionID,OptionDesc) VALUES (5,'Remote keyless entry')
INTO tblOption (OptionID,OptionDesc) VALUES (6,'CD Player')
INTO tblOption (OptionID,OptionDesc) VALUES (7,'GPS')
INTO tblOption (OptionID,OptionDesc) VALUES (8,'In-dash DVD player')
INTO tblOption (OptionID,OptionDesc) VALUES (9,'Overhead DVD player')
INTO tblOption (OptionID,OptionDesc) VALUES (10,'Satellite radio')
INTO tblOption (OptionID,OptionDesc) VALUES (11,'MP3 player')
INTO tblOption (OptionID,OptionDesc) VALUES (12,'Antilock braking system')
INTO tblOption (OptionID,OptionDesc) VALUES (13,'Electronic stability system')
INTO tblOption (OptionID,OptionDesc) VALUES (14,'Traction control')
INTO tblOption (OptionID,OptionDesc) VALUES (15,'Cruise control')
INTO tblOption (OptionID,OptionDesc) VALUES (16,'Intelligent cruise control')
INTO tblOption (OptionID,OptionDesc) VALUES (17,'Parking assist system')
INTO tblOption (OptionID,OptionDesc) VALUES (18,'Xenon headlights')
INTO tblOption (OptionID,OptionDesc) VALUES (19,'Aluminum rims')
INTO tblOption (OptionID,OptionDesc) VALUES (20,'AWD')
INTO tblOption (OptionID,OptionDesc) VALUES (21,'Convertable')
INTO tblOption (OptionID,OptionDesc) VALUES (22,'Heated Seats')
SELECT * FROM dual;

-- populate Vehicle table

INSERT ALL
INTO tblVehicle (VehicleID,ModelID, VehicleYear, VehicleKM, VehiclePrice) VALUES (1,10, 2010, 45000, 18000)
INTO tblVehicle (VehicleID,ModelID, VehicleYear, VehicleKM, VehiclePrice) VALUES (2,10, 2010, 65420, 17500)
INTO tblVehicle (VehicleID,ModelID, VehicleYear, VehicleKM, VehiclePrice) VALUES (3,16, 2004, 143900, 3200)
INTO tblVehicle (VehicleID,ModelID, VehicleYear, VehicleKM, VehiclePrice) VALUES (4,11, 2010, 38900, 14500)
INTO tblVehicle (VehicleID,ModelID, VehicleYear, VehicleKM, VehiclePrice) VALUES (5,27,2014,17250,45999)
INTO tblVehicle (VehicleID,ModelID, VehicleYear, VehicleKM, VehiclePrice) VALUES (6,25,2015,2900,62300)
INTO tblVehicle (VehicleID,ModelID, VehicleYear, VehicleKM, VehiclePrice) VALUES (7,17,2010,87900,19800)
SELECT * FROM dual;

-- populate OptionDetail table

INSERT ALL
INTO tblOptionDetail (OptionID, VehicleID) VALUES (2, 2)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (1, 2)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (3, 2)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (5, 2)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (6, 2)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (7, 2)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (8, 2)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (11, 2)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (12, 2)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (14, 2)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (15, 2)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (19, 2)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (2, 1)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (1, 1)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (3, 1)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (6, 1)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (12, 1)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (14, 1)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (15, 1)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (19, 1)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (2, 3)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (1, 3)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (3, 3)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (6, 3)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (12, 3)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (14, 3)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (15, 3)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (19, 3)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (2, 4)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (1, 4)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (3, 4)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (6, 4)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (11, 4)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (12, 4)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (14, 4)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (15, 4)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (19, 4)
INTO tblOptionDetail (OptionID, VehicleID) VALUES  (4,5)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (8,5)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (1,5)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (2,5)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (5,5)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (21,6)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (22,6)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (3,6)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (1,6)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (2,6)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (1,7)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (4,7)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (5,7)
INTO tblOptionDetail (OptionID, VehicleID) VALUES (2,7)
SELECT * FROM dual;

COMMIT;

Upvotes: 0

Views: 38

Answers (2)

user5683823
user5683823

Reputation:

First let's analyze your attempt - perhaps a few things can be learned from that. (I will provide a working answer below, don't worry!)

In the subquery, you take all the rows from the tblVehicle table. Then you GROUP them by price; so if three vehicles have the same price of $25,000 they will be in one group. (Most groups will likely have just one row in them, as prices for different vehicles are very rarely the same.)

Then within each group you compute the average price for the group and you compare to the price within the same group. That's how HAVING works: it treats each group in isolation, as if those were the only rows under consideration.

So, in your case all the rows in a group have the same price - and therefore the average is also the same, equal to the price of each vehicle in that group. So the < comparison obviously will fail in every single case - you will get no rows. That is: no rows even in the SUBQUERY. Then you use it for IN - but since the subquery returns no rows, nothing is "in" the list from the subquery, so the overall query returns no rows either.

One more thing - you were lucky that vehicleprice was even available in the HAVING clause. It was available because you grouped by that column; other columns (not included in the GROUP BY list) wouldn't be available in the HAVING clause, you would get a syntax error.

Now to the correct solution: You need to compare each vehicle's price to the average over all vehicles. This average over all vehicles is the only "strange" quantity, which you must compute by traversing the entire table. So it alone is what you need to compute in a subquery.

Like so: (note I don't like "..." for column names - not a good practice)

SELECT t1.MODELNAME AS model
FROM TBLMODEL t1
FULL JOIN TBLVEHICLE t2 ON t1.MODELID = t2.MODELID
WHERE t2.VEHICLEPRICE >
(
  SELECT AVG(VEHICLEPRICE)    
  FROM TBLVEHICLE     
);

Notice the subquery returns only one row with one column - a single value. This is called a "scalar" subquery, and the value it returns can be used as if it were a "stand-alone" value (and not the result of a subquery). You can compare to it with the > condition as if you were comparing to a simple number.

Upvotes: 2

Gordon Linoff
Gordon Linoff

Reputation: 1269593

This is the answer to your question:

SELECT m.MODELNAME AS "Model"
FROM TBLMODEL m JOIN
     TBLVEHICLE v
     ON m.MODELID = v.MODELID
WHERE t2.VEHICLEPRICE > (SELECT AVG(VEHICLEPRICE)    
                         FROM TBLVEHICLE  
                        )  ;

Where to begin on the issues with your query.

  • A FULL JOIN is not necessary. In fact, the WHERE filters out non-matching rows, turning the full join into a left or right outer join.
  • The subquery is taking AVG(VEHICLEPRICE) and grouping by VEHICLEPRICE. Well, that is easy to calculate. If the values are all the same, the value is simply VEHICLEPRICE.
  • The HAVING clause is quite difficult to follow. You are only keeping rows where the average is strictly less than the outer value.
  • Well, the IN will never match values that are strictly less than it.
  • And, when you use table aliases, make them abbreviations for the tables.

Upvotes: 0

Related Questions