删除带有行枢轴的重复项

时间:2013-04-02 13:40:40

标签: sql sql-server xml for-loop pivot

我想删除一列(device_name)中的重复项,但保留另一列(app_id)中的相关数据。每个设备可以有几个应用程序(1 - > x,通常在1-5之间),所以我想将这些应用程序标识符放入我想调用的新列中[APP1],[APP2],[APP3]等等上。最好的选择是动态Pivot,但任何静态解决方案也将受到欢迎。
提前感谢您的帮助。

PS 我提出了下面的代码,但是只将连接的id id由comas分隔成一列。


    USE tempdb;
    SELECT  DEVICE_NAME,
        NoOfApps,
        STUFF(( SELECT  ', ' + APP_ID
                FROM    dbo.Aperture_full_test apps
                WHERE   apps.DEVICE_NAME = Aperture_full_test.DEVICE_NAME
                FOR XML PATH(''), TYPE
                ).value('.', 'VARCHAR(MAX)'), 1, 2, '') AS Appid

    FROM    (   SELECT  DEVICE_NAME, COUNT(DEVICE_NAME) AS NoOfApps
            FROM    dbo.Aperture_full_test
            GROUP BY DEVICE_NAME     
        ) Aperture_full_test
        ORDER BY NoOfApps DESC 

数据样本:


    USE tempdb;
    GO

    IF OBJECT_ID('dbo.Aperture_full_test') IS NOT NULL
    DROP TABLE dbo.Aperture_full_test;
    GO

    CREATE TABLE dbo.Aperture_full_test
    (
    DEVICE_NAME   varchar(30) NOT NULL,
    APP_ID        varchar(10) NOT NULL
    );

    INSERT INTO dbo.Aperture_full_test(DEVICE_NAME, APP_ID)
    VALUES('LDNSQLF700', 157848);
    INSERT INTO dbo.Aperture_full_test(DEVICE_NAME, APP_ID)
    VALUES('LDNSQLF700', 155439);
    INSERT INTO dbo.Aperture_full_test(DEVICE_NAME, APP_ID)
    VALUES('LDNSQLF700', 635533);
    INSERT INTO dbo.Aperture_full_test(DEVICE_NAME, APP_ID)
    VALUES('NYSQL502', 189164);
    INSERT INTO dbo.Aperture_full_test(DEVICE_NAME, APP_ID)
    VALUES('NYSQL502', 188641);
    INSERT INTO dbo.Aperture_full_test(DEVICE_NAME, APP_ID)
    VALUES('AUSSQL140', 537990);
    INSERT INTO dbo.Aperture_full_test(DEVICE_NAME, APP_ID)
    VALUES('AUSSQL140', 1349605);
    INSERT INTO dbo.Aperture_full_test(DEVICE_NAME, APP_ID)
    VALUES('JAP543X2', 5646789);
    INSERT INTO dbo.Aperture_full_test(DEVICE_NAME, APP_ID)
    VALUES('EU456CLX', 6545789);
    INSERT INTO dbo.Aperture_full_test(DEVICE_NAME, APP_ID)
    VALUES('EUCTX654', 5637965);
    INSERT INTO dbo.Aperture_full_test(DEVICE_NAME, APP_ID)
    VALUES('EUCTX654', 6464367) ;
    INSERT INTO dbo.Aperture_full_test(DEVICE_NAME, APP_ID)
    VALUES('EUCTX654', 1323123) ;
    INSERT INTO dbo.Aperture_full_test(DEVICE_NAME, APP_ID)
    VALUES('EUCTX654', 1004326) ;
    GO

2 个答案:

答案 0 :(得分:2)

由于您使用的是SQL Server,因此可以实现PIVOT功能。

如果您有一定数量的值,那么您可以使用以下代码对查询进行硬编码:

select device_name, App1, App2, App3, App4, App5
from
(
  select device_name, app_id,
    'App'+
      cast(row_number() over(partition by device_name 
                            order by device_name) as varchar(10)) col
  from Aperture_full_test
) d
pivot
(
  max(app_id)
  for col in (App1, App2, App3, App4, App5)
) piv;

请参阅SQL Fiddle with Demo

但是如果你要为每个设备提供未知数量的app_ids,那么你可以使用动态SQL:

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

select @cols = STUFF((SELECT ', ' + QUOTENAME('App'+cast(rn as varchar(10))) 
                    from
                    (
                      select row_number() over(partition by device_name 
                                              order by device_name) rn
                      from Aperture_full_test
                    ) d
                    group by rn
                    order by rn
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT device_name, ' + @cols + ' from 
             (
                select device_name, app_id,
                  ''App''+
                    cast(row_number() over(partition by device_name 
                                          order by device_name) as varchar(10)) col
                from Aperture_full_test
            ) x
            pivot 
            (
                max(app_id)
                for col in (' + @cols + ')
            ) p '

execute(@query)

SQL Fiddle with Demo。两者都给出了结果:

| DEVICE_NAME |    APP1 |    APP2 |    APP3 |    APP4 |
-------------------------------------------------------
|   AUSSQL140 |  537990 | 1349605 |  (null) |  (null) |
|    EU456CLX | 6545789 |  (null) |  (null) |  (null) |
|    EUCTX654 | 5637965 | 6464367 | 1323123 | 1004326 |
|    JAP543X2 | 5646789 |  (null) |  (null) |  (null) |
|  LDNSQLF700 |  157848 |  155439 |  635533 |  (null) |
|    NYSQL502 |  189164 |  188641 |  (null) |  (null) |

编辑,如果要计算每台服务器的设备总数,则可以使用count() over()。硬编码版本将是:

select device_name, TotalDevices, App1, App2, App3, App4, App5
from
(
  select device_name, app_id,
    'App'+
      cast(row_number() over(partition by device_name 
                            order by device_name) as varchar(10)) col,
    count(app_id) over(partition by device_name) TotalDevices  -- add this line
  from Aperture_full_test
) d
pivot
(
  max(app_id)
  for col in (App1, App2, App3, App4, App5)
) piv;

请参阅SQL Fiddle with Demo

答案 1 :(得分:0)

这是一个数据透视查询,可以在group by中完成。您需要的是应用程序的序列号。

select aft.deviceName, COUNT(*) as NumApps,
       MAX(case when seqnum = 1 then App_id end) as App1,
       MAX(case when seqnum = 2 then App_id end) as App2,
       MAX(case when seqnum = 3 then App_id end) as App3,
       MAX(case when seqnum = 4 then App_id end) as App4,
       MAX(case when seqnum = 5 then App_id end) as App5
from (select aft.*,
             ROW_NUMBER() over (partition by device_name order by (select NULL)) as seqnum
      from Aperture_full_test aft
     ) aft
group by aft.deviceName
order by NumApps desc

由于xml代码没有按特定顺序排列,因此该版本没有特定顺序的应用程序。