从包含ID、[值类型]和值的SQL表访问数据

从包含ID、[值类型]和值的SQL表访问数据,sql,sql-server,database,Sql,Sql Server,Database,如果以前有人问过这个问题,请共享该问题的链接。我做了一些搜索,没有找到这样一个问题的答案。这可能是因为我在尝试将其输入显示我要查找的结果的查询时遇到了困难 背景: 我正在设计一个数据库来保存一些信息(就像数据库通常所做的那样)。为了回答这个问题,这个数据库包含三个表 三个表存储不同的信息;一个表通过唯一的ID和用户名定义用户,第二个表存储可以为用户存储的信息类型,第三个表存储关于用户的信息 用户表定义为: CREATE TABLE dbo.Users ( Id UNIQ

如果以前有人问过这个问题,请共享该问题的链接。我做了一些搜索,没有找到这样一个问题的答案。这可能是因为我在尝试将其输入显示我要查找的结果的查询时遇到了困难

背景:
我正在设计一个数据库来保存一些信息(就像数据库通常所做的那样)。为了回答这个问题,这个数据库包含三个表

三个表存储不同的信息;一个表通过唯一的ID和用户名定义用户,第二个表存储可以为用户存储的信息类型,第三个表存储关于用户的信息

用户表定义为:

CREATE TABLE dbo.Users (
    Id          UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWID()),
    [User Name] NVARCHAR(1024)   NOT NULL
);
[用户信息数据类型]表定义为:

CREATE TABLE dbo.[User Info Data Type] (
    Id               UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWID()),
    [Data Type Name] NVARCHAR(256)    NOT NULL
);
CREATE TABLE dbo.[User Info] (
    Id               UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWID()),
    [User Id]        UNIQUEIDENTIFIER NOT NULL, --FK from [Users].Id
    [User Info Type] UNIQUEIDENTIFIER NOT NULL, --FK from [User Info Data Dype].Id
    Value            VARBINARY(MAX)   NULL
);
最后但并非最不重要的一点是,[User Info]表定义为:

CREATE TABLE dbo.[User Info Data Type] (
    Id               UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWID()),
    [Data Type Name] NVARCHAR(256)    NOT NULL
);
CREATE TABLE dbo.[User Info] (
    Id               UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWID()),
    [User Id]        UNIQUEIDENTIFIER NOT NULL, --FK from [Users].Id
    [User Info Type] UNIQUEIDENTIFIER NOT NULL, --FK from [User Info Data Dype].Id
    Value            VARBINARY(MAX)   NULL
);
问题:
我以前见过这样做(在以前的工作中),但我在SQL方面不如我希望的那么先进。我想知道如何使用第二个表来定义第三个表中数据的标题,根据第一个表中的单个记录聚合第三个表中的数据

我甚至会澄清我期待的结果

假设第一个表有一条记录,其名称列包含Dave。
第二个表有一个“已创建”类型的条目。
第三个表有一个条目,其中包含Dave的Id、“创建”Id和创建日期的值(二进制)

假设“Dave’s”记录创建于2015年8月24日00:00。查询结果将产生:

User Name | Created
Dave      | 8D2AC16F443C000
列名将从第二个表中提取,值将从第三个表中提取

我知道这是一个复杂的要求,但任何帮助将不胜感激

提前谢谢

-戴夫

这是一个很好的例子。正如尼克所评论的,你应该研究一下它的利弊。但是,如果您希望采用此模型,您的查询将非常依赖于
PIVOT
s或
Crosstab
s。下面是一个使用

首先,我们创建示例数据。注意,我删除了列名中的空格

CREATE TABLE #Users (
    Id          UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWID()),
    UserName    NVARCHAR(1024)   NOT NULL
);
CREATE TABLE #UserInfoDataType (
    Id              UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWID()),
    DataTypeName    NVARCHAR(256)    NOT NULL
);
CREATE TABLE #UserInfo (
    Id              UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWID()),
    UserId          UNIQUEIDENTIFIER NOT NULL, --FK from [#Users].Id
    UserInfoType    UNIQUEIDENTIFIER NOT NULL, --FK from [User Info Data Dype].Id
    Value           VARBINARY(MAX)   NULL
);

INSERT INTO #Users(UserName) VALUES('Dave');
INSERT INTO #UserInfoDataType(DataTypeName) VALUES('Created'), ('FirstName'), ('LastName')
INSERT INTO #UserInfo(UserId, UserInfoType, Value)
    SELECT
        u.Id,
        uidt.Id,
        Value =
            CASE
                WHEN uidt.DataTypeName = 'Created' THEN CONVERT(VARBINARY(MAX), CONVERT(VARCHAR(10),GETDATE(), 101))
                WHEN uidt.DataTypeName = 'FirstName' THEN CONVERT(VARBINARY(MAX), 'Dave')
                WHEN uidt.DataTypeName = 'LastName' THEN CONVERT(VARBINARY(MAX), 'Doe')
            END
    FROM #Users u
    CROSS JOIN #UserInfoDataType uidt
现在,对于动态交叉表解决方案:

DECLARE @sql1 NVARCHAR(2000) = '',
        @sql2 NVARCHAR(2000) = '',
        @sql3 NVARCHAR(2000) = ''

SELECT @sql1 = 
'SELECT
      u.UserName' + CHAR(10)

SELECT @sql2 = @sql2 +
'   , MAX(CASE WHEN i.UserInfoType = ''' + CONVERT(VARCHAR(MAX), Id) + ''' THEN CONVERT(VARCHAR(MAX), i.Value) END) AS ' + QUOTENAME(DataTypeName) + CHAR(10)
FROM #UserInfoDataType

SELECT @sql3 =
'FROM #UserInfo i
INNER JOIN #Users u ON u.Id = i.UserId
INNER JOIN #UserInfoDataType t ON t.Id = i.UserInfoType
GROUP BY i.UserId, u.UserName'

PRINT(@sql1 + @sql2+ @sql3)
EXEC(@sql1 + @sql2+ @sql3)
结果:

UserName Created    FirstName LastName 
-------- ---------- --------- -------- 
Dave     08/25/2015 Dave      Doe   

中查看,鉴于您所需的模式,以及您希望扩展到UID所能提供的范围之外,您确定RDBMS是这里最好的平台吗?你正在将标准化提升到史诗级。可能是一个列数据库,或者是一个键/值存储(或者是一个混合数据库,比如Cassandra)可能是一个更好的选择?在RDBMS系统中,按照您要求的方式提取数据可能会影响性能。这是一个EAV设计。是的,这是一个EAV设计-您应该对此进行一些研究-有很多关于其优点的讨论-通常是否定的。由于这种设计,您的性能将在您用完唯一整数键之前很久受到影响。@Dave,这就是为什么它们只是注释。Felix,谢谢。你根据我的问题给出了一个答案。我现在只是坐下来讨论,看起来它可能会起作用。我只是将动态交叉表从临时表转换为实际表。如果我有任何问题,我会告诉你。让它在我的数据库中工作,名称中还有空格。转换了对临时表(及其列)的所有引用,以指向我创建的表。再次感谢菲利克斯!