【问题标题】:What SQL query or view will show "dynamic columns"哪些 SQL 查询或视图将显示“动态列”
【发布时间】:2010-09-18 04:29:19
【问题描述】:

我有一个数据表,我允许人们将元数据添加到该表中。

我为他们提供了一个接口,让他们可以将其视为向存储数据的表添加额外的列,但我实际上是将数据存储在另一个表中。

Data Table
   DataID
   Data

Meta Table
   DataID
   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

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

this question的选项3有关。

-亚当

【问题讨论】:

    标签: sql database metadata dataview


    【解决方案1】:

    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 语句示例来执行数据透视。

    【讨论】:

    • 所以这是两个查询选项,我首先找出需要从元表中提取哪些“动态”列,然后根据这些结果构造查询?
    • 是的,但是,您可以在单个存储过程中动态执行此操作。如果您的 MetaNames 是固定的,您可以按原样使用上面的查询,否则它将是动态的。我会尽快发布一些代码,它可以快速生成。
    • 谢谢,这会很有帮助。您是否还会提及您知道在哪个 SQL 服务器上工作?
    • 这将在 SQL Server 上工作,使用 SELECT 技巧来制作没有游标的动态字符串。在其他平台上有一个 CONCAT 或者您可能必须使用游标。它生成的查询应该足够 ANSI(您必须注意表名或 MetaName 中的坏字符)。
    【解决方案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
    

    【讨论】:

    • 更多关于 CASE 的 SQL 撬棒。 4guysfromrolla.com/webtech/102704-1.shtml
    • 查询结果的最佳方式是什么?示例:SELECT * FROM Table WHERE Name = 'Joe Test' 我需要保存第一个结果并查询该表吗?或者有没有办法在第一遍中实现WHERE 过滤器?
    【解决方案3】:
    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')来返回用户感兴趣的行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-15
      相关资源
      最近更新 更多