SQL Server-如何透视同一密钥的多个值

SQL Server-如何透视同一密钥的多个值,sql,sql-server,Sql,Sql Server,如何使用同一键透视具有多个值的列。 例如,我们有桌子 ID FieldName FieldValue 1 Name Jack 1 Country Auz 1 PostCode 1234 1 Name Jhon 2 Name Leo 2 Country USA 2 PostCode 2345 我想在pivot之后获得结果表: ID Name Country PostCode 1

如何使用同一键透视具有多个值的列。 例如,我们有桌子

ID   FieldName FieldValue 
1    Name       Jack
1    Country    Auz     
1    PostCode   1234
1    Name       Jhon
2    Name       Leo
2    Country    USA
2    PostCode   2345
我想在pivot之后获得结果表:

ID  Name  Country  PostCode
1   Jack  Auz      1234
1   Jhon  Auz      1234
2   Leo   USA      2345
我使用了pivot函数的代码:

SELECT *
FROM (
   SELECT 
      ID, FieldName, FieldValue
   FROM Table
 ) AS p
PIVOT 
(
   MAX(FieldValue)
   FOR FieldName IN ([Name], [Country], [PostCode])
) AS pvt

从上面的代码中,结果表将只获得ID为“1”的一条记录,我认为这可能是由于使用了“MAX”函数。有没有办法通过使用任何其他函数来显示两条记录

您的数据中存在异常情况,因为ID 1有两个与之关联的名称,并且您希望两者共享其他属性,如邮政编码等。为此,您可以使用
apply
操作符为每个ID返回一个或多个名称,然后
ID
name
的组合进行分组

SELECT
    id
  , Name
  , MAX(CASE WHEN fieldname = 'Country' THEN fieldvalue END) AS Country
  , MAX(CASE WHEN fieldname = 'Postcode' THEN fieldvalue END) AS Postcode
FROM (
    SELECT
        t.*, ca.Name
    FROM mytable AS t
    CROSS APPLY (
        SELECT
            FieldValue AS Name
        FROM mytable AS t2
        WHERE t.id = t2.id
        AND t2.FieldName = 'Name'
    ) AS ca
WHERE FieldName IN ('Country','PostCode')
) t
GROUP BY
    id
  , name
;
另见:

结果:

+----+----+------+---------+----------+
|    | id | Name | Country | Postcode |
+----+----+------+---------+----------+
|  1 |  1 | Jack | Auz     |     1234 |
|  2 |  1 | Jhon | Auz     |     1234 |
|  3 |  2 | Leo  | USA     |     2345 |
+----+----+------+---------+----------+
注意,使用
交叉应用
有点像
内部连接
;如果没有与id关联的名称,则上述查询不会返回该id。如果需要不带名称的id,请使用
外部应用
(因为这类似于
左连接

另一种选择是,您可以像这样使用
pivot

SELECT id, name, [Country], [PostCode]
FROM (
    SELECT
        t.*, ca.Name
    FROM mytable AS t
    CROSS APPLY (
        SELECT
            FieldValue AS Name
        FROM mytable AS t2
        WHERE t.id = t2.id
        AND t2.FieldName = 'Name'
    ) AS ca
    WHERE FieldName IN ('Country','PostCode')
 ) AS p
PIVOT 
(
   MAX(FieldValue)
   FOR FieldName IN ([Country], [PostCode])
) AS pvt

SQL表表示无序集。没有办法将前三行关联为一条记录,因为没有“前三行”这样的东西。你有一个列可以用来指定哪些行放在一起吗?是的,我想这就是我经常感到困惑的地方,因为数据本身是非常不寻常的。您的解决方案非常好,但如果有更多的字段名关联,则会变得复杂。例如,现在ID 1有2个与之关联的名称,可以为ID 1生成两行记录。如果ID 1也有2个与之关联的国家,那么应该为ID 1生成2*2=4行记录。如果有更多的关联,这将使您的编码更加复杂??我认为您的数据模型有缺陷,但假设它是这样的话,这种方法可以扩展。是的,这可能会增加复杂性,但不会太大。是的,模型一点也不友好。您的编码非常优雅,我认为这里可能不需要包含“FieldName In”,因为Case语句已经检查了FieldName。之前我已经提出了左外连接另一个多值连接。不管怎样,这两种方法都很好,非常感谢你的帮助。非常感谢您抽出时间!!!!
where子句
可以省略,但是您将处理不需要处理的行,因此它是为了提高效率。是的,谢谢,我尝试了您上面提到的“交叉应用”方式,但是它比“左外连接”要花更多的时间。我尝试了使用filter fieldName='name'的'LEFT OUTER JOIN',以获取与ID1关联的两个名称,这对于大量数据来说花费的时间要少得多。