【问题标题】:How can I create multiple columns from one DB Field in SQL Server?如何从 SQL Server 中的一个 DB 字段创建多个列?
【发布时间】:2010-11-14 20:17:39
【问题描述】:

我在UserProfile 表中有一个名为PropertyValue 的字段,其中可以包含地址、电话号码、名字、姓氏、用户名、城市等信息...此表中的每条记录都与UserId 的用户,它还与包含每个属性的定义的ProfilePropertyDefinition 相关联(即PropertyName)。

通过这种关系,我可以获得所有属性值及其属性名称。我想做的是从这两列(PropertyValue,PropertyName)中提取数据并创建一个类似的表:

First Name | Last Name | Email | Phone | City | Country
-------------------------------------------------------
           |           |       |       |      |

所以,我想知道是否可以使用 SQL 语句来执行此操作,这是我的尝试:

SELECT FirstName = (SELECT PropertyValue FROM UserProfile WHERE PropertyDefinitionID = (SELECT PropertyDefinitionID WHERE PropertyName = 'first name')), 
LastName = (SELECT PropertyValue FROM UserProfile WHERE PropertyDefinitionID = (SELECT PropertyDefinitionID WHERE PropertyName = 'last name')), 
Email = (SELECT PropertyValue FROM UserProfile WHERE PropertyDefinitionID = (SELECT PropertyDefinitionID WHERE PropertyName = 'email'))

但这并没有奏效,而且似乎有些奇怪...有人知道如何获取一列并将其值显示在几个不同的列中吗?

【问题讨论】:

    标签: sql-server select join subquery table-relationships


    【解决方案1】:

    就我个人而言,我现在会停下来考虑一下这种设计对性能的影响有多大。这通常是一种用于存储此类数据的非常糟糕的技术。如果您有 20 个要显示的属性,您将必须加入(并且留下加入,因为您不能保证每个属性都会被表示)到该表 20 次。此外,如果这是您的数据结构的核心(听起来像是来自您似乎正在存储的数据类型),那么几乎每个查询都需要执行类似的操作,并且性能将非常糟糕。有时这是最好的模型(当您无法提前知道需要存储哪些属性时),但大多数时候,它的使用是糟糕设计的标志。

    http://en.wikipedia.org/wiki/Entity-Attribute-Value_model

    【讨论】:

    • 我同意,但这是默认设置用户配置文件的方式(Asp.Net 上的 DNN)。除非我为每个需要更改的表检查并创建表,否则重新连接所有使用这些表的 DNN 模块,并创建全新的注册和配置文件模块,这些模块可以以这种方式处理表并处理添加新列到每个新的自定义配置文件属性的表...技术不会改变...我想我会在性能方面受到打击。
    【解决方案2】:

    我需要更多地了解您的表结构以及您想要实现的目标,但一个选项可能是创建一个 SQL 标量函数来检索属性的值。我正在对表名和数据库设置做出一些假设,但请尝试...

    CREATE FUNCTION [dbo].[UserProperty] 
    (
        @UserProfileID UNIQUEIDENTIFIER, @Property VARCHAR(200)
    )
    RETURNS VARCHAR(max)
    AS
    BEGIN
        -- Declare the return variable here
        DECLARE @Value AS VARCHAR(MAX)
        SELECT @Value = PropertyValue FROM UserProfile up INNER JOIN PropertyDefinitions pd ON 
        up.PropertyDefinitionID = pd.PropertyDefinitionID 
        WHERE pd.PropertyName = @Property AND up.UserProfileID=@UserProfileID
    
        RETURN ISNULL(@Value,'')
    
    END
    
    SELECT 
        [dbo].[UserProperty](UserProfileID, 'first name') AS [First Name],
        [dbo].[UserProperty](UserProfileID, 'last name') AS [Last Name],
        [dbo].[UserProperty](UserProfileID, 'email') AS [Email] 
    FROM 
        [Users]
    

    【讨论】:

      【解决方案3】:

      我会这样写查询:

      Select 
        aa.userId,
        Coalesce(Max(Case when PropertyName = 'First Name' then PropertyValue else '' end),'') as FirstName,
        and so on
      from
        UserTable as aa
      left join
        UserProfile as bb
        on
        aa.UserId = bb.UserId
      left join
        ProfilePropertyDefinition as cc
        on bb.PropertyDefinitionId = cc.PropertdefinitionId
      group by
        aa.UserId
      

      【讨论】:

        【解决方案4】:

        假设架构像

        UserProfile#
        {userid,
        ProfileName, 
        propertyValue
        }
        

        你会想要做的

        SELECT 
         FirstName.PropertyValue  FirstNAme,
         LastName.PropertyValue  LastName,
        FROM
        users
        JOIN (USERPROFILE) FirstName ON
        FirstName.userid = users.userid
        and PropertName ='FirstName'
        JOIN (USERPROFILE) LastName ON
        LastName.userid = users.userid
        and PropertName ='LastName'
        

        【讨论】:

          【解决方案5】:
          SELECT fn.PropertyValue FirstName,
                 ln.PropertyValue LastName,
                 etc...
          
          From UserProfile fN
             Join UserProfile lN
                On fN.PropertyName = 'first name' 
                   And ln.PropertyName = 'last name' 
                   And fn.user = ln.user
             Join UserProfile eM
                On fN.PropertyName = 'first name' 
                   And eM.PropertyName = 'email' 
                   And eM.user = fn.user
          

          (

          【讨论】:

          • 为什么有人赞成这个?究竟是什么让这个答案比其他答案更好?我想知道,以便我可以选择最佳答案...
          • 我不知道,我会试试这个并将性能与我的解决方案进行比较。我想如果表很大并且你有很多字段要构建,你会发现我的表现要好得多(因为这个解决方案对每个字段都使用了一个连接)。
          【解决方案6】:

          您需要多次加入表格(与字段数一样多):

          SELECT UPFN.PropertyValue AS FirstName, UPLN.PropertyValue AS LastName, ...
          FROM UserProfile UPFN
          INNER JOIN ProfilePropertyDefinition PPDFN ON PPDFN.PropertyDefinitionID = UPFN.PropertyDefinitionID AND PPDFN.PropertyName = 'first name'
          INNER JOIN UserProfile UPLN ON UPLN.id = UPFN.id
          INNER JOIN ProfilePropertyDefinition PPDLN ON PPDLN.PropertyDefinitionID = UPLN.PropertyDefinitionID AND PPDLN.PropertyName = 'last name'
          ...
          

          请注意,这依赖于它们是 UserProfile 中的某个 ID 字段,您可以使用该字段将同一用户的所有行绑定在一起。

          【讨论】:

            【解决方案7】:

            我想您可以多次从同一个表中进行选择。 假设 tA 是具有 UserProfileID、PropertyDefinition 和 PropertyValue 的名称表

            你可以的

            select
            t1.PropertyValue as FirstName,
            t2.PropertyValue as LastName,
            ...
            FROM
            tA as t1, tA as t2, ....
            WHERE
            t1.PropertyDefinition Like 'FirstName' AND
            t2.PropertyDefinition Like 'LastName' AND
            ....
            AND
            t1.UserId = @user AND
            t2.UserID = @user ....
            

            不理想,但它会工作

            【讨论】:

            • 您也可以将查询构造为一堆内部连接,但我认为幕后操作将接近相同(不要引用我的话相同)
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-08-14
            • 2012-12-11
            • 1970-01-01
            相关资源
            最近更新 更多