2013-04-02 3 views
1

Я хочу избавиться от дубликатов в одном столбце (имя_устройства), но сохранить связанные данные из другого столбца (app_id). Каждое устройство может иметь пару приложений (1 -> x, обычно между 1-5), поэтому я хочу поместить эти идентификаторы приложений в новые столбцы, которые я хочу назвать [APP1], [APP2], [APP3] и т. Д. , Лучший вариант - это разновидность динамического Pivot, но любое статическое решение также будет приветствоваться.
Спасибо за помощь.Удалить дубликаты с помощью строки pivot

PS Я придумал код ниже, чем когда-либо, но только в конкатенации APP 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 
+0

** STUFF ((SELECT DISTINCT '' + APP_ID ** – Luv

ответ

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) | 

Edit, если вы хотите, чтобы подсчитать общее количество устройств для каждого сервера, то вы можете использовать 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

+0

Отличный фрагмент кода, особенно динамический. – Mario

+0

Еще один вопрос - есть ли возможность добавить еще один столбец в динамический код SQL (представленный выше), который обеспечит подсчет приложения для каждого сервера? Я попытался 100 раз изменить код, но, похоже, я потерпел неудачу и должен отказаться. – Mario

+0

@Mario Да, вы можете использовать 'count (app_id) over (partition by device_name) ', чтобы получить общее количество устройств для каждого сервера. См. Мое редактирование, я добавил статическую версию запроса с новым столбцом. – Taryn

0

Это стержень запрос, который может быть сделан в группе. Что вам нужно, это порядковый номер для приложений.

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 не имел их в определенном порядке.

+0

Спасибо за этот код Это действительно работает, и это красиво и ясно Looks.. например, я, наконец, понимаю процедуру «по вечеринке по». – Mario

Смежные вопросы