2015-06-18 1 views
2

Я хочу написать запрос, в котором перечислены программы, которые мы предлагаем в моем университете. Программа состоит из, по крайней мере, крупного и, возможно, «варианта», «специальности» и «подспециальности». Каждый из этих четырех элементов подробно описывается кодом, который связывает их с майором.Разбиение столбцов SQL в несколько столбцов на основе определенного значения столбца

Один майор может иметь ноль или более вариантов, один вариант может иметь ноль или больше специальностей, а одна специальность может иметь ноль или более специальностей. И наоборот, майору разрешено иметь никаких связанных с ним вариантов.

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

Моя проблема заключается в том, как хранятся данные. Все данные программы лежит в одной таблице, которая выкладывается, как это:

+----------------+---------------+------+ 
| program_name | program_level | code | 
+----------------+---------------+------+ 
| Animal Science | Major   | 1 | 
| Equine   | Option  | 1 | 
| Dairy   | Option  | 1 | 
| CLD   | Major   | 2 | 
| Thesis   | Option  | 2 | 
| Non-Thesis  | Option  | 2 | 
| Development | Specialty  | 2 | 
| General  | Subspecialty | 2 | 
| Rural   | Subspecialty | 2 | 
| Education  | Major   | 3 | 
+----------------+---------------+------+ 

Желаемая выход будет выглядеть примерно так:

+----------------+-------------+----------------+-------------------+------+ 
| major_name  | option_name | specialty_name | subspecialty_name | code | 
+----------------+-------------+----------------+-------------------+------+ 
| Animal Science | Equine  |    |     | 1 | 
| Animal Science | Dairy  |    |     | 1 | 
| CLD   | Thesis  | Development | General   | 2 | 
| CLD   | Thesis  | Development | Rural    | 2 | 
| CLD   | Non-Thesis | Development | General   | 2 | 
| CLD   | Non-Thesis | Development | Rural    | 2 | 
| Education  |    |    |     | 3 | 
+----------------+-------------+----------------+-------------------+------+ 

До сих пор я пытался создать четыре запроса, которые соединяются на этом «код», каждый из которых выбирается на основе другого «program_level». Однако поля не сочетаются должным образом.

+1

Вы имеете 'Specialty' в данных выборки, но использовать' Speciality' в соединении (то же самое для 'Subspeciality'), и поэтому ваши соединения терпят неудачу. Если вы исправите эти опечатки, ваше заявление отлично работает –

+0

@a_horse_with_no_name Хороший улов, мой плохой :) Я исправил свой запрос ниже. –

ответ

0

Я не могу найти проще, чем это:

/* Replace @Programs with the name of your table */ 

SELECT majors.program_name, options.program_name, 
    specs.program_name, subspecs.program_name, majors.code 
FROM @Programs majors 
LEFT JOIN @Programs options 
    ON majors.code = options.code AND options.program_level = 'Option' 
LEFT JOIN @Programs specs 
    ON options.code = specs.code AND specs.program_level = 'Specialty' 
LEFT JOIN @Programs subspecs 
    ON specs.code = subspecs.code AND subspecs.program_level = 'Subspecialty' 
WHERE majors.program_level = 'Major' 

EDIT: исправлена ​​опечатка «Специфическое ality ", он должен работать сейчас.

+0

Я думаю, что это правильный трек ... однако, когда я запускаю это, я получаю набор результатов с нулями для каждой строки в spec и subspec колонка. Посмотреть мой пост Редактировать –

+0

Это очень странно. Я выполнил запрос в SQL Server, используя переменную таблицы, и результат - именно тот, который вы ищете. Я могу вставить весь код для вас, но я бы предложил сначала проверить, что строки, используемые в условиях, соответствуют значениям, хранящимся в базе данных (т. Е. Вы можете иметь пробелы в полях 'program_level'). –

+0

После исправления он отлично работает! Большое спасибо, редактируя сообщение сейчас. –

0

Используйте подзапросы, чтобы создать то, что вы хотите.

КОД:

SELECT(SELECT m.program_name FROM yourtable m WHERE m.program_level = 'Major' AND y.program_name = m.program_name) AS major_name, 
     (SELECT o.program_name FROM yourtable o WHERE o.program_level = 'Option' AND y.program_name = o.program_name) AS Option_name, 
     (SELECT s.program_name FROM yourtable s WHERE s.program_level = 'Specialty' AND y.program_name = s.program_name) AS Specialty_name, 
     (SELECT ss.program_name FROM yourtable ss WHERE ss.program_level = 'Subspecialty' AND y.program_name = ss.program_name) AS Subspecialty_name, code 
FROM yourtable y 

ВЫВОД:

major_name  Option_name Specialty_name Subspecialty_name code 
Animal Science (null)  (null)   (null)    1 
(null)   Equine  (null)   (null)    1 
(null)   Dairy  (null)   (null)    1 
CLD    (null)  (null)   (null)    2 
(null)   Thesis  (null)   (null)    2 
(null)   Non-Thesis (null)   (null)    2 
(null)   (null)  Development  (null)    2 
(null)   (null)  (null)   General    2 
(null)   (null)  (null)   Rural    2 
Education  (null)  (null)   (null)    3 

SQL Скрипки: http://sqlfiddle.com/#!3/9b75a/2/0

+0

спасибо за быстрый ответ. Это, по сути, тот же самый результат, который я получал, - есть ли способ перечислить связанные майоры/предыдущие столбцы в каждой строке, как в моем примере вывода? –

+0

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

+0

@Amine Абсолютно, если возможно, эту структуру данных следует переделать как отдельные столбцы – Matt

0

Ключом к решению здесь является осознание того, что на самом деле существуют несколько объектов, хранящихся в одной и той же таблице, и что эти объекты должны быть сначала «извлечены».

Это можно сделать с помощью простого подзапроса, который фильтрует столбец program_level.

select ma.major_name, op.option_name, sp.specialty_name, ss.subspecialty_name, ma.code 
from 
    (select code, program_name as major_name 
    from programs where program_level = 'Major') ma 
left outer join 
    (select code, program_name as option_name 
    from programs where program_level ='Option') op 
    on ma.code = op.code  
left outer join 
    (select code, program_name as specialty_name 
    from programs where program_level ='Specialty') sp 
    on op.code = sp.code 
left outer join 
    (select code, program_name as subspecialty_name 
    from programs where program_level ='Subspecialty') ss 
    on sp.code = ss.code 
order by ma.code asc, 
     ma.major_name asc, 
     op.option_name asc, 
     sp.specialty_name asc, 
     ss.subspecialty_name asc; 

Это дает вам выход вы требовали:

MAJOR_NAME  OPTION_NAME SPECIALTY_NAME SUBSPECIALTY_NAME CODE 
Animal Science Dairy  ?    ?     1 
Animal Science Equine  ?    ?     1 
CLD    Non-Thesis Development  General    2 
CLD    Non-Thesis Development  Rural    2 
CLD    Thesis  Development  General    2 
CLD    Thesis  Development  Rural    2 
Education  ?   ?    ?     3 

Cheers, Lars