I have a query, which finds the GREATEST amount of which item was purchased. It appears to be working fine (see below).
I have two questions, first is there a better way to rewrite this query without using 2 CTE and not displaying the value of rnk in the output.
Secondly, in another query how can I show the product_id, product_name, price, customer_id, first_name, last_name, total_qty, total_amt for this item. I am expecting to see 3 rows based on the data provided.
CREATE TABLE customers
(CUSTOMER_ID, FIRST_NAME, LAST_NAME) AS
SELECT 1, 'Faith', 'Mazzarone' FROM DUAL UNION ALL
SELECT 2, 'Lisa', 'Saladino' FROM DUAL UNION ALL
SELECT 3, 'Micheal', 'Palmice' FROM DUAL UNION ALL
SELECT 4, 'Jerry', 'Torchiano' FROM DUAL;
CREATE TABLE items
(PRODUCT_ID, PRODUCT_NAME, PRICE) AS
SELECT 100, 'Black Shoes', 79.99 FROM DUAL UNION ALL
SELECT 101, 'Brown Pants', 111.99 FROM DUAL UNION ALL
SELECT 102, 'White Shirt', 10.99 FROM DUAL;
CREATE TABLE purchases(
ORDER_ID NUMBER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
CUSTOMER_ID NUMBER,
PRODUCT_ID NUMBER,
QUANTITY NUMBER,
PURCHASE_DATE TIMESTAMP
);
INSERT INTO purchases
(CUSTOMER_ID, PRODUCT_ID, QUANTITY, PURCHASE_DATE)
SELECT 1, 101, 3, TIMESTAMP'2022-10-11 09:54:48' FROM DUAL UNION ALL
SELECT 1, 100, 1, TIMESTAMP '2022-10-12 19:04:18' FROM DUAL UNION ALL
SELECT 2, 101,1, TIMESTAMP '2022-10-11 09:54:48' FROM DUAL UNION ALL
SELECT 2, 101, 3, TIMESTAMP '2022-10-17 19:34:58' FROM DUAL UNION ALL
SELECT 2, 102, 3,TIMESTAMP '2022-12-06 11:41:25' NUMTODSINTERVAL ( LEVEL * 2, 'DAY') FROM dual CONNECT BY LEVEL <= 6 UNION ALL
SELECT 2, 102, 3,TIMESTAMP '2022-12-26 11:41:25' NUMTODSINTERVAL ( LEVEL * 2, 'DAY') FROM dual CONNECT BY LEVEL <= 6 UNION ALL
SELECT 3, 101,1, TIMESTAMP '2022-12-21 09:54:48' FROM DUAL UNION ALL
SELECT 3, 102,1, TIMESTAMP '2022-12-27 19:04:18' FROM DUAL UNION ALL
SELECT 3, 102, 4,TIMESTAMP '2022-12-22 21:44:35' NUMTODSINTERVAL ( LEVEL * 2, 'DAY') FROM dual
CONNECT BY LEVEL <= 15 UNION ALL
SELECT 3, 101,1, TIMESTAMP '2022-12-11 09:54:48' FROM DUAL UNION ALL
SELECT 3, 102,1, TIMESTAMP '2022-12-17 19:04:18' FROM DUAL UNION ALL
SELECT 3, 102, 4,TIMESTAMP '2022-12-12 21:44:35' NUMTODSINTERVAL ( LEVEL * 2, 'DAY') FROM dual
CONNECT BY LEVEL <= 5;
ALTER TABLE customers
ADD CONSTRAINT customers_pk PRIMARY KEY (customer_id);
ALTER TABLE items
ADD CONSTRAINT items_pk PRIMARY KEY (product_id);
ALTER TABLE purchases
ADD CONSTRAINT order_pk PRIMARY KEY (order_id);
ALTER TABLE purchases ADD CONSTRAINT customers_fk FOREIGN KEY (customer_id) REFERENCES customers(customer_id);
ALTER TABLE purchases ADD CONSTRAINT items_fk FOREIGN KEY (PRODUCT_ID) REFERENCES items(product_id);
/*
get item with GREATEST amount of purchases
*/
with cte as
(SELECT
i.product_id,
i.product_name,
i.price,
SUM (p.quantity) AS total_qty,
SUM (p.quantity * i.price) AS total_amt
FROM purchases p
JOIN customers c ON p.customer_id = c.customer_id
JOIN items i ON p.product_id = i.product_id
GROUP BY
i.product_id,
i.product_name,
i.price, p.quantity),
cte2 as
(SELECT product_id,
product_name,
price,
total_qty,
total_amt,
RANK() OVER (ORDER BY total_amt DESC) rnk
FROM cte)
SELECT *
FROM cte2
WHERE rnk = 1;
PRODUCT_ID PRODUCT_NAME PRICE TOTAL_QTY TOTAL_AMT RNK
102 White Shirt 10.99 80 879.2 1
CodePudding user response:
You could create a cte (or a subquery) that will give you all the data you need to get either greatest amount of all products or greatest per product:
SELECT
i.PRODUCT_ID, i.PRODUCT_NAME, i.PRICE,
c.CUSTOMER_ID, c.FIRST_NAME, c.LAST_NAME,
Sum(p.QUANTITY) "TOTAL_QTY", Sum(p.QUANTITY * i.PRICE) "TOTAL_AMT",
RANK() OVER (PARTITION BY i.PRODUCT_ID ORDER BY i.PRODUCT_ID, Sum(p.QUANTITY * i.PRICE) DESC) "PRODUCT_RNK",
RANK() OVER (ORDER BY Sum(p.QUANTITY * i.PRICE) DESC) "TOTAL_RNK"
FROM
items i
INNER JOIN
purchases p ON(p.PRODUCT_ID = i.PRODUCT_ID)
INNER JOIN
customers c ON(c.CUSTOMER_ID = p.CUSTOMER_ID)
GROUP BY
i.PRODUCT_ID, i.PRODUCT_NAME, i.PRICE,
c.CUSTOMER_ID, c.FIRST_NAME, c.LAST_NAME
ORDER BY
i.PRODUCT_ID, Sum(p.QUANTITY * i.PRICE) DESC
SubQuery or CTE Result:
PRODUCT_ID PRODUCT_NAME PRICE CUSTOMER_ID FIRST_NAME LAST_NAME TOTAL_QTY TOTAL_AMT PRODUCT_RNK TOTAL_RNK
---------- ------------ ---------- ----------- ---------- --------- ---------- ---------- ----------- ----------
100 Black Shoes 79.99 1 Faith Mazzarone 1 79.99 1 6
101 Brown Pants 111.99 2 Lisa Saladino 4 447.96 1 2
101 Brown Pants 111.99 1 Faith Mazzarone 3 335.97 2 4
101 Brown Pants 111.99 3 Micheal Palmice 2 223.98 3 5
102 White Shirt 10.99 3 Micheal Palmice 82 901.18 1 1
102 White Shirt 10.99 2 Lisa Saladino 36 395.64 2 3
with this dataset you can get the results like below:
-- if it is a CTE named cte:
SELECT * FROM cte WHERE PRODUCT_RNK = 1
PRODUCT_ID PRODUCT_NAME PRICE CUSTOMER_ID FIRST_NAME LAST_NAME TOTAL_QTY TOTAL_AMT PRODUCT_RNK TOTAL_RNK
---------- ------------ ---------- ----------- ---------- --------- ---------- ---------- ----------- ----------
100 Black Shoes 79.99 1 Faith Mazzarone 1 79.99 1 6
101 Brown Pants 111.99 2 Lisa Saladino 4 447.96 1 2
102 White Shirt 10.99 3 Micheal Palmice 82 901.18 1 1
OR
SELECT * FROM cte WHERE TOTAL_RNK = 1
PRODUCT_ID PRODUCT_NAME PRICE CUSTOMER_ID FIRST_NAME LAST_NAME TOTAL_QTY TOTAL_AMT PRODUCT_RNK TOTAL_RNK
---------- ------------ ---------- ----------- ---------- --------- ---------- ---------- ----------- ----------
102 White Shirt 10.99 3 Micheal Palmice 82 901.18 1 1