2008-08-22 2 views
7

SQL Experts,Групповые прогоны данных

Есть ли эффективный способ группировки прогонов данных вместе с использованием SQL?
Или это будет более эффективно обрабатывать данные в коде.

Например, если у меня есть следующие данные:

ID|Name 
01|Harry Johns 
02|Adam Taylor 
03|John Smith 
04|John Smith 
05|Bill Manning 
06|John Smith 

Мне нужно показать это:

Harry Johns 
Adam Taylor 
John Smith (2) 
Bill Manning 
John Smith 

@ Matt: К сожалению, у меня были проблемы форматирования данных с помощью встроенного HTML таблицы он работал в предварительном просмотре, но не на конечном дисплее.

ответ

2

Попробуйте это:

select n.name, 
    (select count(*) 
    from myTable n1 
    where n1.name = n.name and n1.id >= n.id and (n1.id <= 
     (
     select isnull(min(nn.id), (select max(id) + 1 from myTable)) 
     from myTable nn 
     where nn.id > n.id and nn.name <> n.name 
     ) 
    )) 
from myTable n 
where not exists (
    select 1 
    from myTable n3 
    where n3.name = n.name and n3.id < n.id and n3.id > (
      select isnull(max(n4.id), (select min(id) - 1 from myTable)) 
      from myTable n4 
      where n4.id < n.id and n4.name <> n.name 
      ) 
) 

Я думаю, что будет делать то, что вы хотите. Тем не менее, бит клочья.

Фу! После нескольких исправлений я думаю, что у меня все случаи, связанные с краем, разобрались.

+0

, который группирует Строки с определенным именем. OP хотел сгруппировать консекутивные строки, я не знаю, как это сделать в SQL. – Nickolay 2008-08-22 00:20:01

0

Для этого конкретного случая, все, что вам нужно сделать, это группа по имени и попросить граф, как это:

select Name, count(*) 
from MyTable 
group by Name 

Это будет получить вам счет для каждого имени в качестве второго столбца.

Вы можете получить все это в одном столбце конкатенацией, как это:

select Name + ' (' + cast(count(*) as varchar) + ')' 
from MyTable 
group by Name 
1

Ну, это:

select Name, count(Id) 
from MyTable 
group by Name 

даст вам это:

Harry Johns, 1 
Adam Taylor, 1 
John Smith, 2 
Bill Manning, 1 

и это (MS SQL):

select Name + 
    case when (count(Id) > 1) 
     then ' ('+cast(count(Id) as varchar)+')' 
     else '' 
    end 
from MyTable 
group by Name 

даст вам следующее:

Harry Johns 
Adam Taylor 
John Smith (2) 
Bill Manning 

ли вы на самом деле хотите, чтобы другие Джон Смит на конце ваших результатов?

EDIT: О, я вижу, вы хотите, чтобы последовательные прогоны группировались. В этом случае, я бы сказал, вам нужен курсор или сделать это в коде программы.

2

Я ненавижу курсоры со страстью ... но вот изворотливая версия курсора ...

Declare @NewName Varchar(50) 
Declare @OldName Varchar(50) 
Declare @CountNum int 
Set @CountNum = 0 

DECLARE nameCursor CURSOR FOR 
SELECT Name 
FROM NameTest 
OPEN nameCursor 

FETCH NEXT FROM nameCursor INTO @NewName 

    WHILE @@FETCH_STATUS = 0 

    BEGIN 

     if @OldName <> @NewName 
     BEGIN 
     Print @OldName + ' (' + Cast(@CountNum as Varchar(50)) + ')' 
     Set @CountNum = 0 
     END 
     SELECT @OldName = @NewName 
     FETCH NEXT FROM nameCursor INTO @NewName 
     Set @CountNum = @CountNum + 1 

    END 
Print @OldName + ' (' + Cast(@CountNum as Varchar(50)) + ')' 

CLOSE nameCursor 
DEALLOCATE nameCursor 
1

Как об этом:

declare @tmp table (Id int, Nm varchar(50)); 

insert @tmp select 1, 'Harry Johns'; 
insert @tmp select 2, 'Adam Taylor'; 
insert @tmp select 3, 'John Smith'; 
insert @tmp select 4, 'John Smith'; 
insert @tmp select 5, 'Bill Manning'; 
insert @tmp select 6, 'John Smith'; 

select * from @tmp order by Id; 

select Nm, count(1) from 
(
select Id, Nm, 
    case when exists (
     select 1 from @tmp t2 
     where t2.Nm=t1.Nm 
     and (t2.Id = t1.Id + 1 or t2.Id = t1.Id - 1)) 
     then 1 else 0 end as Run 
from @tmp t1 
) truns group by Nm, Run 

[Edit] Это может быть сокращен немного

select Nm, count(1) from (select Id, Nm, case when exists (
     select 1 from @tmp t2 where t2.Nm=t1.Nm 
     and abs(t2.Id-t1.Id)=1) then 1 else 0 end as Run 
from @tmp t1) t group by Nm, Run 
2

Мое решение только для пинков (это было веселое упражнение), не курсоры, нет итераций, но у меня есть вспомогательное поле

-- Setup test table 
DECLARE @names TABLE (
         id  INT     IDENTITY(1,1), 
         name NVARCHAR(25)  NOT NULL, 
         grp  UNIQUEIDENTIFIER NULL 
         ) 

INSERT @names (name) 
SELECT 'Harry Johns' UNION ALL 
SELECT 'Adam Taylor' UNION ALL 
SELECT 'John Smith'  UNION ALL 
SELECT 'John Smith'  UNION ALL 
SELECT 'Bill Manning' UNION ALL 
SELECT 'Bill Manning' UNION ALL 
SELECT 'Bill Manning' UNION ALL 
SELECT 'John Smith'  UNION ALL 
SELECT 'Bill Manning' 

-- Set the first id's group to a newid() 
UPDATE  n 
SET   grp = newid() 
FROM  @names n 
WHERE  n.id = (SELECT MIN(id) FROM @names) 

-- Set the group to a newid() if the name does not equal the previous 
UPDATE  n 
SET   grp = newid() 
FROM  @names n 
INNER JOIN @names b 
     ON (n.ID - 1) = b.ID 
     AND ISNULL(b.Name, '') <> n.Name 

-- Set groups that are null to the previous group 
-- Keep on doing this until all groups have been set 
WHILE (EXISTS(SELECT 1 FROM @names WHERE grp IS NULL)) 
BEGIN 
    UPDATE  n 
    SET   grp = b.grp 
    FROM  @names n 
    INNER JOIN @names b 
      ON (n.ID - 1) = b.ID 
      AND n.grp IS NULL 
END 

-- Final output 
SELECT  MIN(id)  AS id_start, 
      MAX(id)  AS id_end, 
      name, 
      count(1) AS consecutive 
FROM  @names 
GROUP BY grp, 
      name 
ORDER BY id_start 

/* 
Results: 

id_start id_end name   consecutive 
1   1  Harry Johns  1 
2   2  Adam Taylor  1 
3   4  John Smith  2 
5   7  Bill Manning 3 
8   8  John Smith  1 
9   9  Bill Manning 1 
*/ 
Смежные вопросы