Почему SQL не допускает предложение WITH для нескольких подзапросов? - PullRequest
0 голосов
/ 02 апреля 2020

Почему SQL разрешает только вложенные подзапросы?

Например, возьмите этот вопрос

  • Найдите пользователей в каждой профессии с наибольшим количеством оценок.

Имя таблицы рейтинги , с колонками

  1. user_id
  2. занятие
  3. рейтинг

В Postgres или Bigquery я бы сделал

with ratings_by_user as (
select occupation, user_id, count(*) num_ratings
from ratings
group by 1,2
),

max_ratings_by_occupation as (
select occupation, max(num_ratings) as max_ratings
from ratings_by_user
group by 1
),

select occupation, user_id
from ratings_by_user
inner join max_ratings_by_occupation
using (occupation)
where num_ratings = max_ratings

Но я не уверен, как это сделать в SQL, где мне нужно вложить все подзапросы в один блок. Это моя попытка в SQL, но она не работает.

select occupation, user_id, count(*) as num_ratings
from ( 
    select occupation, max(num_ratings) max_ratings 
    from ( 
        select occupation, user_id, count(*) num_ratings
        from users
        group by 1,2
        ) as ratings_table
    group by 1
    ) as max_ratings_table
)
inner join ratings on ratings.occupation = max_ratings_table.occupation
where max_ratings = num_ratings

Может кто-нибудь просветить меня, как я использую тот же стиль Postgres / Bigquery в SQL, где я буду sh обрабатывать мои подзапросы последовательно? Мне просто трудно решать сложные вопросы в один большой кусок.

Большое вам спасибо за ваше время.

1 Ответ

0 голосов
/ 02 апреля 2020

Per https://dev.mysql.com/doc/refman/8.0/en/with.html и MySQL Предложение «WITH» - WITH поддерживается только на MySQL 8+. Убедитесь, что вы используете соответствующую версию MySQL

. Конвертировать во вложенную версию не сложно. Мы берем ваш рабочий sql:

with ratings_by_user as (
select occupation, user_id, count(*) num_ratings
from ratings
group by 1,2
),

max_ratings_by_occupation as (
select occupation, max(num_ratings) as max_ratings
from ratings_by_user
group by 1
),

select occupation, user_id
from ratings_by_user
inner join max_ratings_by_occupation
using (occupation)
where num_ratings = max_ratings

, копируем все, включая скобки с WITH, и вставляем его перед использованием псевдонима.

шаг 1, вырезаем Rating_by_user и вставьте его везде, где используется Rating_by_user (дважды)



--cut from here
with ratings_by_user as ,

max_ratings_by_occupation as (
select occupation, max(num_ratings) as max_ratings
from 
  --paste to here
  (
    select occupation, user_id, count(*) num_ratings
    from ratings
    group by 1,2
  ) ratings_by_user
group by 1
),

select occupation, user_id
from
--and also paste to here 
(
  select occupation, user_id, count(*) num_ratings
  from ratings
  group by 1,2
) ratings_by_user
inner join max_ratings_by_occupation
using (occupation)
where num_ratings = max_ratings

шаг 2, вставьте max_ratings_by_occupation и вставьте его туда, где он используется:

with ratings_by_user as ,

--cut from here
max_ratings_by_occupation as ,

select occupation, user_id
from
(
  select occupation, user_id, count(*) num_ratings
  from ratings
  group by 1,2
) ratings_by_user
inner join 

--paste to here
(
  select occupation, max(num_ratings) as max_ratings
  from 
  (
    select occupation, user_id, count(*) num_ratings
    from ratings
    group by 1,2
  ) ratings_by_user
  group by 1
) max_ratings_by_occupation

using (occupation)
where num_ratings = max_ratings

шаг 3, очистите Пустой с


select occupation, user_id
from
(
  select occupation, user_id, count(*) num_ratings
  from ratings
  group by 1,2
) ratings_by_user
inner join 
(
  select occupation, max(num_ratings) as max_ratings
  from 
  (
    select occupation, user_id, count(*) num_ratings
    from ratings
    group by 1,2
  ) ratings_by_user
  group by 1
) max_ratings_by_occupation

using (occupation)
where num_ratings = max_ratings

Это было бы началом для оптимизации / переписывания. Сложность заключалась в том, что он дважды использовал Rating_by_user, поэтому на шаге 1

* 1024 потребовалось две вставки. Ваша попытка переформатирования не удалась, потому что вы пытались использовать на внешнем уровне набор результатов, который только существовал на внутреннем уровне:
select occupation, user_id, count(*) as num_ratings
from 

( --max_ratings_table available inside these brackets
    select occupation, max(num_ratings) max_ratings 
    from ( 
        select occupation, user_id, count(*) num_ratings
        from users
        group by 1,2
        ) as ratings_table
    group by 1
    ) as max_ratings_table
  --end of max_ratings_table availability
) 

inner join ratings on ratings.occupation = max_ratings_table.occupation
--                                         ^^^^^^^^^^^^^^^^^
--                                       mrt not available here
where max_ratings = num_ratings
...