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

Я предоставил инструкции для создания двух примеров таблиц для моего вопроса ниже.

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

Как бы вы написали оператор выбора, который объединяет две таблицы, и все данные classID повторяются в одном и том же столбце, как в примере ниже:

CREATE TABLE Student (
 StudentId int,
 FirstName VarChar (255),
 LastName VarChar (255)
);

CREATE TABLE Classes (
 StudentId int,
 ClassId int,
 ClassName VarChar (255),
 ClassCost int
);

INSERT INTO Student (StudentId, FirstName, LastName)
VALUES 
(123, 'Carol', 'Dwek'),
(456, 'Cal', 'Newport');

INSERT INTO Classes (StudentId, ClassId, ClassName,ClassCost)
VALUES 
(123, 972, 'Psychology',30),
(456, 214, 'Focus',99),
(123, 903, 'Sociology',30),
(456, 851, 'Meditation',99),
(456, 911, 'Reading',20),
(456, 111, 'Deep Work',50),
(456, 117, 'Time Management',25),
(456, 999, 'Goal Setting',50);

Полученные результаты:

Добавьте тег для используемой СУБД. Решение зависит от этого. Данные должны быть размещены в виде форматированной текстовой таблицы, а не изображения. Поиск по теме «объединить связанные записи».

June7 17.02.2023 22:09

Привет, я добавил больше деталей. Вы говорите использовать конкатенацию, а не сводное решение?

madQuestions 17.02.2023 22:21

Зависит от того, что вы хотите сделать с выводом. Попробуйте и отредактируйте свой вопрос с оператором SQL и возникшими проблемами. Я ожидаю, что в вашем случае поворот будет более сложным, потому что нет поля, которое могло бы служить источником для заголовков столбцов, его нужно было бы вычислить, возможно, с помощью функции ROW_NUMBER. Кроме того, вы хотите использовать две точки данных — ClassID и ClassName.

June7 17.02.2023 22:34

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

madQuestions 17.02.2023 22:46

Язык SQL имеет очень строгое правило: он ДОЛЖЕН знать обо ВСЕХ столбцах в результатах во время компиляции запроса, прежде чем просматривать ЛЮБЫЕ данные таблицы. Если вы этого не знаете, вы НЕ сможете повернуть данные в одном запросе. Вместо этого вам нужно сделать это в три шага: 1) Запустите запрос, чтобы узнать, какие у вас столбцы. 2) Создайте новый динамический запрос на основе результатов из 1. 3) Запустите запрос из 2.

Joel Coehoorn 17.02.2023 22:56
[cont] Теперь, если у вас есть максимальное количество повторяющихся столбцов, вы можете обойти это, присоединившись к целевой таблице (таблицам) несколько раз: один раз для каждого набора повторяющихся столбцов. Но это имеет тенденцию быть глупо медленным. Это также противоречит теории реляционных множеств, лежащей в основе современных БД, так что вам обычно НАМНОГО лучше выполнять эту работу в клиентском коде или инструменте отчетности.
Joel Coehoorn 17.02.2023 22:59

Что вы используете для графического интерфейса? Сводка доступа не имеет этого ограничения. Однако это может затруднить создание стабильного отчета на основе разворота (он же CROSSTAB). Другая трудность в Access SQL заключается в вычислении номера строки группы, поскольку он не поддерживает функцию ROW_NUMBER. stackoverflow.com/questions/64400911/pivot-query-in-ms-acces‌​s

June7 18.02.2023 00:08

Если вы используете Access в качестве графического пользовательского интерфейса, вы можете связать его с таблицей SQLServer, построить запрос Pass-Through для построения набора данных с помощью функции Row_Number, а затем построить CROSSTAB в обычном SQL Access с PTQ в качестве источника, хотя все еще есть сложности с двумя опорными точками. У Access есть способы справиться с этим, но не просто.

June7 18.02.2023 00:38

