Какой запрос или представление SQL будет показывать "динамические столбцы"
У меня есть таблица данных, и я разрешаю людям добавлять метаданные в эту таблицу.
Я даю им интерфейс, который позволяет им обрабатывать его так, как будто они добавляют дополнительные столбцы в таблицу, в которой хранятся данные, но на самом деле я храню данные в другой таблице.
Data Table
DataID
Data
Meta Table
DataID
MetaName
MetaData
Так что, если бы они хотели таблицу, в которой хранятся данные, дата и имя, то у меня были бы данные в таблице данных, и слово "Дата" в metaname, и дата в MetaData, и другая строка в мета-таблица с именем в метанаме и именем в метаданных.
Теперь мне нужен запрос, который берет информацию из этих таблиц и представляет ее, как будто она поступает из одной таблицы с двумя дополнительными столбцами "Данные" и "Имя", чтобы клиенту казалось, что есть одна таблица со своими пользовательскими столбцами.:
MyTable
Data
Date
Name
Или, другими словами, как мне идти отсюда:
Data Table
DataID Data
1 Testing!
2 Hello, World!
Meta Table
DataID MetaName MetaData
1 Date 20081020
1 Name adavis
2 Date 20081019
2 Name mdavis
Сюда:
MyTable
Data Date Name
Testing! 20081020 adavis
Hello, World! 20081019 mdavis
Несколько лет назад, когда я делал это в MySQL с использованием PHP, я сделал два запроса: первый для получения дополнительных метаданных, второй для объединения их всех вместе. Я надеюсь, что современные базы данных имеют альтернативные методы борьбы с этим.
Относится к варианту 3 этого вопроса.
-Адам
3 ответа
Вы хотите повернуть каждую строку пары имя-значение в MyTable... Попробуйте этот sql:
DECLARE @Data TABLE (
DataID INT IDENTITY(1,1) PRIMARY KEY,
Data VARCHAR(MAX)
)
DECLARE @Meta TABLE (
DataID INT ,
MetaName VARCHAR(MAX),
MetaData VARCHAR(MAX)
)
INSERT INTO @Data
SELECT 'Data'
INSERT INTO @Meta
SELECT 1, 'Date', CAST(GetDate() as VARCHAR(20))
UNION
SELECT 1, 'Name', 'Joe Test'
SELECT * FROM @Data
SELECT * FROM @Meta
SELECT
D.DataID,
D.Data,
MAX(CASE MetaName WHEN 'Date' THEN MetaData ELSE NULL END) as Date,
MAX(CASE MetaName WHEN 'Name' THEN MetaData ELSE NULL END) as Name
FROM
@Meta M
JOIN @Data D ON M.DataID = D.DataID
GROUP BY
D.DataID,
D.Data
SELECT DataTable.Data AS Data, MetaTable.MetaData AS Date, MetaTable.MetaName AS Name
FROM DataTable, MetaTable
WHERE DataTable.DataID = MetaTable.DataID
Возможно, вы захотите добавить дополнительное предложение (AND Data = 'some value'), чтобы вернуть строки, которые интересуют пользователя.
AFAIK, вы можете сделать это на стороне сервера только с динамическим SQL
хранимая процедура.
Эффективно код, который вы хотите генерировать динамически:
SELECT [Data Table].*
,[MyTable Date].MetaData
,[MyTable Name].MetaData
FROM [Data Table]
LEFT JOIN [MyTable] AS [MyTable Date]
ON [MyTable Date].DataID = [Data Table].DataID
AND [MyTable Date].MetaName = 'Date'
LEFT JOIN [MyTable] AS [MyTable Name]
ON [MyTable Name].DataID = [Data Table].DataID
AND [MyTable Name].MetaName = 'Name'
И вот код, чтобы сделать это:
DECLARE @sql AS varchar(max)
DECLARE @select_list AS varchar(max)
DECLARE @join_list AS varchar(max)
DECLARE @CRLF AS varchar(2)
DECLARE @Tab AS varchar(1)
SET @CRLF = CHAR(13) + CHAR(10)
SET @Tab = CHAR(9)
SELECT @select_list = COALESCE(@select_list, '')
+ @Tab + ',[MyTable_' + PIVOT_CODE + '].[MetaData]' + @CRLF
,@join_list = COALESCE(@join_list, '')
+ 'LEFT JOIN [MyTable] AS [MyTable_' + PIVOT_CODE + ']' + @CRLF
+ @Tab + 'ON [MyTable_' + PIVOT_CODE + '].DataID = [DataTable].DataID' + @CRLF
+ @Tab + 'AND [MyTable_' + PIVOT_CODE + '].MetaName = ''' + PIVOT_CODE + '''' + @CRLF
FROM (
SELECT DISTINCT MetaName AS PIVOT_CODE
FROM [MyTable]
) AS PIVOT_CODES
SET @sql = 'SELECT [DataTable].*' + @CRLF
+ @select_list
+ 'FROM [DataTable]' + @CRLF
+ @join_list
PRINT @sql
--EXEC (@sql)
Вы можете использовать аналогичную динамическую технику, используя CASE
Пример выписки для выполнения разворота.