Как суммировать 2 значения из разных запросов?

Я пытаюсь определить, насколько ниже или выше среднего показатели заведения. Например, запрос вернет место проведения, дату и то, насколько ниже ожидаемого среднего показателя. Из приведенных ниже данных вы можете видеть, что средний балл Пола составлял 100, не считая Лейквью, поэтому он прошел точно свой средний балл, а Мел на 20 ниже своего среднего показателя в Лейквью, поэтому Лейквью показала в среднем на -10 результат ниже средней дистанции для людей.

Результат запроса будет выглядеть так:

Venue      Date           Performance
-------------------------------------
Lakeview   12/08/2024     -10

Во-первых, мне нужно сгруппировать по имени, чтобы получить среднее значение. Однако я хочу включить только последние 5 дистанций.

Я могу сделать это с помощью этого запроса

SELECT name, AVG(distance) as avg_distance
FROM 
    (SELECT 
         database.*,
         ROW_NUMBER() OVER (PARTITION BY name ORDER BY date DESC) AS seqnum
     FROM database) s
WHERE seqnum <= 5
GROUP BY name

Затем мне нужно сгруппировать по местам проведения и найти среднее расстояние всех, кто выступал в этот день и в этом месте. Что я могу сделать с помощью этого запроса

SELECT venue, AVG(distance)
FROM "database"
GROUP BY venue, date

Затем мне нужно вычесть расстояние в этот день из их среднего значения, чтобы увидеть, как оно работает. Какой самый простой способ сделать это?

Пример данных

Name  Venue     Distance   Date
-------------------------------------
Paul  Holland   120        20/07/2024
Paul  Venus     80         21/07/2024
Paul  Lakeview  100        12/08/2024
Tom   Lakeview  120        12/08/2024
Mel   Lakeview  140        12/08/2024
Mel   Hightail  160        05/05/2024

Пожалуйста, обновите сообщение, добавив таблицу DDL, и предоставьте исполняемый SQL для заполнения таблицы примерами данных (чтобы другим было максимально просто решить проблему). Предоставьте полный ожидаемый результат запроса, а не только одну точку. Данные примера должны включать достаточно значений для выполнения всех требований. В этом случае недостаточно точек данных, чтобы продемонстрировать фильтрацию только по пяти самым последним по имени. Является ли сочетание имени и даты уникальным? Если нет, то какие дополнительные критерии следует использовать для определения того, какие из них включены?

JohnH 01.09.2024 19:05

база данных — очень запутанное имя таблицы.

jarlh 01.09.2024 20:06

Рассчитываются ли средние расстояния для каждого человека по всем объектам или по исключенным объектам? Представленный запрос для расчета средних расстояний делает первое, но из описания следует, что предназначено второе.

JohnH 01.09.2024 20:19
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
3
82
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Один из вариантов — создать cte (или подзапрос) с добавленными столбцами со средними расстояниями для каждого имени и места/даты. Это можно сделать с помощью аналитической функции Avg() Over().

WITH    --  S a m p l e    D a t a : 
    tbl ( a_name, venue, distance, a_date ) AS 
      ( Select 'Paul', 'Holland',   120, To_Date('20/07/2024', 'dd/mm/yyyy') Union All 
        Select 'Paul', 'Venus',      80, To_Date('21/07/2024', 'dd/mm/yyyy') Union All 
        Select 'Paul', 'Lakeview',  100, To_Date('12/08/2024', 'dd/mm/yyyy') Union All 
        Select 'Tom', 'Lakeview',   120, To_Date('12/08/2024', 'dd/mm/yyyy') Union All 
        Select 'Mel', 'Lakeview',   140, To_Date('12/08/2024', 'dd/mm/yyyy') Union All 
        Select 'Mel', 'Hightail',   160, To_Date('05/05/2024', 'dd/mm/yyyy') 
      ), 

... cte сетка, чтобы получить средние значения по имени (последние 5 дат) и по месту/дате (все расстояния)

    grid AS 
      ( SELECT  a.*, 
                Round(Avg(Case When rn_name <= 5 Then a.distance End) Over(Partition By a_name ), 2) as avg_name, 
                Round(Avg(a.distance) Over(Partition By venue, a_date ), 2) as avg_venue_date
        FROM  ( Select Row_Number() Over(Partition By a_name Order By a_name, a_date Desc) as rn_name, 
                       a_name, venue, distance, a_date
                From tbl
              )  a
      ) 
