SQL - столбцы для разных категорий

Я новичок в SQL. У меня есть база данных с данными для разных экзаменов, например:

Student Test Grade
--------------------
St1    T1   A
St2    T1   B
St3    T1   B
St1    T2   B
St2    T2   B
St3    T2   A
St1    T3   A
St2    T3   C
St3    T3   B

Затем я хотел бы распечатать отчет с использованием тестов (T1, T2 и T3) в качестве столбцов:

Student  T1   T2   T3
----------------------
St1      A    B    A
St2      B    B    C
St3      B    A    B

Я пробовал разные вещи, но я зациклился на том, как производить такую ​​распечатку. Любая помощь приветствуется!

Ответ 1

Использование:

  SELECT t.student,
         MAX(CASE WHEN t.test = 'T1' THEN t.grade END) AS T1,
         MAX(CASE WHEN t.test = 'T2' THEN t.grade END) AS T2,
         MAX(CASE WHEN t.test = 'T3' THEN t.grade END) AS T3
    FROM TABLE t
GROUP BY t.student

Ответ 2

Я попросил повторить аналогичную question. Вам нужно что-то похожее на сводную таблицу, но это невозможно в SQLite (насколько я знаю).

Ответ 3

Я считаю, что если вы собираетесь расширить эту систему, чтобы включить в нее больше информации, вы могли бы воспользоваться переработкой своей базы данных, я бы построил ее так:

Имя таблицы= Полужирный

Название столбца = курсив

Студенты

  • SID (первичный ключ)
  • Другая информация о студенте

Испытания

  • TID (первичный ключ)
  • Другая информация о тесте

Тест-классы

  • GID (первичный ключ)
  • TID (внешний ключ)
  • SID (внешний ключ)
  • Оценка

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

Первое, что нужно знать, это то, что первичный ключ - это только уникальный идентификатор, он обычно не является частью информации (однако, поскольку он уникален, каждая базовая точка должна иметь разное значение для своего первичного ключа) и внешний ключ это способ ссылки на строку в одной таблице из строки в другой таблице с использованием первичного ключа ссылки: например, здесь SID внешнего ключа в каждом классе ссылается на одного ученика на основе их SID первичного ключа.

например. у ученика есть SID 1, и все его тесты имеют 1 в столбце SID. для учащихся 2, 3, 4 и т.д.

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

Чтобы получить то, что вы хотите от этих таблиц, я бы использовал это (написанное на PHP):

$sql = 'SELECT * FROM Tests ORDER BY TID';
$tempresult = mysql_query($sql);
while($temprow = mysql_fetch_array($tempresult)){
    echo $temprow['TID'];
}

$sql = 'SELECT * FROM Students';
$result = mysql_query($sql);
while($row = mysql_fetch_array($result)){
   echo '\n'.$row['SID'];
   $sql = 'SELECT * FROM Grades WHERE SID='.$row['SID'].' ORDER BY TID';
   $result2 = mysql_query($sql);
   while($row2 = mysql_fetch_array($result2)){
      echo ' '.$rows['Grade'];
   }
}

Вы можете добавить к этому форматирование в операторах эха, а также распечатать любую дополнительную информацию, которую вы хотите добавить. Если у вас есть какие-либо вопросы, спросите их.

РЕДАКТИРОВАТЬ: Я прочитал другие и согласен с тем, что их метод, по всей вероятности, превосходит, единственное, что я не уверен в том, могут ли сводные таблицы расширяться, чтобы обрабатывать различное количество тесты, если это возможно (или вам не нужно), то я предлагаю их метод, иначе я чувствую, что это может иметь место в вашем приложении.

Ответ 4

Существует несколько способов сделать это, оба из которых (в чистом SQL, а не в коде, генерирующем команду SQL) требуют, чтобы количество столбцов было известно и исправлено. Наиболее простой способ реализации:

SELECT eg.Student,
(SELECT Grade from ExamGrade eg1 WHERE eg1.Student = eg.Student AND Test = 'T1') AS T1
(SELECT Grade from ExamGrade eg2 WHERE eg2.Student = eg.Student AND Test = 'T2') AS T2
(SELECT Grade from ExamGrade eg3 WHERE eg3.Student = eg.Student AND Test = 'T3') AS T3
FROM ExamGrade eg

Это будет работать практически в любой среде, включая SQLite, и может быть немного более изящным со скалярной функцией GetTest(), которая будет принимать учащийся и номер теста и возвращать оценку. Однако в любом случае это не является ни исполнительным, ни закрытым для изменения; он будет запрашивать таблицу N-квадратов раз для N тестов, и если вы добавите четвертый тест, этот запрос должен будет измениться, чтобы включить его в отчет.

Если комбинация Student и Test уникальна, и вы работаете в базе данных с функциональностью Pivot (чего, по-видимому, нет в SQLite), вы можете использовать сводный запрос практически с любым агрегатором (MAX/MIN/AVG/SUM набора с одним значением - это значение). В MSS2005 работает следующее:

SELECT Student, T1, T2, T3
FROM (Select Student, Test, Grade FROM ExamGrade) As SourceQuery
PIVOT (MAX(Grade) FOR Test IN (T1, T2, T3)) AS PivotTable

Это будет более впечатляюще, и это намного более элегантно. Списки столбцов по-прежнему не могут быть динамически определены AFAIK, но они тривиальны для генерации, если вы делаете этот запрос из кода приложения или используете встроенный хранимый proc sp_executesql в MS SQL Server для генерации запроса из другого хранимого proc или функция.

Ответ 5

Попробуйте это

SELECT Student, MAX(CASE WHEN Test = 'T1' THEN Grade END) AS T1,
   MAX(CASE WHEN Test = 'T2' THEN Grade END) AS T2,
   MAX(CASE WHEN Test = 'T3' THEN Grade END) AS T3 FROM tablename  GROUP BY Student

Используйте имя таблицы вместо "tablename".