Обзор: stackoverflow.com/questions/7822004/… и stackoverflow.com/questions/70804530/…

June7 18.02.2023 00:52
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
9
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

WITH NumberedClasses As (
   SELECT *, row_number() over (partition by StudentID order by ClassID) rn
   FROM Classes
)
SELECT s.*
    ,c1.ClassId, c1.ClassName, c1.ClassCost
    ,c2.ClassID, c2.ClassName, c2.ClassCost
    -- ...
    ,cn.ClassID, cn.ClassName, cn.ClassCost
FROM Student s
LEFT JOIN NumberedClasses c1 ON c1.StudentID = s.StudentID AND c1.rn = 1
LEFT JOIN NumberedClasses c2 ON c2.StudentID = s.StudentID And c2.rn = 2
-- ...
LEFT JOIN NumberedClasses cn ON cn.StudentID = s.StudentID And cn.rn = {n}

Примечание: это, как правило, МЕДЛЕННО — и ​​не просто медленно; мы говорим о нескольких минутах (или дольше), если у вас есть разумный объем данных. И да, вам действительно нужно повторить себя в двух местах столько раз, сколько у вас есть возможных зачислений в класс.

Здесь также стоит упомянуть, что этот вид PIVOT противоречит формальной теории множеств, лежащей в основе всех реляционных баз данных. По этой причине обычно НАМНОГО лучше выполнять эту работу в клиентском коде или инструменте создания отчетов.

Ответ принят как подходящий

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

Тот же порядок, который обеспечивает нумерацию строк (StudentId, ClassId), также может использоваться для группировки по StudentId (предусмотрено primary key (StudentId, ClassId) на плане ниже)

Тем не менее, запрос все еще довольно уродлив, и его лучше всего выполнять в приложении (если есть приложение, и вы не просто запускаете специальные запросы в SSMS для просмотра результатов там)

With Numbered As
(
SELECT *,
       rn = row_number() over (PARTITION BY StudentID ORDER BY ClassID) 
FROM Classes
), Pivoted As
(
SELECT StudentId, 
       ClassId1 = MAX(CASE WHEN rn = 1 THEN ClassId END), 
       ClassName1 = MAX(CASE WHEN rn = 1 THEN ClassName END), 
       ClassCost1 = MAX(CASE WHEN rn = 1 THEN ClassCost END),
       ClassId2 = MAX(CASE WHEN rn = 2 THEN ClassId END), 
       ClassName2 = MAX(CASE WHEN rn = 2 THEN ClassName END), 
       ClassCost2 = MAX(CASE WHEN rn = 2 THEN ClassCost END),
       ClassId3 = MAX(CASE WHEN rn = 3 THEN ClassId END), 
       ClassName3 = MAX(CASE WHEN rn = 3 THEN ClassName END), 
       ClassCost3 = MAX(CASE WHEN rn = 3 THEN ClassCost END),
       ClassId4 = MAX(CASE WHEN rn = 4 THEN ClassId END), 
       ClassName4 = MAX(CASE WHEN rn = 4 THEN ClassName END), 
       ClassCost4 = MAX(CASE WHEN rn = 4 THEN ClassCost END),
       ClassId5 = MAX(CASE WHEN rn = 5 THEN ClassId END), 
       ClassName5 = MAX(CASE WHEN rn = 5 THEN ClassName END), 
       ClassCost5 = MAX(CASE WHEN rn = 5 THEN ClassCost END),
       ClassId6 = MAX(CASE WHEN rn = 6 THEN ClassId END), 
       ClassName6 = MAX(CASE WHEN rn = 6 THEN ClassName END), 
       ClassCost6 = MAX(CASE WHEN rn = 6 THEN ClassCost END)
FROM Numbered
GROUP BY StudentId
)
SELECT S.FirstName, S.LastName, P.*
FROM   Student S
       JOIN Pivoted P
         ON P.StudentId = S.StudentId 

Другие вопросы по теме