2010-06-25 3 views
24

У меня есть таблица базы данных Sql, подобный следующему:Как повернуть строки в столбцы (пользовательские поворотными)

Day Period Subject 

Mon 1   Ch 
Mon 2   Ph 
Mon 3   Mth 
Mon 4   CS 
Mon 5   Lab1 
Mon 6   Lab2 
Mon 7   Lab3 
Tue 1   Ph 
Tue 2   Ele 
Tue 3   Hu 
Tue 4   Ph 
Tue 5   En 
Tue 6   CS2 
Tue 7   Mth 

Я хотел бы она отображается следующим образом: Вид кросс-таблицы или Pivot

Day P1 P2 P3 P4 P5 P6 P7 

Mon Ch Ph Mth CS2 Lab1 Lab2 Lab3 
Tue Ph Ele Hu Ph En CS2 Mth 

Что было бы идеальным способом сделать это? Может кто-нибудь, пожалуйста, покажите мне код Sql, пожалуйста?

ответ

17

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

SELECT 
    dy, 
    MAX(CASE WHEN period = 1 THEN subj ELSE NULL END) AS P1, 
    MAX(CASE WHEN period = 2 THEN subj ELSE NULL END) AS P2, 
    MAX(CASE WHEN period = 3 THEN subj ELSE NULL END) AS P3, 
    MAX(CASE WHEN period = 4 THEN subj ELSE NULL END) AS P4, 
    MAX(CASE WHEN period = 5 THEN subj ELSE NULL END) AS P5, 
    MAX(CASE WHEN period = 6 THEN subj ELSE NULL END) AS P6, 
    MAX(CASE WHEN period = 7 THEN subj ELSE NULL END) AS P7 
FROM 
    Classes 
GROUP BY 
    dy 
ORDER BY 
    CASE dy 
     WHEN 'Mon' THEN 1 
     WHEN 'Tue' THEN 2 
     WHEN 'Wed' THEN 3 
     WHEN 'Thu' THEN 4 
     WHEN 'Fri' THEN 5 
     WHEN 'Sat' THEN 6 
     WHEN 'Sun' THEN 7 
     ELSE 8 
    END 
  • Я изменил некоторые имена столбцов, чтобы избежать зарезервированные слова
+0

+1: Вы были быстрее и имеют ORDER BY , Поэтому я просто добавлю: как вы можете видеть, динамические столбцы потребуют использования динамического SQL. Существует синтаксис ANSI PIVOT, но он поддерживается только SQL Server 2005+ и Oracle 11g. –

+0

В настоящее время я делаю это в SQLite, но это довольно интенсивная операция. Кто-нибудь знает, есть ли более эффективное решение? – EnemyBagJones

+0

Я не верю, что SQLite имеет любую встроенную опорную функцию, поэтому, вероятно, это то, за что вы застряли. Я не использую SQLite, хотя, возможно, у кого-то, у кого больше опыта работы с этим конкретным продавцом SQL, есть идея лучше. –

1

Вы можете попробовать ...

SELECT DISTINCT Day, 
     (SELECT Subject 
      FROM my_table mt2 
      WHERE mt2.Day = mt.Day AND 
        Period = 1) AS P1, 
     (SELECT Subject 
      FROM my_table mt2 
      WHERE mt2.Day = mt.Day AND 
        Period = 2) AS P2, 
    . 
    . 
    etc 
    . 
    . 
    . 
    (SELECT Subject 
     FROM my_table mt2 
     WHERE mt2.Day = mt.Day AND 
       Period = 7) AS P7 
FROM my_table mt; 

, но я не могу сказать, что это очень нравится. Лучше, чем ничего.

1

Использование кросс применить к получить все значения в формате с разделителями-запятыми в одном столбце. вместо «7» разных столбцов. Следующий запрос может быть использован для любого отображения столбцов строки>

SELECT DISTINCT Day, [DerivedColumn] FROM <Table> A CROSS APPLY (SELECT Period + ',' FROM <Table> B WHERE A.Day = B.Day Order By Period FOR XML PATH('')) AS C (DerivedColumn) 

