Я изучаю SQL (самоучка). Я пытаюсь написать исполняемый SQL-запрос postgres, чтобы ответить на этот вопрос: на основе города происхождения (имя) рассчитайте процент поездок, в которых оплата был как минимум на 10% выше, чем в среднем для поездок из этого города.
Контекст: 1) Завершенная поездка определяется как поездка со статусом «завершена» в таблице аренды. 2) Только с учетом поездок за последние 30 дней.
С чего я начал (надеюсь, это выглядит хорошо):
SELECT n.name, r.origin_id, SUM(r.fare_dollars), AVG(r.fare_dollars), count(r.id)
FROM rentals r, neighborhood n
LEFT JOIN r ON r.origin_id = n.id
GROUP BY n.name;
На правильном пути?!
В чем мне нужна ваша помощь (если я прав в отношении этого подхода):
Вопрос потребует, чтобы я выполнил подзапрос, который извлечет все записи, чтобы увидеть, как они соотносятся со средней стоимостью проезда. Затем мне нужно будет написать еще один запрос, который скажет мне, какие из этих поездок стоили на 10% дороже, чем средняя стоимость проезда.
Я с нетерпением жду возможности увидеть любые идеи, которые вы можете предоставить! Дайте мне знать, если я могу предоставить любую дополнительную информацию.
Спасибо.
Вы думаете в правильном направлении, хотя ваши навыки запросов еще не развиты, верно? Я постараюсь объяснить, насколько это возможно, надеюсь, вы будете следовать (а если вы не можете, не стесняйтесь спрашивать).
Итак, во-первых, вам нужно знать, какова средняя стоимость проезда по каждому пункту отправления:
SELECT n.id, n.name, AVG(r.fare_dollars) AS average_fare
FROM neighborhood n
JOIN rentals r
ON r.origin_id = n.id
GROUP BY n.id, n.name
Это довольно простой запрос, хотя обычно вам здесь не нужен идентификатор. Однако мы собираемся использовать этот запрос для сравнения с отдельными поездками, поэтому мы просто присоединим его к нашей таблице аренды:
SELECT avg_per_neighborhood.name
, SUM(CASE
WHEN r.fare_dollars >= avg_per_neighborhood.average_fare * 1.1 THEN 1.0
ELSE 0
END) / COUNT(*) AS percAbove110
FROM rentals r
JOIN (SELECT n.id, n.name, AVG(r.fare_dollars) AS average_fare
FROM neighborhood n
JOIN rentals r
ON r.origin_id = n.id
GROUP BY n.id, n.name) avg_per_neighborhood
ON r.origin_id = avg_per_neighborhood.id
GROUP BY avg_per_neighborhood.name
Интересная часть, конечно, процент выше 10% выше, чем в среднем; поэтому сначала мы определяем, выше ли индивидуальная арендная плата объединенного среднего * 1,1 (или 110% от среднего), и является ли она доходом 1 или доходностью 0, если нет — это утверждение CASE
. Мы суммируем их по районам (SUM(CASE ... END)
) и делим на общее количество поездок в этом районе (COUNT(*)
), что дает нам процент.
Этот запрос можно немного переписать, используя оконные функции:
SELECT subq.NAME
, SUM(subq.isHigherThan110avg) / COUNT(*) AS percAbove110
FROM (SELECT n.NAME
, CASE
WHEN r.fare_dollars > 1.1 * AVG(r.fare_dollars) OVER (PARTITION BY n.id) THEN 1.0
ELSE 0
END AS isHigherThan110avg
FROM neighborhood n
JOIN rentals r
ON r.origin_id = n.id
) subq
GROUP BY subq.name
Здесь подзапрос subq
сравнивает со средним встроенным значением, используя оконную функцию AVG(...) OVER (...)
, а внешний запрос просто агрегирует результаты.
Вам, конечно, нужно применить свои собственные фильтры, например, завершенные и последние 30 дней, но суть вы уловили, надеюсь.
Большое спасибо за ваше объяснение. Это тщательно и так полезно. Очень признателен! И да, я еще не совсем готов с моими навыками запросов, но скоро буду. Спасибо еще раз!
Совершенно никаких проблем. Если возможно, подумайте о том, чтобы проголосовать за мой ответ, чтобы пользователи, которые найдут этот вопрос в будущем, знали, что он правильный и помог.
Конечно! У меня есть еще один вопрос, так как я не уверен, что сделал это правильно. Как бы вы добавили фильтры, т. е. завершенные и последние 30 дней, в этот sql?
Просто добавьте их после объединения, WHERE r.status = 'Completed' AND r.date_completed > current_date - interval '30 days'
или что-то в этом роде (я не знаю названия ваших столбцов).
Спасибо! Я не был полностью в этой части, и это здорово. Я принял ваш ответ и сделал так, как вы просили, и получил следующее: Голоса, отданные теми, у кого репутация менее 15, записываются, но не изменяют общедоступную оценку публикации. В любом случае, я принял это, и это работает для всех, кто читает это! Большое спасибо, еще раз. У меня, безусловно, будет больше вопросов, поскольку я пытаюсь улучшить свои навыки запросов.
Ах да, вы не можете проголосовать, потому что вы новичок, извините! Удачи и удачи, не стесняйтесь спрашивать, если вы застряли, и помните, что лучший способ научиться — это попробовать.
ваш вопрос не ясен. Во-первых, я мог бы сказать, что вы запутались с форматом соединения, разделенным запятыми, и форматом соединения ansi-92, и следует предпочесть второй стиль форматирования (ansi-92).