Удаление дубликатов на основе ранга после объединения в SQL-запросе

#mysql #sql

#mysql #sql

Вопрос:

Я использую MySQL 5.6. У меня есть таблица SQL со списком пользователей:

 id name
1  Alice
2  Bob
3  John
 

и таблица SQL со списком подарков для каждого пользователя (пронумерованы в порядке предпочтения):

 id gift       rank
1  balloon    2
1  shoes      1
1  seeds      3
1  video-game 1
2  computer   2
3  shoes      2
3  hat        1
 

И я хотел бы получить список предпочтительных подарков для каждого пользователя (самый высокий ранг — если два подарка имеют одинаковый ранг, выбирайте только один случайным образом) (бонус: если список можно рандомизировать, это было бы идеально!):

 id name  gift     rank
2  Bob   computer 2
1  Alice shoes    1
3  John  hat      1
 

Я пытался использовать предложение GROUP BY, но без какого-либо успеха.

Комментарии:

1. какой движок вы используете?

2. Я использую MySQL!

3. @klaus всегда добавляйте правильные теги к вопросу, чтобы люди, просматривающие определенные фильтры, могли его видеть

4. Хорошо, я виноват. Тип базы данных — InnoDB.

5. Какую версию MySQL вы используете? Ранжирование стало простым с MySQL 8.

Ответ №1:

Учет ранга как части ваших данных; Без использования оконных функций или сложных вложенных запросов

 SELECT u.id, u.name, g.gift
FROM users u
JOIN gifts g ON g.id = u.id
LEFT JOIN gifts g2 ON g2.id = g.id AND g2.rank > g.rank
WHERE g2.id IS NULL;

 

Добавлена ссылка http://sqlfiddle.com /#!9/62f59e/15/0

Комментарии:

1. Это не работает. У меня дублированные имена, а столбец «ранг» заполнен «НУЛЕВЫМ»…

2. игнорируйте столбцы справа; удалены только первые 3 @klaus

3. ОК. В вашем примере вам нужно переключиться с g2.rank> g.rank на g2.rank < g.rank

4. И если я добавлю «вставить в значения подарков (1, «видеоигра», 1);», я получу две строки для Алисы… Я хотел бы только один… как вы могли это сделать?

5. @klaus Затем вы можете сгруппировать по идентификатору, и он покажет только 1

Ответ №2:

Вы можете использовать row_number , чтобы получить одну строку для каждого пользователя. (Mysql 8.0 )

 SELECT A.ID,NAME,GIFT,`RANK` FROM USERS A
LEFT JOIN (
    SELECT ID,GIFT,`RANK` FROM 
        (SELECT *,ROW_NUMBER() OVER(PARTITION BY ID ORDER BY `RANK` ASC) AS RN  FROM X) X
    WHERE RN =1
) B 
ON A.ID= B.ID
 

Ответ №3:

Я не знаю DB, что вы используете. И я не эксперт в SQL (у меня может быть какая-то ошибка в next). Но я думаю, что это не сложно.

Поэтому я могу дать вам просто совет, что вы должны думать постепенно. Позвольте мне написать.

Сначала все, что мне нужно, это самый высокий ранг. Итак, я должен получить это.

 SELECT  MAX(RANK)
FROM    GIFT
GROUP BY ID
 

И тогда я думаю, что мне нужно получать подарки от этого ранга.

 SELECT GIFT.*
FROM   GIFT
INNER JOIN(
  SELECT ID, MAX(RANK)
  FROM GIFT
  GROUP BY ID
) filter ON GIFT.ID = filter.ID AND GIFT.RANK = filter.RANK
 

Я думаю, что это таблица, которую вы хотите!

Итак, если приведенный ниже код работает, это то, что вы действительно хотите.

 SELECT *
FROM USER
LEFT OUTER JOIN(
  above table
) GIFT ON USER.ID = GIFT.ID
 

Но помните об этом, я сказал, что я не эксперт в SQL. Может быть лучший способ.

Ответ №4:

Прикрепленное изображение Проверка запроса

 SELECT tbluser.id,name,gift,rank into tblrslt
FROM tbluser 
LEFT JOIN tblgifts
ON tbluser.id = tblgifts.id  order by id,rank;

SELECT tt.*
FROM tblrslt tt
INNER JOIN
    (SELECT id, min(rank) AS rank
    FROM tblrslt
    GROUP BY id) groupedtt 
ON tt.id = groupedtt.id 
AND tt.rank = groupedtt.rank order by id

 

Комментарии:

1. Пожалуйста, ознакомьтесь с изображением … Я считаю, что это сработает..

2. У меня следующая ошибка: #1327 — Необъявленная переменная: tblrslt 🙁

3. Пожалуйста, проверьте скрипку sqlfiddle.com /#!18/5ad59/19

Ответ №5:

В версиях MySQL старше 8 у вас нет доступных функций ранжирования. Вместо этого вы выберете минимальный ранг для каждого пользователя и будете использовать эти ранги для выбора строк подарков. Это означает, что вы дважды обращаетесь к таблице подарков.

Я предлагаю это:

 select *
fron users u
join gifts g 
  on g.id = u.id 
  and (g.id, g.rank) in (select id, min(rank) from gifts group by id)
order by u.id;
 

Если вы также хотите показывать пользователей без подарков, просто измените внутреннее соединение на левое внешнее соединение.

Комментарии:

1. Я попробовал ваш запрос, но если у меня есть несколько подарков с одинаковым рангом (скажем, для Алисы «обувь» с рангом 1 и «видеоигра» с рангом 1) В итоге я получу две записи для Алисы, но мне нужна только одна

2. И весь мой столбец ранга равен «NULL»

3. А, ладно. Вы не упомянули, что у пользователя может быть два подарка с одинаковым рангом. Вы должны добавить это объяснение к своему запросу, а также добавить такой случай к вашим образцам данных.

4. Да, вы правы. Мой плохой. Я обновил образец.