вы получите [Ch, Ph, MTH, CS2, LAB1, LAB2, Lab3] в одной колонке для пна и так далее ... Вы может использовать это как таблицу для запроса какого-либо конкретного Дня.

Надеется, что это помогает

12

Просто упаковываю вы хотите новый метод школы. (Оператор Pivot должен работать в SQL2005 +, в VALUES бит для примера данных только SQL2008)

WITH ExampleData AS 
(
SELECT X.* 
    FROM (VALUES 
('Mon', 1, 'Ch'), 
('Mon', 2, 'Ph'), 
('Mon', 3, 'Mth'), 
('Mon', 4, 'CS'), 
('Mon', 5, 'Lab1'), 
('Mon', 6, 'Lab2'), 
('Mon', 7, 'Lab3'), 
('Tue', 1, 'Ph'), 
('Tue', 2, 'Ele'), 
('Tue', 3, 'Hu'), 
('Tue', 4, 'Ph'), 
('Tue', 5, 'En'), 
('Tue', 6, 'CS2'), 
('Tue', 7, 'Mth') 
) AS X (Day, Period, Subject) 
) 

SELECT Day, [1] AS P1, [2] AS P2,[3] AS P3, [4] AS P4, [5] AS P5,[6] AS P6,[7] AS P7 
FROM ExampleData 
PIVOT 
( 
Max(Subject) 
FOR Period IN ([1], [2],[3],[4], [5],[6], [7]) 
) AS PivotTable; 

Результат

Day P1 P2 P3 P4 P5 P6 P7 
---- ---- ---- ---- ---- ---- ---- ---- 
Mon Ch Ph Mth CS Lab1 Lab2 Lab3 
Tue Ph Ele Hu Ph En CS2 Mth 
+1

Почему Макс (тема)? Это потому, что PIVOT должен выполнять агрегатную функцию? – JBRWilkinson

+1

@JBRWilkinson Да. В точку. Для комбинации «День/Период» должна быть только одна соответствующая запись, поэтому «MIN» будет работать одинаково хорошо. –

0
with pivot_data as 
(
select [day], -- groping column 
period, -- spreading column 
subject -- aggreate column 
from pivot_tb 
) 
select [day], [1] AS P1, [2] AS P2,[3] AS P3, [4] AS P4, [5] AS P5,[6] AS P6,[7] AS P7 
from pivot_data 
pivot (max(subject) for period in ([1], [2],[3],[4], [5],[6], [7])) as p; 
1
DECLARE @TIMETABLE TABLE (
    [Day]  CHAR(3), 
    [Period] TINYINT, 
    [Subject] CHAR(5) 
) 
INSERT INTO @TIMETABLE([Day], [Period], [Subject]) 
VALUES 
    ('Mon', 1, 'Ch'), 
    ('Mon', 2, 'Ph'), 
    ('Mon', 3, 'Mth'), 
    ('Mon', 4, 'CS'), 
    ('Mon', 5, 'Lab1'), 
    ('Mon', 6, 'Lab2'), 
    ('Mon', 7, 'Lab3'), 
    ('Tue', 1, 'Ph'), 
    ('Tue', 2, 'Ele'), 
    ('Tue', 3, 'Hu'), 
    ('Tue', 4, 'Ph'), 
    ('Tue', 5, 'En'), 
    ('Tue', 6, 'CS2'), 
    ('Tue', 7, 'Mth') 

SELECT 
    [Day], 
    MAX(CASE [Period] WHEN 1 THEN [Subject] END) AS P1, 
    MAX(CASE [Period] WHEN 2 THEN [Subject] END) AS P2, 
    MAX(CASE [Period] WHEN 3 THEN [Subject] END) AS P3, 
    MAX(CASE [Period] WHEN 4 THEN [Subject] END) AS P4, 
    MAX(CASE [Period] WHEN 5 THEN [Subject] END) AS P5, 
    MAX(CASE [Period] WHEN 6 THEN [Subject] END) AS P6, 
    MAX(CASE [Period] WHEN 7 THEN [Subject] END) AS P7 
FROM @TIMETABLE 
GROUP BY [Day] 
+0

Является ли это SQL ANSI? – ViniciusPires

Смежные вопросы