I have this table:
CREATE TABLE runner_orders (
"order_id" integer,
"runner_id" integer,
"distance" decimal (5,2),
"duration" decimal (5,2),
"cancellation" varchar(23)
);
INSERT INTO runner_orders
("order_id", "runner_id", "distance", "duration", "cancellation")
VALUES
(1, 1, 20, 32, ''),
('2', '1', 20, 27, ''),
('3', '1', 13.4, 20, ''),
('4', '2', 23.4, 40, ''),
('5', '3', 10, 15, ''),
('6', '3', NULL, NULL, 'Restaurant Cancellation'),
('7', '2', 25, 25, ''),
('8', '2', 23.4, 15, ''),
('9', '2', NULL, NULL, 'Customer Cancellation'),
('10', '1', 10, 10, '');
And they ask me:
What is the successful delivery percentage for each runner?
I did this, that finally gave me the correct results:
WITH cte_1
AS (
SELECT runner_id, (COUNT(runner_id))*100 AS percentages
FROM runner_orders
WHERE cancellation = ''
group by runner_id
)
SELECT cte_1.runner_id, (percentages/(COUNT(ru.cancellation))) as percentages_successful_deliveries
FROM cte_1
FULL JOIN runner_orders AS ru
ON cte_1.runner_id = ru.runner_id
GROUP BY cte_1.runner_id, cte_1.percentages
ORDER BY runner_id
But I wonder, How can I get the same results in a shorter query? I tried subqueries, and It didn't work for me. This is one of the many subqueries I tried:
SELECT runner_id, ((COUNT(runner_id) over (PARTITION BY runner_id, cancellation))*100)/(count(runner_id))
FROM runner_orders
group by runner_id, cancellation
So how I can make this work in a shorter and more simple way than a CTE.
1条答案
按热度按时间pbossiut1#
Use conditional aggregation as the following:
demo
count(case when cancellation = '' then 1 end)
means, for eachrunner_id
count only the rows wherecancellation = ''
. The case expression inside the count will return null for rows wherecancellation <> ''
and 1 (you may use anything other than 1) for other rows, noting that the count function is not counting null values, this will return only the count of rows wherecancellation = ''
.