2008-10-20 58 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