Добавление N количество динамических столбцов в SQL-запрос - PullRequest
0 голосов
/ 30 июня 2011

У меня есть таблица, которая называется datarecords, которая содержит 7 фиксированных столбцов, которые всегда требуются в запросе выбора.Пользователь может добавить столько пользовательских столбцов, которые он хочет.Я храню эту информацию в таблице с именем datacolumn, а значения хранятся в другой таблице с именем datavalue.

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

Ответы [ 2 ]

2 голосов
/ 30 июня 2011

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

Вы можете получить произвольное количество пользовательских атрибутов, только выбирая их построчно, так как они хранятся в базе данных. Затем напишите код приложения, чтобы просмотреть результаты. При желании вы можете написать класс для сопоставления нескольких строк пользовательских атрибутов с полями объекта в вашем приложении.

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

Многие люди пытаются расширить это, используя дизайн, который вы используете, но они считают, что им трудно управлять и он плохо масштабируется. Этот дизайн обычно называется моделью Entity-Attribute-Value или парами ключ-значение. Подробнее о подводных камнях в дизайне EAV см. Мою книгу Антипаттерны SQL .

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

  • Храните все пользовательские атрибуты вместе в BLOB с некоторой внутренней структурой для разделения имен и значений полей ( Serialized LOB ). При желании вы можете создать инвертированные индексы, чтобы помочь вам искать строки, в которых данное поле имеет заданное значение (см. Как FriendFeed использует MySQL ).

  • Используйте базу данных, ориентированную на документы, такую ​​как MongoDB или Solr для динамических данных.

  • Используйте ALTER TABLE, чтобы добавить обычные столбцы в таблицу, когда пользователям нужны пользовательские атрибуты. Это означает, что вам нужно либо применить один и тот же набор настраиваемых атрибутов для всех пользователей, либо сохранить пользовательские атрибуты всех пользователей и надеяться, что ваша таблица не станет слишком широкой ( Наследование одной таблицы ), или создать отдельная таблица для пользователя, либо для всех столбцов ( Наследование бетонной таблицы ), либо только для пользовательских столбцов ( Наследование таблицы классов ).

1 голос
/ 15 апреля 2013

РЕДАКТИРОВАТЬ: см. Примечание внизу для более подробной информации.

Я столкнулся с той же проблемой, и я нашел решение, которое медленно. Может быть, у кого-то есть решение для ускорения моих выводов. В моем коде у меня есть таблица с тремя столбцами: Col1, Col2, Col3. Col1 мой идентификатор записи. Col2 - это имя моих динамических столбцов. Col3 - это значение в этом столбце. Поэтому, если бы я хотел представить запись с идентификатором 1, двумя столбцами 2 и 3 и значениями в этих столбцах: 4 и 5, у меня было бы следующее:

Col1, Col2, Col3
1, 2, 4
1, 3, 5

Затем мы поворачиваемся над столбцом 2 и выбираем MAX (или MIN, или AVG, не имеет значения, поскольку комбинации col2 и col3 уникальны) col3 в сводной таблице. Чтобы выполнить сводку с переменным числом столбцов, мы используем динамическое генерирование SQL для генерации нашего SQL. Это хорошо работает для небольших входных данных (я полагаю, производная таблица внутри предложения FROM динамического SQL). Как только ваш набор данных станет большим, выполнение средней функции займет много времени. Очень долгое время. Похоже, это начинается примерно с 1000 строк, так что, возможно, есть подсказка или другой метод, который делает это короче.

Как примечание, поскольку значения для Col2 и Col3 отображаются 1: 1, я также попытался динамически сгенерировать оператор SELECT, как показано ниже:

SELECT Col1,
   CASE WHEN Col2 = '4' THEN Col3 END [4],
   CASE WHEN Col2 = '5' THEN Col3 END [5],
   CASE WHEN Col2 = '6' THEN Col3 END [6], -- ... these were dyanmically generated
FROM #example
GROUP BY Col1

Это было так же медленно для моего набора данных. Ваша миля может отличаться. Вот полный пример того, как это работает, написанный для SQL Server (2005+ должен запускать это).

--DROP TABLE #example
CREATE TABLE #example
(
    Col1 INT,
    Col2 INT,
    Col3 INT
)

INSERT INTO #example VALUES (2,4,10)
INSERT INTO #example VALUES (2,5,20)
INSERT INTO #example VALUES (2,6,30)
INSERT INTO #example VALUES (2,7,40)
INSERT INTO #example VALUES (2,8,50)
INSERT INTO #example VALUES (3,4,11)
INSERT INTO #example VALUES (3,5,22)
INSERT INTO #example VALUES (3,6,33)
INSERT INTO #example VALUES (3,7,44)
INSERT INTO #example VALUES (3,8,55)

DECLARE @columns VARCHAR(100)
SET @columns = ''

SELECT @columns = @columns + '[' + CAST(Col2 AS VARCHAR(10)) + '],'
FROM (SELECT DISTINCT Col2 FROM #Example) a

SELECT @columns = SUBSTRING(@columns, 0, LEN(@columns) )

DECLARE @dsql NVARCHAR(MAX)

SET @dsql = '
select Col1, ' + @columns + '
from
    (select Col1, Col2, Col3 FROM #example e) a
PIVOT
(
    MAX(Col3)
    FOR Col2 IN (' + @columns + ')
) p'

print @dsql
EXEC sp_executesql @dsql

РЕДАКТИРОВАТЬ: из-за уникальной ситуации, в которой я это делаю, мне удалось ускорить работу с использованием двух таблиц (одна с сущностями, а другая с парами атрибут-значение) и создания кластеризованного индекса на пары атрибут-значение, которые включают все столбцы (идентификатор, атрибут, значение). Я рекомендую вам обойти этот подход другим способом, если вам нужны быстрые вставки, большое количество столбцов, много строк данных и т. Д. У меня есть некоторые известные уверенности относительно размера и темпов роста моих данных, и мое решение подходит для моей области ,

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

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