2008-08-22 35 views
7

Chuyên gia SQL,Chạy theo nhóm dữ liệu

Có cách hiệu quả để nhóm các luồng dữ liệu cùng nhau bằng SQL không?
Hoặc sẽ xử lý dữ liệu trong mã hiệu quả hơn.

Ví dụ nếu tôi có các dữ liệu sau:

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

tôi cần phải hiển thị này:

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

@ Matt: Xin lỗi tôi gặp khó khăn định dạng dữ liệu sử dụng một bảng html nhúng nó làm việc trong bản xem trước nhưng không có trong màn hình cuối cùng.

Trả lời

2

Hãy thử điều này:

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

Tôi nghĩ rằng tôi sẽ làm những gì bạn muốn. Bit của một kludge mặc dù.

Phew! Sau một vài chỉnh sửa, tôi nghĩ rằng tôi có tất cả các trường hợp cạnh được sắp xếp.

+0

nhóm này ll các hàng có tên cụ thể. OP muốn nhóm các hàng hậu quả, tôi không biết cách thực hiện nó trong SQL. – Nickolay

0

Đối với trường hợp đặc biệt này, tất cả các bạn cần làm là nhóm theo tên và yêu cầu số lượng, như thế này:

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

Điều đó sẽ giúp bạn có được số lượng cho mỗi tên như một cột thứ hai.

Bạn có thể nhận được nó tất cả như một cột bằng cách kết hợp như thế này:

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

Vâng, điều này:

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

sẽ cung cấp cho bạn điều này:

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

và điều này (Cú pháp MS SQL):

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

sẽ cung cấp cho bạn điều này:

Harry Johns 
Adam Taylor 
John Smith (2) 
Bill Manning 

Bạn có thực sự muốn điều đó khác John Smith ở đầu các kết quả của bạn?

EDIT: Ồ tôi hiểu, bạn muốn chạy liên tiếp được nhóm lại. Trong trường hợp đó, tôi muốn nói rằng bạn cần một con trỏ hoặc để làm điều đó trong mã chương trình của bạn.

2

Tôi ghét con trỏ với niềm đam mê ... nhưng đây là phiên bản con trỏ tinh ranh ...

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

Làm thế nào về điều này:

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 

[Chỉnh sửa] Điều đó có thể được rút ngắn một chút

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

Giải pháp của tôi chỉ cần cho đá (đây là một tập thể dục vui vẻ), không có con trỏ, không có lặp lại, nhưng tôi có trường trợ giúp

-- 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 
*/ 
Các vấn đề liên quan