SQL在未确定的列上进行透视

问题描述 投票:2回答:2

我有多个表需要加入并展平。用户表,用户的属性类型表以及包含属性值的表。以下是users表的示例:

Id  User
1   Sam
2   Bill

和属性类型:

Id  Order   Property
1   30      Weight
2   20      Hair Color
3   10      Eye Color

和财产价值:

UserId  PropertyId  Value
1       3           Blue
1       2           Blond
1       1           170
2       3           Brown
2       2           Black
2       1           180

我希望得到这样的结果:

User    Eye Color   Hair Color  Weight
Sam     Blue        Blond       170
Bill    Brown       Black       180

请注意,属性列的顺序由属性类型中的Order列驱动。而且我不会提前知道属性名称是什么或者可能有多少。

这是创建3个表的代码。

DECLARE @TableA TABLE (ProperyId int, DisplayOrder int, Property varchar(50))
DECLARE @TableB TABLE (UserId int, [User] varchar(50))
DECLARE @TableC TABLE (UserId int, PropertyId varchar(50), Value varchar(50))
INSERT INTO @TableA SELECT 1, 30, 'Weight'
INSERT INTO @TableA SELECT 2, 20, 'Hair Color'
INSERT INTO @TableA SELECT 3, 30, 'Eye Color'
INSERT INTO @TableB SELECT 1, 'Sam'
INSERT INTO @TableB SELECT 2, 'Bill'
INSERT INTO @TableC SELECT 1, 3, 'Blue'
INSERT INTO @TableC SELECT 1, 2, 'Blond'
INSERT INTO @TableC SELECT 1, 1, '170'
INSERT INTO @TableC SELECT 2, 3, 'Brown'
INSERT INTO @TableC SELECT 2, 2, 'Black'
INSERT INTO @TableC SELECT 2, 1, '180'
select * from @TableA
select * from @TableB
select * from @TableC 

提前致谢!史蒂夫。

sql sql-server tsql pivot
2个回答
0
投票

试图在将表构建为临时表时使其工作太麻烦了,所以我更改了模式代码以使它们成为实际表(并在其中一个列名中更正了拼写错误)。更改的模式代码和结果代码可以在SQL Fiddle上找到here,这样你就可以测试它,但我也把结果代码放在下面。关键是你必须使用SQL来编写你需要的SQL(因为你不知道所有列将是什么):

DECLARE
    @Columns NVARCHAR(MAX),
    @SQL_Statement NVARCHAR(MAX)

SELECT  @Columns = ISNULL( @Columns + ', ', '') + '[' + s.Property + ']' FROM (SELECT DISTINCT [Property] FROM TableA) AS s

SELECT @SQL_Statement = '
WITH cte_Flat AS
(
SELECT
    b.[User],
    a.[Property],
    C.[Value]
FROM
    TableC AS c
JOIN
    TableB AS b
ON
    c.[UserID] = b.[UserID]
JOIN
TableA AS a
ON
    c.[PropertyId] = a.[PropertyID]
)
SELECT
    [User],
    ' + @Columns + '
FROM
    cte_Flat
PIVOT
    (
      MAX([Value])
      for [Property] in (' + @Columns + ')
    ) AS u'

EXEC SP_EXECUTESQL  @SQL_Statement = @SQL_Statement

0
投票

我有一个解决方案给你。您可以在查询中使用第二个表(TableA)在属性,属性和订单中进行编码。所以,你实际上并不需要它。您可以使用第一个和第三个表格获得相同的结果!这是因为用户不会有两种类型的头发,眼睛和重量,因此userID和PropertyId的组合将成为第三个表(TableC)中的关键。

在这种情况下,我喜欢做的是为每个Property创建一个子查询,然后将它们与user表连接起来。我知道这可以是更多的代码,但在我处理更复杂的数据时总是更容易。

WITH EyeColor AS
(
SELECT
 UserId
 , Value
FROM
 TableC
WHERE
 PropertyId = 3
)
, HairColor AS
(
SELECT
 UserId
 , Value
FROM
 TableC
WHERE
 PropertyId = 2
)
, Weight AS
(
SELECT
 UserId
 , Value
FROM
 TableC
WHERE
 PropertyId = 2
)
------------------------------------
SELECT
 u.User AS NAME
 , e.Value AS EYECOLOR
 , h.Value AS HAIRCOLOR
 , w.Value AS WEIGHT
FROM
 TableB u
LEFT JOIN
 EyeColor e
ON u.Id = e.UserId
LEFT JOIN
 HairColor h
ON u.Id = h.UserId
LEFT JOIN
 Weight w
ON u.Id = w.UserId  

祝好运!

© www.soinside.com 2019 - 2024. All rights reserved.