Извлеките только первую строку для каждого учащегося

#sql #postgresql

Вопрос:

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

 student_id           math           chemistry        science
 100                  A                B                C              <--------
 100                  B                A                D
 100                  D                F                C
 200                  B                A                C              <--------
 300                  C                D                F              <--------
 300                  A                A                A              
 400                  F                C                B              <--------
 400                  B                A                C              
 500                  A                B                A              <--------
 

Я хочу получить первую строку в соответствии с идентификатором student_id, как описано ниже.

Запрошено в PostgreSQL:

 student_id           math           chemistry        science
 100                  A                B                C
 200                  B                A                C
 300                  C                D                F
 400                  F                C                B
 500                  A                B                A 
 

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

1. Таблицы SQL представляют собой неупорядоченные наборы. «Первой» строки нет, если только в столбце не указан порядок.

2. Итак, вы разъясняете, что такого способа выполнения этой задачи НЕ существует!

3. @JakeWagner Вы можете получить результат, но то, что считается «первым», будет не определено.

4. Если бы у вас было что-то для упорядочения строк, вы бы использовали для этого оконную функцию rank , например.

5. Будь добрым. Вместо этого возьмите их самые высокие оценки 😀

Ответ №1:

В тот момент, когда вы решаете стратегию заказа (например, добавляете столбец, в котором записывается дата сдачи экзаменов, и определяете «первый» как «самый последний»), вы можете получить «первую» строку с чем-то вроде

 SELECT * 
FROM(
  SELECT *, ROW_NUMBER() OVER(PARTITION BY student_id ORDER BY date_taken DESC) rn 
  FROM yourtable 
) x
WHERE rn = 1
 

ROW_NUMBER создает счетчик приращения 1,2,3,4.., который перезапускается с 1 для каждого отдельного идентификатора учащегося, а строки нумеруются в порядке убывания даты (поэтому самая последняя получает 1). К тому времени, требуя, чтобы rn был равен 1, мы получим самую последнюю строку

Вы можете решить поставить ученику лучшие оценки, и, возможно, мы могли бы использовать значение ascii для оценки (A равно 65, B равно 66 и т. Д.). Если мы сложим баллы, то наименьшая общая сумма (т. Е. порядок по возрастанию) будет лучшим набором оценок (BBB лучше, чем AAF).

 OVER(PARTITION BY student_id ORDER BY ASCII(math) ASCII(chemistry) ASCII(science))
 

Ответ №2:

Это может быть достигнуто с помощью следующего запроса:

 SELECT DISTINCT ON (student_id) student_id, math, chemistry, science
FROM
   student
ORDER BY
   student_id
 

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

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

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

1. Вы не можете полагаться на заказ. Смотрите официальную документацию: postgresql.org/docs/9.0/sql-select.html#SQL-DISTINCT

2. Ах да, я понимаю. Я соответствующим образом отредактировал ответ.

Ответ №3:

Основное решение — использование функции MIN/MAX для агрегирования значений:

 SELECT student_id, MAX(math) math, MAX(chemistry) chemistry, MAX(science) science
FROM
   student
GROUP BY
   student_id