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表格格式化数据时遇到了问题,该表格在预览中有效但不在最终显示中。
答案 0 :(得分: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
)
)
我认为你会做你想做的事。虽然有点像kludge。
唷!经过一些编辑后,我想我已经整理了所有边缘案例。
答案 1 :(得分: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
答案 2 :(得分: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
*/
答案 3 :(得分: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
你真的想要结果的其他约翰史密斯吗?
编辑:哦,我明白了,你想要连续分组。在这种情况下,我会说你需要一个光标或者在程序代码中执行它。
答案 4 :(得分: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
答案 5 :(得分:0)
对于这种特殊情况,您需要做的就是按名称分组并询问计数,如下所示:
select Name, count(*)
from MyTable
group by Name
这会让你把每个名字的计数作为第二列。
你可以通过这样连接来将它全部作为一列:
select Name + ' (' + cast(count(*) as varchar) + ')'
from MyTable
group by Name