2008-08-22 19 views
7

SQLエキスパートデータのグループ化

SQLを使用して複数のデータを効率的にグループ化する方法はありますか?
コードでデータを処理する方が効率的になるでしょうか。例えば

私は、次のデータがある場合:

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

@Matt:

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

を、私はこれを表示する必要が申し訳ありませんが、私は悩み、それが働いた組み込み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 
      ) 
) 

は、私はそれはあなたがやりたいと思います。しかし、クルージングのビット。

Phew!いくつかの編集の後、私はすべてのエッジケースを整理していると思う。

+0

特定の名前の行を表示します。 OPは一連の行をグループ化したいと思っていましたが、私はSQLでそれを行う方法を知らない。 – Nickolay

0

、あなたがする必要があるすべてのグループは、名前であり、このように、カウント数を求める:

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

は、すなわち、第2列とそれぞれの名前のためにあなたの数を取得します。

あなたはこのように連結して1列としてそれをすべてを取得することができます。この、

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 

あなたが実際にあなたの結果の最後に他のジョン・スミスという希望でしたか?

編集:ああ私は、あなたが連続してランをグループ化したいと思う。その場合は、カーソルが必要であるとか、プログラムコードでカーソルが必要だと言えます。

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 

ビットを短縮することができ、[編集]

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 
*/ 
関連する問題