получить первый ряд для каждой группы SQL - PullRequest
1 голос
/ 01 марта 2020

У меня есть данные, как показано ниже. Я хотел бы получить лучший выбор для каждого пола из следующих данных

subjectID <- c("1", "2", "1", "0", "1", "0", "0", "1", "0", "2", 
       "0", "0", "2", "2","2","1","2","1","0","2")
gender <- c("M", "M", "F", "M", "M", "F", "M", "M", "M", "F", 
    "M", "F", "M", "M", "F","M", "F", "M", "F",  "F")

 selection <- data.frame(subjectID, gender)
       subjectID <- c("1", "2", "0")
       subject <- c("Maths", "Music",  "English")

    subjects <- data.frame(subjectID, subject)

Я попытался отобразить варианты в порядке убывания, как показано ниже:

 favourite <- sqldf("SELECT  a.gender, b.subject, COUNT(a.subjectID) as `no of selections`
              FROM selection a
              JOIN subjects b
              ON (a.subjectID  = b.subjectID )
              GROUP BY a.subjectID, a.gender
              ORDER BY a.gender, `no of selections` DESC
              ")

НО, я хотел бы чтобы получить следующую таблицу, где я получаю лучший выбор для каждого пола:

gender <- c("F", "M")
subjects <- c("Music", "Maths")
mostfav <- data.frame(gender, subjects)

Ответы [ 2 ]

1 голос
/ 01 марта 2020

Если вы используете MySQL 8.0, вы можете использовать RANK() в подзапросе для ранжирования записей по количеству субъектов для каждого пола и фильтрации по верхней записи по группе во внешнем запросе (если есть верхние связи , RANK() сохраняет их):

SELECT gender, subject, no_of_selections
FROM (
    SELECT  
        se.gender, 
        su.subject, 
        COUNT(*) as no_of_selections,
        RANK() OVER(PARTITION BY se.gender ORDER BY COUNT(*) DESC) rn
    FROM selection se
    JOIN subjects su ON se.subjectID  = su.subjectID
    GROUP BY se.subjectID, se.gender, su.subject
) t
WHERE rn = 1
ORDER BY gender DESC

В более ранних версиях, когда оконные функции недоступны, один из вариантов - это фильтрация с предложением having, которое возвращает счетчик верхов по полу:

SELECT  
    se.gender, 
    su.subject, 
    COUNT(*) as no_of_selections
FROM selection se
JOIN subjects su ON se.subjectID  = su.subjectID
GROUP BY se.subjectID, se.gender, su.subject
HAVING COUNT(*) = (
    SELECT COUNT(*) 
    FROM selection se1
    WHERE se1.gender = se.gender
    GROUP BY se1.subjectID, se1.gender
    ORDER BY COUNT(*) DESC
    LIMIT 1
)

Примечания:

  • Я изменил псевдонимы таблицы, чтобы сделать их более значимыми

  • Вы должны столбец subject, чтобы предложение GROUP BY, чтобы сделать ваш запрос работоспособным в режиме sql ONLY_FULL_GROUP_MODE, который по умолчанию включен, начиная с MySQL 5.7

1 голос
/ 01 марта 2020

Если я правильно понимаю, вы можете использовать оконные функции в SQL:

SELECT gs.*
FROM (SELECT s.gender, su.subject, COUNT(*) as cnt,
             ROW_NUMBER() OVER (PARTITION BY s.gender ORDER BY COUNT(*) DESC) as seqnum
      FROM selection s JOIN
           subjects su
           ON su.subjectID  = s.subjectID
      GROUP BY s.gender, su.subject
     ) gs
WHERE seqnum = 1;
...