2008-10-20 34 views
4

我有一个数据表,我允许人们添加元数据到该表。什么SQL查询或视图将显示“动态列”

我给他们一个接口,允许他们对待它,好像他们将额外的列添加到他们的数据存储在表中,但我实际上将数据存储在另一个表中。

Data Table 
    DataID 
    Data 

Meta Table 
    DataID 
    MetaName 
    MetaData 

所以,如果他们想存储数据,日期和名字,然后我不得不在数据表中的数据表,并在metaname单词“日期”,并在该日期元数据以及元表中的另一行,元名称中包含“名称”和元数据中的名称。

我现在需要一个查询,它从这些表中获取信息,并将其呈现为来自具有两个额外列“Data”和“Name”的单个表,因此对于客户来说它看起来像是有一个表与他们的自定义列:

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 

几年前,当我在PHP中使用MySQL时,我做了两个查询,第一个是获取额外的元数据,第二个是将它们连接在一起。我希望现代数据库有处理这个问题的替代方法。

this question的选项3相关。

- 亚当

回答

2

你想每转动在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 
1
SELECT DataTable.Data AS Data, MetaTable.MetaData AS Date, MetaTable.MetaName AS Name 
FROM DataTable, MetaTable 
WHERE DataTable.DataID = MetaTable.DataID 

你可能想增加一个附加条款(和数据=“某个值”)返回用户感兴趣的行。

0

据我所知,你可以在服务器端仅使用动态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语句示例执行使用类似的动态技术枢。

+0

所以这是两个查询选项,在这里我先找出什么“动态”栏目我需要从元表中拉入,然后从这些结果构建一个查询? – 2008-10-20 19:41:26

+0

是的,但是,您可以在单个存储过程中动态执行此操作。如果你的MetaNames是固定的,你可以按原样使用上面的查询,否则它将是动态的。我会尽快发布一些代码,以便快速生成代码。 – 2008-10-20 19:44:37