如何在SQL中对数据透视结果进行分组?

时间:2013-12-07 23:13:03

标签: sql sql-server pivot

我已经能够使用pivot功能组合结果。在我的解决方案上尝试各种示例,将这些结果组合在一起。我做错了还是简单的修复?

create table DBE_LOCATION
(
REF int,
STATUS varchar(1)
);

insert into DBE_LOCATION values
(1, 'A'),
(2, 'A');

create table SYS_SCREEN_FIELD
(
REF int,
FIELD_DISPLAY varchar(20),
ORDER_BY int
);

insert into SYS_SCREEN_FIELD values
(1, 'Location Name', 0),
(2, 'Address', 1),
(3, 'Suburb', 2),
(4, 'Postcode', 3),
(5, 'State', 4),
(6, 'Country', 5);

create table DBE_LOCATION_DATA
(
REF int,
FIELD_REF int,
LOCATION_REF int,
VALUE_TEXT_FIELD varchar(MAX)
);

insert into DBE_LOCATION_DATA values
(1, 1, 1, 'New York'),
(2, 1, 2, 'Japan'),
(3, 2, 1, '123 Address St'),
(4, 2, 2, '456 Address St');

现在最后的事情是显示每个Location的结果集,并将字段显示为列名。如果使用上面的例子,那就是这样:

Ref   Location Name    Address                  Status
1       New York             123 Address St      A
2       Japan                   456 Address Ave   A

在收集数据和创建动态列方面有以下工作:

DECLARE @cols AS NVARCHAR(MAX),
@query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(FIELD_DISPLAY) 
                from SYS_SCREEN_FIELD
                group by FIELD_DISPLAY, ORDER_BY
                order by ORDER_BY
        FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')

set @query = 'SELECT REF, ' + @cols + ', STATUS from 
         (
            select l.REF, l.STATUS,
              f.FIELD_DISPLAY,
              d.FIELD_REF, d.VALUE_TEXT_FIELD
            from DBE_LOCATION l
            right join DBE_LOCATION_DATA d
              on l.REF = d.LOCATION_REF
            inner join SYS_SCREEN_FIELD f
              on d.FIELD_REF = f.REF
        ) x 
        pivot 
        (
            max(VALUE_TEXT_FIELD)
            for FIELD_DISPLAY in (' + @cols + ')
        ) p'

execute(@query)

结果未按REF分组。这是怎么做到的?

SQL Fiddle Link

1 个答案:

答案 0 :(得分:0)

问题在于在子查询中添加了列FIELD_REF。即使您没有在最终选择列表中包含此列,因为它在您的子查询中,该列将在PIVOT分组期间使用。

如果您将其包含在最终选择中,则可以看到问题,您会得到一个结果:

| REF | FIELD_REF | LOCATION NAME |        ADDRESS | SUBURB | POSTCODE |  STATE | COUNTRY | STATUS |
|-----|-----------|---------------|----------------|--------|----------|--------|---------|--------|
|   1 |         1 |      Adelaide |         (null) | (null) |   (null) | (null) |  (null) |      S |
|   1 |         2 |        (null) |  1 Adelaide St | (null) |   (null) | (null) |  (null) |      S |

FIELD_REF的值12 REF=1,当应用聚合和分组时,您将返回多行。

如果从子查询中删除此列,您将获得所需的结果:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(FIELD_DISPLAY) 
                    from SYS_SCREEN_FIELD
                    group by FIELD_DISPLAY, ORDER_BY
                    order by ORDER_BY
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT REF, ' + @cols + ', STATUS from 
             (
                select l.REF, l.STATUS,
                  f.FIELD_DISPLAY,
                  d.VALUE_TEXT_FIELD
                from DBE_LOCATION l
                right join DBE_LOCATION_DATA d
                  on l.REF = d.LOCATION_REF
                inner join SYS_SCREEN_FIELD f
                  on d.FIELD_REF = f.REF
            ) x 
            pivot 
            (
                max(VALUE_TEXT_FIELD)
                for FIELD_DISPLAY in (' + @cols + ')
            ) p'

execute sp_executesql @query;

SQL Fiddle with Demo。现在你的最终结果是:

| REF | LOCATION NAME |        ADDRESS | SUBURB | POSTCODE |  STATE | COUNTRY | STATUS |
|-----|---------------|----------------|--------|----------|--------|---------|--------|
|   1 |      Adelaide |  1 Adelaide St | (null) |   (null) | (null) |  (null) |      S |
|   2 |     Melbourne | 2 Melbourne St | (null) |   (null) | (null) |  (null) |      S |