Сведения о вопросе

Codeliver

06:18, 21st August, 2020

Теги

sql    

Группировка запусков данных

Просмотров: 413   Ответов: 6

SQL эксперты,

Есть ли эффективный способ группировать прогоны данных вместе с помощью 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, она работала в предварительном просмотре, но не в окончательном отображении.



  Сведения об ответе

crush

15:16, 16th August, 2020

Попробовать это:

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

Я думаю, что это будет делать то, что вы хотите. Хотя немного Клудж.

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


  Сведения об ответе

qwerty101

10:47, 22nd August, 2020

Я страстно ненавижу курсоры... но вот хитрая версия курсора...

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


  Сведения об ответе

crush

06:19, 8th August, 2020

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

-- 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
*/


  Сведения об ответе

ASSembler

08:38, 27th August, 2020

Ну, это:

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: О, я вижу, вы хотите, чтобы последовательные прогоны сгруппированы. В этом случае я бы сказал, что вам нужен курсор или сделать это в вашем программном коде.


  Сведения об ответе

nYU

12:24, 3rd August, 2020

Как насчет этого:

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


  Сведения об ответе

PAGE

21:37, 1st August, 2020

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

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

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

Вы можете получить все это в виде одного столбца путем объединения следующим образом:

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться