Sql: транспонирование строк в столбцы - PullRequest
2 голосов
/ 13 июля 2011

Рассмотрим приведенный ниже пример, где у меня есть таблица Person , содержащая записи о персонале, и таблица PersonAttribute , которая содержит необязательные атрибуты, связанные с персоной:

Таблица: Персона

ID    Name
1     Joe Bloggs
2     Jane Doe

Таблица PersonAttribute

PersonId  Key         Value
1         Age         27            
2         HairColor   Brown

Как мне написать запрос, который возвращает всех людей с атрибутами, как если бы они были столбцами? Мне нужен набор результатов:

ID    Name        Age    HairColor
1     Joe Bloggs  27     
2     Jane Doe           Brown

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

Обратите внимание, что первичный ключ в таблице PersonAttribute PersonID и Key объединен, поэтому у нас не будет повторяющихся записей для определенного ключа и персоны.

Очевидно, что я мог бы добавить Age и HairColor в качестве полей в таблицу Person и вообще не использовать таблицу PersonAttribute , но это всего лишь пример, иллюстрирующий проблему. На самом деле у меня есть огромное количество пользовательских атрибутов, которые сильно различаются для разных записей о людях, поэтому делать это не практично.

Ответы [ 2 ]

3 голосов
/ 13 июля 2011

Я не могу говорить о MySQL, но в PostgreSQL вы можете использовать функцию кросс-таблицы из tablefunc module:

CREATE OR REPLACE VIEW PersonAttributePivot AS
    SELECT PersonId AS ID, Age, HairColor
    FROM crosstab
    (
       'SELECT PersonId, Key, Value FROM PersonAttribute',
       'SELECT DISTINCT Key FROM PersonAttribute ORDER BY Key'
    )
    AS
    (
        PersonId integer,
        Age text,
        HairColor text
    );

Запрос на присоединение:

SELECT id, name, age, haircolor
FROM Person JOIN PersonAttributePivot USING(id)
ORDER BY id;

Требуемый результат:

 id |    name    | age | haircolor 
----+------------+-----+-----------
  1 | Joe Bloggs | 27  | 
  2 | Jane Doe   |     | Brown
(2 rows)

Как видите, я поставил явный список столбцов в представлении PersonAttributePivot. Я не знаю никакого способа создания "автоматического поворота" с неявным списком столбцов.

EDIT:

Для огромного списка столбцов (при условии всегда text type) в качестве обходного пути я вижу такой немного измененный подход:

Создание динамического типа (здесь тривиально на основе Java):

Class.forName("org.postgresql.Driver");
Connection c =
        DriverManager.getConnection("jdbc:postgresql://localhost/postgres", "postgres", "12345");
Statement s = c.createStatement();
ResultSet rs = s.executeQuery("SELECT DISTINCT Key FROM PersonAttribute ORDER BY Key");
List<String> columns = new ArrayList<String>();

while (rs.next())
    columns.add(rs.getString(1));

System.out.println("CREATE TYPE PersonAttributePivotType AS (");
System.out.println("\tPersonId integer,");
for (int i = 0; i < columns.size(); ++i)
{
    System.out.print("\t" + columns.get(i) + " text");
    if (i != columns.size() - 1)
        System.out.print(",");
    System.out.println();
}
System.out.println(");");

Результат:

CREATE TYPE PersonAttributePivotType AS (
    PersonId integer,
    Age text,
    HairColor text
);

Функция-обертка:

CREATE OR REPLACE FUNCTION crosstabPersonAttribute(text, text)
    RETURNS setof PersonAttributePivotType
    AS '$libdir/tablefunc','crosstab_hash' LANGUAGE C STABLE STRICT;

Автоматическое создание представления:

CREATE OR REPLACE VIEW PersonAttributePivot AS
    SELECT * FROM crosstabPersonAttribute
    (
       'SELECT PersonId, Key, Value FROM PersonAttribute',
       'SELECT DISTINCT Key FROM PersonAttribute ORDER BY Key'
    );

Результат:

TABLE PersonAttributePivot;
 personid | age | haircolor
----------+-----+-----------
        1 | 27  |
        2 |     | Brown
(2 rows)
1 голос
/ 13 июля 2011

Процесс преобразования набора данных на основе строк в набор данных на основе столбцов называется поворотным. Вы можете получить некоторое представление о том, как это сделать, по этой ссылке: Как развернуть схему значения-атрибута сущности MySQL

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...