--      M a i n    S Q L : 
Select    venue, a_date, Sum(avg_venue_date - avg_name) as performance
From      grid 
Group By  a_date, venue
Order By  a_date, venue
/*      R e s u l t : 
venue        a_date      performance
-----------  ----------  -----------
Hightail    2024-05-05         10.00
Holland     2024-07-20         20.00
Venus       2024-07-21        -20.00
Lakeview    2024-08-12        -10.00      */

См. скрипку здесь.

Дополнение:
Если имя вашей таблицы — база данных (что в любом случае плохо), и если имена/типы столбцов в этой таблице — это имя /varchar, место проведения /varchar, расстояние /целое число и дата /дата (дата также является очень, очень плохим именем столбца потому что это тоже тип данных), тогда попробуйте использовать полный код, как показано ниже. Есть еще один (первый) способ, который должен привести вашу таблицу в соответствие с остальным кодом:

WITH    
    tbl AS 
      ( Select t.name as a_name, t.venue, t.distance, t.date as a_date
        From database t
      ), 
    grid AS 
      ( SELECT  a.*, 
                Round(Avg(Case When rn_name <= 5 Then a.distance End) Over(Partition By a_name ), 2) as avg_name, 
                Round(Avg(a.distance) Over(Partition By venue, a_date ), 2) as avg_venue_date
        FROM  ( Select Row_Number() Over(Partition By a_name Order By a_name, a_date Desc) as rn_name, 
                       a_name, venue, distance, a_date
                From tbl
              )  a
      ) 
Select    venue, a_date, Sum(avg_venue_date - avg_name) as performance
From      grid 
Group By  a_date, venue
Order By  a_date, venue

Спасибо за ваш ответ! Первый ввод сделан только для того, чтобы предоставить вам образец данных? Как мне это сделать, если у меня уже есть все данные? У меня более 100 000 строк данных, поэтому я не думаю, что смогу вручную поместить их все в запрос.

undecided000 02.09.2024 04:31

@undecided000 Это всего лишь пример данных, которые вы опубликовали в конце своего вопроса. Это НЕ часть ответа. Вам нужно всего лишь: С сеткой AS (код сетки sql) Основной код SQL

d r 02.09.2024 06:48

Спасибо. Он говорит мне, что все значения a_ не существуют? Например, имя_а.

undecided000 02.09.2024 07:16

@undecided000 Вам нужно адаптировать код к вашему контексту. Укажите имя своей таблицы и имена столбцов, чтобы все заработало. В этом ответе используются имена из образцов данных, а не из вашей базы данных...

d r 02.09.2024 07:22

Ах, я вижу. Я считаю, что внес необходимые изменения, но получаю эту ошибку. ОШИБКА: оператор не существует: варьируется символ <= целое число LINE 4: ... Round(Avg(Case When data.name <= 5 then... ^ ПОДСКАЗКА: ни один оператор не соответствует данному имени и типам аргументов. Возможно, вам понадобится чтобы добавить явное приведение типов.

undecided000 02.09.2024 16:19

@undecided000 это rn_name <= 5 . rn_name — это псевдоним из подзапроса в сетке cte. Вам следует изменить только имя вашей таблицы (вместо моей tbl) и имена столбцов, если они отличаются. Имена столбцов, которые следует изменить на ваши: a_name, a_date, location и distance. Не меняйте мои псевдонимы (например, rn_name, avg_name, avg_venue_date). И, пожалуйста, не используйте базу данных в качестве имени таблицы.

d r 02.09.2024 18:06

@undecided000 Только что опубликовал дополнение, которое может вам помочь...

d r 02.09.2024 18:31

Потрясающий! Спасибо, приятель. Это работает, и спасибо за совет по поводу моих имен, я новичок в sql. Единственное, что я изменил, это четвертая последняя строка: вместо суммы я хотел Avg. Я просто изменил это, и теперь все именно так, как я хотел. Огромное спасибо за ваше время и мудрость.

undecided000 03.09.2024 00:47

Другие вопросы по теме