SQL select: двумерный выбор с переменным количеством столбцов - PullRequest
2 голосов
/ 14 июня 2009
CREATE TABLE activities(activityid, name);
CREATE TABLE activity_scores(activityid, studentid, score);   
CREATE TABLE students (id, name);

Есть ли способ написать один запрос SELECT, который даст один результат для каждого учащегося в этом формате?

studentid | studentname | activity1_score | activity2_score | activity3_score [...]

Тривиально выполнить несколько запросов:

for each studentid in "select id from students":
    print studentid
    for each activity in "select activityid from activities":
        select score from activity_scores where studentid = studentid
        print score

(псевдокод, я знаю, что это не точно)

Конечно, есть способ создать этот результат с помощью одного запроса SELECT, верно?

Ответы [ 6 ]

3 голосов
/ 14 июня 2009

MySQL, SQLite и, возможно, другие РСУБД имеют что-то под названием GROUP_CONCAT,
который должен делать что-то вроде того, что вы хотите (не проверено - не знаю ваше условие соединения в таблице activity_scores):

SELECT   students.studentid
         , students.studentname
         , GROUP_CONCAT(activity_scores.score)

FROM     activity_scores 
         INNER JOIN activities 
         ON activities.activityid = activity_scores.activityid
         INNER JOIN students 
         ON students.studentid = activities.studentid

GROUP BY students.studentid 
         , students.studentname

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

  • доступ к данным / сбор
  • представление данных
2 голосов
/ 14 июня 2009

Вы в основном ищете сводную таблицу. Если вы просто хотите использовать чистый ANSI SQL, то сделать это невозможно. SQL генерирует только наборы результатов с предсказуемым количеством столбцов (не считая select *).

Однако может существовать технологический способ сделать это. Какой движок базы данных вы используете? SQL Server 2005 имеет возможность сделать сводную таблицу.

1 голос
/ 14 июня 2009

Один из наиболее часто задаваемых вопросов по SO .

Причина, по которой это не поддерживается в ANSI SQL, заключается в том, что набор результатов не является четко определенным - он будет иметь произвольно изменяющееся количество столбцов.

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

1 голос
/ 14 июня 2009

Эта форма результирующего набора нарушает реляционную алгебру (на которой основан SQL). См. Пост антипаттерна SQL № 2 Какие наиболее распространенные анти-паттерны SQL?

Вы должны выполнить этот запрос и отформатировать результаты на клиенте:

SELECT s.name, a.name, x.score
FROM Activity_Score as x
  JOIN Students s
  ON x.StudentID = s.StudentID
  JOIN Activity a
  ON x.ActivityID = a.ActivityID
ORDER BY s.name, a.name, x.score
1 голос
/ 14 июня 2009

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

SELECT s.id, s.name,
  (SELECT score FROM activity_scores as JOIN activities a ON a.activityid = as.activityid WHERE studentid = s.id AND a.activityname = 'Basketball') basketball_score,
  (SELECT score FROM activity_scores as JOIN activities a ON a.activityid = as.activityid WHERE studentid = s.id AND a.activityname = 'Football') football_score,
  ...

Обычно это называется кросс-таблицей. Если вы хотите сделать это динамически, то это сложнее, и вам, вероятно, придется прибегнуть либо к коду, либо к хранимой процедуре, поэтому это будет зависеть от вашей базы данных. Вот пример с использованием SQL Server .

0 голосов
/ 28 июля 2009

В SQL Server 2005/2008 вы можете попытаться вернуть задания / оценки для каждого учащегося в виде набора xml. Не идеально, но работает. Что-то вроде:

SELECT s.name, 
(select a.name, x.score FROM FROM Activity_Score as x  
JOIN Activity a  ON x.ActivityID = a.ActivityID 
WHERE x.StudentID = s.StudentID FOR XML AUTO) Activities
FROM Students s
ORDER BY s.name
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...