Я решал пример SQL Дэнни Ма для Pizza Runner. В одном из разделов «Цены и рейтинги» я застрял в двух вопросах и не могу прийти к правильному решению. Ссылка на кейс: https://8weeksqlchallenge.com/case-study-2/
[cleaned_customer_orders table](https://i.sstatic.net/fEgXb.png)
[cleaned_runner_orders table](https://i.sstatic.net/sl6kd.png)
[extras table](https://i.sstatic.net/Ggm0B.png)
CREATE TABLE customer_orders (
"order_id" INTEGER,
"customer_id" INTEGER,
"pizza_id" INTEGER,
"exclusions" VARCHAR(4),
"extras" VARCHAR(4),
"order_time" TIMESTAMP
);
INSERT INTO customer_orders
("order_id", "customer_id", "pizza_id", "exclusions", "extras", "order_time")
VALUES
('1', '101', '1', '', '', '2020-01-01 18:05:02'),
('2', '101', '1', '', '', '2020-01-01 19:00:52'),
('3', '102', '1', '', '', '2020-01-02 23:51:23'),
('3', '102', '2', '', NULL, '2020-01-02 23:51:23'),
('4', '103', '1', '4', '', '2020-01-04 13:23:46'),
('4', '103', '1', '4', '', '2020-01-04 13:23:46'),
('4', '103', '2', '4', '', '2020-01-04 13:23:46'),
('5', '104', '1', 'null', '1', '2020-01-08 21:00:29'),
('6', '101', '2', 'null', 'null', '2020-01-08 21:03:13'),
('7', '105', '2', 'null', '1', '2020-01-08 21:20:29'),
('8', '102', '1', 'null', 'null', '2020-01-09 23:54:33'),
('9', '103', '1', '4', '1, 5', '2020-01-10 11:22:59'),
('10', '104', '1', 'null', 'null', '2020-01-11 18:34:49'),
('10', '104', '1', '2, 6', '1, 4', '2020-01-11 18:34:49');
CREATE TABLE runner_orders (
"order_id" INTEGER,
"runner_id" INTEGER,
"pickup_time" VARCHAR(19),
"distance" VARCHAR(7),
"duration" VARCHAR(10),
"cancellation" VARCHAR(23)
);
INSERT INTO runner_orders
("order_id", "runner_id", "pickup_time", "distance", "duration", "cancellation")
VALUES
('1', '1', '2020-01-01 18:15:34', '20km', '32 minutes', ''),
('2', '1', '2020-01-01 19:10:54', '20km', '27 minutes', ''),
('3', '1', '2020-01-03 00:12:37', '13.4km', '20 mins', NULL),
('4', '2', '2020-01-04 13:53:03', '23.4', '40', NULL),
('5', '3', '2020-01-08 21:10:57', '10', '15', NULL),
('6', '3', 'null', 'null', 'null', 'Restaurant Cancellation'),
('7', '2', '2020-01-08 21:30:45', '25km', '25mins', 'null'),
('8', '2', '2020-01-10 00:15:02', '23.4 km', '15 minute', 'null'),
('9', '2', 'null', 'null', 'null', 'Customer Cancellation'),
('10', '1', '2020-01-11 18:50:20', '10km', '10minutes', 'null');
select order_id, customer_id, pizza_id,
case
when exclusions in ('null', '') then null
else exclusions
end as exclusions,
case
when extras in ('null', '') then null
else extras
end as extras,
order_time
into cleaned_customer_orders
from customer_orders
select
order_id,
runner_id,
cast(case
when pickup_time = 'null' then null
else pickup_time
end as timestamp) as pickup_time,
cast(case
when distance = 'null' then null
else trim('km' from distance)
end as float) as distance,
cast(case
when duration = 'null' then null
else substring(duration, 1, 2)
end as int)as duration,
case
when cancellation in ('null', '') then null
else cancellation
end as cancellation
into cleaned_runner_orders
from runner_orders;
select * from cleaned_customer_orders
select * from cleaned_runner_orders
alter table cleaned_customer_orders
add column record_id serial;
select * from cleaned_customer_orders;
-- to generate extras table
select
cco.record_id,
trim(e.value) as topping_id
into extras
from
cleaned_customer_orders as cco
cross join lateral unnest(string_to_array(cco.extras, ',')) as e(value);
Вопрос 1. Запрос
select
sum(case when cco.pizza_id = 1 then 12 else 10 end) as pizza_cost
from cleaned_customer_orders cco
join pizza_names pn on pn.pizza_id = cco.pizza_id
join cleaned_runner_orders cro on cro.order_id = cco.order_id
where cro.cancellation is null
В2. Запрос
with cte_extras_cost as (select
sum(case when pn.pizza_id = 1 then 12 else 10 end) as pizza_cost,
count (e.topping_id)*1 as extras_cost
from cleaned_customer_orders cco
join pizza_names pn on pn.pizza_id = cco.pizza_id
left join extras e on e.record_id = cco.record_id
join cleaned_runner_orders cro on cro.order_id = cco.order_id
where cro.cancellation is null)
select pizza_cost, coalesce(extras_cost, 0) as extras_cost, (pizza_cost+coalesce(extras_cost, 0))
as total_cost
from cte_extras_cost;
Вопрос 5. Запрос
with cte as (
select
sum(cro.distance*0.30) as delivery_cost,
sum(case when cco.pizza_id = 1 then 12 else 10 end) as total_cost
from cleaned_runner_orders cro
join cleaned_customer_orders cco on cro.order_id = cco.order_id
where cro.cancellation is null)
select cte.total_cost, cte.delivery_cost, (cte.total_cost - cte.delivery_cost) as actual_cost
from cte
Мой результат:
Вопрос 1. 138
В2. Pizza_cost=150, extras_cost=4, total_cost=154
Вопрос 5. общая_стоимость=138, стоимость_доставки=64, фактическая_стоимость=73
Правильные ответы:
Вопрос 1. 138
В2. Pizza_cost=138, extras_cost=4, total_cost=142
Вопрос 5. общая_стоимость=138, стоимость_доставки=43, фактическая_стоимость=94
Выше приведены изображения, на которых я показал, какие таблицы я использую для получения выходных данных и какие запросы я написал. Я получаю результат, но он не подходит для Q2 и Q5, и я не понимаю, почему это происходит?
Также поделитесь примерами данных и структурой таблицы.
Я не могу напрямую делиться изображениями, так как для этого требуется получить 10 репутаций. Если вы откроете ссылку на таблицы, вы сможете четко увидеть структуру и содержимое таблицы.
Вам не нужно делиться никакими изображениями. Поделитесь всеми подробностями в текстовой форме, например, утверждениями CREATE TABLE и INSERT.
Я добавил код для таблиц, как они создаются и вставляются значения.





лучше, если вы опубликуете операторы вставки для заполнения временных таблиц
q1
select
sum(case when cco.pizza_id = 1 then 12 else 10 end) as pizza_cost
from customer_orders cco
left join runner_orders cro on cro.order_id = cco.order_id
where coalesce(cro.cancellation,'') not in ('Restaurant Cancellation', 'Customer Cancellation')
кв2
with
cco as
(select *, row_number() over(order by order_id, pizza_id) as rn from customer_orders)
, ex as (
select rn, case when extras = 'null' then null else extras end as extras from
cco
where coalesce(case when extras = 'null' then null else extras end,'') <> ''
)
, ex1 as (
select trim(unnest(string_to_array(extras, ',')))::int as topping_id, rn from ex
)
, extras as (
select count(topping_id) as topping_cnt, rn from ex1 group by rn
)
, cte_extras_cost as (
select
sum(case when pn.pizza_id = 1 then 12 else 10 end) pizza_cost
, sum(topping_cnt*1) as extras_cost
from cco
join pizza_names pn on pn.pizza_id = cco.pizza_id
left join extras e on e.rn = cco.rn
join runner_orders cro on cro.order_id = cco.order_id
where coalesce(cro.cancellation,'') not in ('Restaurant Cancellation', 'Customer Cancellation')
)
select pizza_cost, coalesce(extras_cost, 0) as extras_cost, (pizza_cost+coalesce(extras_cost, 0))
as total_cost
from cte_extras_cost;
q5
with
cro as
(
select
case when distance <> '' then cast(distance as numeric) else 0 end as distance, order_id, runner_id,
pickup_time, duration, cancellation
from (
SELECT order_id, runner_id, pickup_time, replace(replace(distance, 'km', ''), 'null', '') as distance,
duration, cancellation
from
pizza_runner.runner_orders
) q1
)
, cco as (
select sum(case when pizza_id = 1 then 12 else 10 end) as pizza_cost, order_id
from customer_orders
group by order_id
)
, cte as (
select
sum(cro.distance*0.30) as delivery_cost,
sum(pizza_cost) as total_cost
from cro
join cco on cro.order_id = cco.order_id
where coalesce(cro.cancellation,'') not in ('Restaurant Cancellation', 'Customer Cancellation')
)
select
cte.total_cost, cte.delivery_cost, (cte.total_cost - cte.delivery_cost) as actual_cost
from cte
q1 и q2 имеют четкое решение, НО я не могу найти, как можно получить 45 за стоимость доставки из этих чисел в Q5. счётчик расстояний
да, вы правы, это не 45, а 43, спасибо за решение. Но можете ли вы сказать, что не так с моим кодом?
q2. Когда вы объединяете заказы и дополнительные услуги, вам нужно использовать группировку и подсчет перед присоединением. В вашем случае вы умножаете стоимость пиццы на количество дополнительных услуг.
q5. вам необходимо использовать отношение «один к одному» при объединении заказов, но в заказах клиентов имеется более одной строки на заказ. Вот почему я использую конструкцию с группой по: выберите сумму (случай, когда Pizza_id = 1, затем 12, иначе 10 заканчивается) в качестве Pizza_cost, order_id из группы customer_orders по order_id
В шагах перед последним шагом я пытался получить таблицу, подобную вашей, clean_customer_orders и clean_runner_orders, если вы выполняете выбор каждого шага предложения With, вы можете это понять.
что ты уже испробовал? Где ты застрял? Пожалуйста, поделитесь всеми подробностями в текстовой форме