Reputation: 47
TASK: for each maker who has models at least in one of the tables PC, Laptop, or Printer, determine the maximum price for his products. Output: maker; if there are NULL values among the prices for the products of a given maker, display NULL for this maker, otherwise, the maximum price.
This is task 41 from this website: http://www.sql-ex.ru/
Database description:
The database scheme consists of four tables:
The Product
table contains data on the maker, model number, and type of product ('PC', 'Laptop', or 'Printer'). It is assumed that model numbers in the Product
table are unique for all makers and product types. Each personal computer in the PC table is unambiguously identified by a unique code, and is additionally characterized by its model (foreign key referring to the Product table), processor speed (in MHz) – speed field, RAM capacity (in Mb) - ram, hard disk drive capacity (in Gb) – hd, CD-ROM speed (e.g, '4x') - cd, and its price.
The Laptop
table is similar to the PC
table, except that instead of the CD-ROM speed, it contains the screen size (in inches) – screen. For each printer model in the Printer
table, its output type (‘y’ for color and ‘n’ for monochrome) – color field, printing technology ('Laser', 'Jet', or 'Matrix') – type, and price are specified.
I've tried several queries, most of them worked on the first database but not on the second one
Here's my last tried query:
SELECT DISTINCT
maker,
CASE
WHEN price IS NULL
THEN NULL
ELSE MAX(price) OVER (PARTITION by maker)
END max_p
FROM
(SELECT DISTINCT maker, price
FROM product
LEFT JOIN pc ON pc.model = product.model
WHERE product.model IN (SELECT model FROM pc)
UNION
SELECT DISTINCT maker, price
FROM product
LEFT JOIN laptop ON laptop.model = product.model
WHERE product.model IN (SELECT model FROM laptop)
UNION
SELECT DISTINCT maker, price FROM product
LEFT JOIN printer ON printer.model = product.model
WHERE product.model IN (SELECT model FROM printer)) as x
Your query returned the correct dataset on the first (available) database, but it returned incorrect dataset on the second checking database.
Upvotes: 1
Views: 2654
Reputation: 1
SELECT maker, CASE WHEN SUM(CASE WHEN price IS NULL THEN 1 ELSE 0 END) > 0
THEN null
ELSE MAX(price)
END AS price
FROM (SELECT maker, price
FROM product LEFT JOIN laptop ON product.model = laptop.model
WHERE product.model IN (SELECT model FROM laptop)
UNION
SELECT maker, price
FROM product LEFT JOIN printer ON product.model = printer.model
WHERE product.model IN (SELECT model FROM printer)
UNION
SELECT maker, price
FROM product LEFT JOIN pc ON product.model = pc.model
WHERE product.model IN (SELECT model FROM pc)
) X
GROUP BY maker
Upvotes: 0
Reputation: 74740
Most expensive product per maker, or null if any of the maker's prices are null:
SELECT
pro.maker,
NULLIF(MAX(COALESCE(pri.price, 922337203685477)), 922337203685477) as price
FROM
product pro
INNER JOIN
(
SELECT model, price FROM printer
UNION ALL
SELECT model, price FROM pc
UNION ALL
SELECT model, price FROM laptop
) pri
ON pri.model = pro.model
GROUP BY pro.maker
How it works:
Strip the laptop, pc and printer tables out to just model and price (including any null prices) and union then together to provide a consistent data set. Join this to product to get the maker. Group by the maker looking for the max price. Because we have to show null as the max price of there is any null price we COALESCE to make all the null prices a massively high price so they will surely be the max price, then we turn that massively high price back into null with NULLIF
NULLIF is proprietary. I could do the same thing with case when max(...) = 922... then null else max(...) end
But it's more wordy
Trivia:
922337203685477 Is almost the max value for a MONEY; I omitted the fractional component
Also consider:
Two of the three hardware tables have a type column. It is not stated whether this relates to the type column of the product table. If it is you'll have to add it into the join. For the table that lacks a type, null it and make the join condition include "or pri.type is null"
Upvotes: 3