合并有相同号码的员工 ,比如下面KFID =001 的有2个号码,其中一个号码在KFID=002 里也出现了,我们就把KFID001,002分在同一组中,然后KFID =002 的13500000002又在 KFID =003中出现,那么FID001,002,003应该都分在同一组中 ,以此类推,如何能高效的分组,请教源:
KFID KFNO
001 13500000001
001 13500000002
002 13500000002
002 13500000003
003 13500000003
003 13500000004
004 13500000005
005 13500000006最终生成下表
KFID GRPID
001 1
002 1
003 1
004 2
005 3
KFID KFNO
001 13500000001
001 13500000002
002 13500000002
002 13500000003
003 13500000003
003 13500000004
004 13500000005
005 13500000006最终生成下表
KFID GRPID
001 1
002 1
003 1
004 2
005 3
INSERT @TB
SELECT '001', '13500000001' UNION ALL
SELECT '001', '13500000002' UNION ALL
SELECT '002', '13500000002' UNION ALL
SELECT '002', '13500000003' UNION ALL
SELECT '003', '13500000003' UNION ALL
SELECT '003', '13500000004' UNION ALL
SELECT '004', '13500000005' UNION ALL
SELECT '005', '13500000006';WITH CTE AS
(
SELECT A.KFID AS KFID1,A.KFNO AS FKNO1,B.KFID AS KFID2,B.KFNO AS KFNO2,
ROW_NUMBER() OVER (ORDER BY A.KFID,A.KFNO) AS SEQ
FROM @TB AS A LEFT JOIN @TB AS B
ON A.KFNO=B.KFNO AND A.KFID<>B.KFID
)
,
CTE2 AS
(
SELECT *, 1 AS GRP FROM CTE WHERE SEQ=1
UNION ALL
SELECT C1.*,CASE WHEN C1.KFID1=C2.KFID1 OR C1.KFNO2=C2.KFNO2 THEN GRP ELSE GRP+1 END
FROM CTE AS C1, CTE2 AS C2
WHERE C1.SEQ=C2.SEQ+1
)
SELECT DISTINCT KFID1,GRP FROM CTE2
/*
KFID1 GRP
----- -----------
001 1
002 1
003 1
004 2
005 3
*/
--不嫌效率低的话,跑个cursor吧
create table T(kfid varchar(03), kfno varchar(11))
insert into T select '001', '13500000001'
insert into T select '001', '13500000002'
insert into T select '002' , '13500000002'
insert into T select '002' , '13500000003'
insert into T select '003' , '13500000003'
insert into T select '003' , '13500000004'
insert into T select '004' , '13500000005'
insert into T select '005' , '13500000006' GOselect kfid,kfno,
tmp=(select count(distinct kfno) from T where kfno<=A.kfno)
into #temp
from T as Aselect distinct tmp into #id from #tempdeclare @tmp int, @i int
set @i=1
declare c1 cursor for select tmp from #id order by tmp
open c1
fetch next from c1 into @tmp
while @@fetch_status=0
begin
if exists(select top 1 1 from #temp where tmp=@tmp)
begin
update #temp
set tmp=@i
where exists(select top 1 1
from #temp A
where A.tmp=#temp.tmp
and exists(select top 1 1 from #temp B
where B.kfid=A.kfid
and B.tmp=@tmp)
)
end if exists(select top 1 1 from #temp where tmp!=@i
and kfid in
(select kfid from #temp where tmp= @i)) begin
select @tmp=max(tmp)
from #temp
where kfid in
(select kfid from #temp where tmp= @i)
end
else
begin
set @i=@i+1
fetch next from c1 into @tmp
end
end
close c1
deallocate c1--查看結果
select kfid, (select count(distinct tmp) from #temp where tmp<=A.tmp) as GRPID
from
(
select distinct kfid,tmp from #temp
) as A
/*
kfid GRPID
-----------------------
001 1
002 1
003 1
004 2
005 3*/
drop table #id
drop table #temp
drop table T
DECLARE @TB TABLE([KFID] VARCHAR(3), [KFNO] VARCHAR(11))
INSERT @TB
SELECT '001', '13500000001' UNION ALL
SELECT '001', '13500000002' UNION ALL
SELECT '001', '13500000007' UNION ALL --加条数据,3楼的结果就不对,要改改SELECT '002', '13500000002' UNION ALL
SELECT '002', '13500000003' UNION ALL
SELECT '003', '13500000003' UNION ALL
SELECT '003', '13500000004' UNION ALL
SELECT '004', '13500000005' UNION ALL
SELECT '005', '13500000006'
首先十分感谢csdyyr的解答,
不好意思,可能是我给的数据太少,
还有一种情况,会造成结果不是我想要的,比如数据如下001 13500000001
001 13500000002
002 13500000002
002 13500000003
003 13500000003
003 13500000004
004 13500000005
005 13500000006
006 13500000006 --数据中还有这样的数据(增加)由于这个对应关系,那么我想的结果是:KFID1 GRP
----- -----------
001 1
002 1
003 1
004 2
005 1 --006的关系,导致005也被归为组1了
006 1也就是说这张表是多对多的关系,行数也不规则,求教
数据量不大的话,cursor跑跑就可以了,我的才1w不到的数据,所以就用cursor来搞了
--用辅助函数实现
--创建环境
create table tab
(
ID INT IDENTITY(1,1),
KFID VARCHAR(10),
KFNO VARCHAR(20)
)
goinsert into tab select '001', '13500000001'
insert into tab select '001', '13500000002'
insert into tab select '002', '13500000002'
insert into tab select '002', '13500000003'
insert into tab select '003', '13500000003'
insert into tab select '003', '13500000004'
insert into tab select '004', '13500000005'
insert into tab select '005', '13500000006' GO--建立辅助函数
create function f_getid
(
@kfid varchar(10)
)
returns int
as
begin declare @tab table
(
id int,
KFID VARCHAR(10),
KFNO VARCHAR(20)
)
insert into @tab
select id,kfid,kfno
from tab
where kfid = @kfid while (@@rowcount > 0)
begin
insert into @tab
select id,kfid,kfno
from tab
where kfid in (select kfid from tab where kfno in (select kfno from @tab))
and id not in (select id from @tab)
end declare @id int
select @id = 0
select @id = min(id) from @tab return @id
end
go--查询
with t1(id,kfid,kfno,nid) as
(
select *,dbo.f_getid(kfid) as nid
from tab
)
select distinct kfid,NID = (select count(distinct nid) + 1 from t1 where nid < a.nid)
from t1 a--结果
/*
kfid NID
-------------------- -----------
13500000001 1
13500000002 1
13500000003 1
13500000004 1
13500000005 2
13500000006 3(6 行受影响)
*/
if object_id('[tb]') is not null drop table [tb]
create table [tb]([KFID] varchar(3),[KFNO] bigint)
insert [tb]
select '001',13500000001 union all
select '001',13500000002 union all
select '002',13500000002 union all
select '002',13500000003 union all
select '003',13500000003 union all
select '003',13500000004 union all
select '004',13500000005 union all
select '005',13500000006select KFID,(select count(distinct KFID) from [tb] where KFID<=r.KFID)-(select sum(group_id)
from (
select KFID ,case when KFNO in (select KFNO from [tb] where KFID=(select max(KFID) from [tb]
where KFID<t.KFID)) then 1 else 0 end as group_id
from [tb] t
) h where KFID<=r.KFID) as GRPID
from
(
select KFID ,case when KFNO in (select KFNO from [tb] where KFID=(select max(KFID) from [tb]
where KFID<t.KFID)) then 1 else 0 end as group_id
from [tb] t
) r
group by KFID--------------------------------
001 1
002 1
003 1
004 2
005 3
if object_id('[tb]') is not null drop table [tb]
create table [tb]([KFID] varchar(3),[KFNO] bigint)
insert [tb]
select '001',13500000001 union all
select '001',13500000002 union all
select '002',13500000002 union all
select '002',13500000003 union all
select '003',13500000003 union all
select '003',13500000004 union all
select '004',13500000005 union all
select '005',13500000006 union all
select '006',13500000006select KFID,(select count(distinct KFID) from [tb] where KFID<=r.KFID)-(select sum(group_id)
from (
select KFID ,case when KFNO in (select KFNO from [tb] where KFID=(select max(KFID) from [tb]
where KFID<t.KFID)) then 1 else 0 end as group_id
from [tb] t
) h where KFID<=r.KFID) as GRPID
from
(
select KFID ,case when KFNO in (select KFNO from [tb] where KFID=(select max(KFID) from [tb]
where KFID<t.KFID)) then 1 else 0 end as group_id
from [tb] t
) r
group by KFID----------------------------------
001 1
002 1
003 1
004 2
005 3
006 3
你加 select '006',13500000004
001 13500000002
001 13500000006 --增加此行 ……还可能更多的号出现在其他KFID里,然后其他里面又有号在其他里,总之可能是个多分支
002 13500000002
002 13500000003
003 13500000003
003 13500000006
004 13500000005
005 13500000006
006 13500000006 playwarcraft 说的差不多~
但是游标效率太低,有没有更好的方法?
只不过,可以将取得的KFID放入临时表,尽量少跑~
暂且这样试试~
INSERT @TB
SELECT '001', '13500000002' UNION ALL
SELECT '001', '13500000006' UNION ALL
SELECT '002', '13500000002' UNION ALL
SELECT '002', '13500000003' UNION ALL
SELECT '003', '13500000003' UNION ALL
SELECT '003', '13500000006' UNION ALL
SELECT '004', '13500000005' UNION ALL
SELECT '005', '13500000006' UNION ALL
SELECT '006', '13500000006' CREATE TABLE #([KFID] VARCHAR(3), [KFNO] VARCHAR(11), ID INT IDENTITY(1,1))
INSERT #
SELECT * FROM @TB ORDER BY KFIDCREATE UNIQUE INDEX IX_ID ON #(ID)DECLARE @TB2 TABLE([KFID] VARCHAR(3), [KFNO] VARCHAR(11), GRP INT)
DECLARE @GRP INT, @ID INT
SET @GRP=1
SET @ID=1INSERT @TB2
SELECT KFID,KFNO,@GRP FROM # WHERE ID=@IDWHILE @@ROWCOUNT>0
BEGIN
SET @GRP=@GRP+1
SET @ID=@ID+1 INSERT @TB2
SELECT TOP 1 T.KFID,T.KFNO,ISNULL(GRP,@GRP)
FROM # AS T LEFT JOIN @TB2 AS T2
ON T.KFID=T2.KFID OR T.KFNO=T2.KFNO
WHERE T.ID=@ID
END;WITH CTE AS
(
SELECT *,ROW_NUMBER() OVER (ORDER BY GRP) AS SEQ FROM @TB2
),
CTE2 AS
(
SELECT *,1 AS GRPID FROM CTE WHERE SEQ=1
UNION ALL
SELECT T.*,CASE WHEN T.GRP=T2.GRP THEN GRPID ELSE GRPID+1 END
FROM CTE AS T,CTE2 AS T2
WHERE T.SEQ=T2.SEQ+1
)SELECT DISTINCT KFID,GRPID FROM CTE2DROP TABLE #
/*
KFID GRPID
---- -----------
001 1
002 1
003 1
004 2
005 1
006 1(6 行受影响)
*/
WHILE @@ROWCOUNT>0
BEGIN
SET @GRP=@GRP+1
SET @ID=@ID+1 INSERT @TB2
SELECT TOP 1 T.KFID,T.KFNO,ISNULL(GRP,@GRP)
FROM # AS T LEFT JOIN @TB2 AS T2
ON T.KFID=T2.KFID OR T.KFNO=T2.KFNO
WHERE T.ID=@ID
ORDER BY T2.KFID DESC
END
SELECT '001', '13500000006' UNION ALL
SELECT '001', '13500000009' UNION ALL
SELECT '001', '13500000010' UNION ALL
SELECT '002', '13500000002' UNION ALL
SELECT '002', '13500000003' UNION ALL
SELECT '003', '13500000003' UNION ALL
SELECT '003', '13500000006' UNION ALL
SELECT '004', '13500000005' UNION ALL
SELECT '005', '13500000006' UNION ALL
SELECT '006', '13500000006' UNION ALL
SELECT '007', '13500000009' UNION ALL
SELECT '008', '13500000009' UNION ALL
SELECT '010', '13500000010'
这种实现,应该不会是实时的查询用吧?如果是做report的话,不必在乎这一点点performance的浪费。
DECLARE @TB TABLE([KFID] VARCHAR(3), [KFNO] VARCHAR(11))
INSERT @TB
SELECT '001', '13500000002' UNION ALL
SELECT '001', '13500000006' UNION ALL
SELECT '001', '13500000009' UNION ALL
SELECT '001', '13500000010' UNION ALL
SELECT '002', '13500000002' UNION ALL
SELECT '002', '13500000005' UNION ALL
SELECT '003', '13500000003' UNION ALL
SELECT '003', '13500000006' UNION ALL
SELECT '004', '13500000005' UNION ALL
SELECT '005', '13500000006' UNION ALL
SELECT '006', '13500000006' UNION ALL
SELECT '007', '13500000009' UNION ALL
SELECT '008', '13500000009' UNION ALL
SELECT '010', '13500000010' CREATE TABLE #([KFID] VARCHAR(3), [KFNO] VARCHAR(11), [KFID2] VARCHAR(3), [KFNO2] VARCHAR(11), ID INT IDENTITY(1,1))
INSERT #
SELECT T.KFID, T.KFNO, T2.KFID AS KFID2, T2.KFNO AS KFNO2
FROM @TB AS T LEFT JOIN @TB AS T2
ON T.KFID<>T2.KFID AND T.KFNO=T2.KFNO
ORDER BY T.KFID,CASE WHEN T2.KFID IS NULL THEN 1 ELSE 0 END,T2.KFIDCREATE UNIQUE INDEX IX_ID ON #(ID)DECLARE @TB2 TABLE([KFID] VARCHAR(3), [KFNO] VARCHAR(11),[KFID2] VARCHAR(3), [KFNO2] VARCHAR(11), GRP INT)
DECLARE @GRP INT, @ID INT
SET @GRP=1
SET @ID=1INSERT @TB2
SELECT KFID,KFNO,KFID2,KFNO2,@GRP FROM # WHERE ID=@IDWHILE @@ROWCOUNT>0
BEGIN
SET @GRP=@GRP+1
SET @ID=@ID+1 INSERT @TB2
SELECT TOP 1 T.KFID,T.KFNO,T.KFID2,T.KFNO2,ISNULL(GRP,@GRP)
FROM # AS T LEFT JOIN @TB2 AS T2
ON T.KFID=T2.KFID OR T.KFNO2=T2.KFNO2 OR T.KFID2=T2.KFID2
WHERE T.ID=@ID
ORDER BY T2.KFID2 DESC
END --SELECT * FROM # DROP TABLE #;WITH CTE AS
(
SELECT *,ROW_NUMBER() OVER (ORDER BY GRP) AS SEQ FROM @TB2
),
CTE2 AS
(
SELECT *,1 AS GRPID FROM CTE WHERE SEQ=1
UNION ALL
SELECT T.*,CASE WHEN T.GRP=T2.GRP THEN GRPID ELSE GRPID+1 END
FROM CTE AS T,CTE2 AS T2
WHERE T.SEQ=T2.SEQ+1
)SELECT DISTINCT KFID,GRPID FROM CTE2DROP TABLE #
/*
KFID GRPID
---- -----------
001 1
002 1
003 1
004 1
005 1
006 1
007 1
008 1
010 1(9 行受影响)
*/
DECLARE @TB TABLE([KFID] VARCHAR(3), [KFNO] VARCHAR(11))
INSERT @TB
SELECT '001', '13500000001' UNION ALL
SELECT '001', '13500000004' UNION ALL
SELECT '001', '13500000008' UNION ALL
SELECT '001', '13500000010' UNION ALL
SELECT '002', '13500000002' UNION ALL
SELECT '002', '13500000003' UNION ALL
SELECT '003', '13500000003' UNION ALL
SELECT '003', '13500000006' UNION ALL
SELECT '004', '13500000005' UNION ALL
SELECT '005', '13500000001' UNION ALL
SELECT '006', '13500000006' UNION ALL
SELECT '007', '13500000009' UNION ALL
SELECT '008', '13500000009' UNION ALL
SELECT '010', '13500000001'
CREATE TABLE #([KFID] VARCHAR(3), [KFID2] VARCHAR(3), [KFNO2] VARCHAR(11), GRP INT, ID INT IDENTITY(1,1))
INSERT #
SELECT T.KFID, T2.KFID AS KFID2, T2.KFNO AS KFNO2, 0 AS GRP
FROM @TB AS T LEFT JOIN @TB AS T2
ON T.KFID<>T2.KFID AND T.KFNO=T2.KFNO
ORDER BY T.KFID,CASE WHEN T2.KFID IS NULL THEN 1 ELSE 0 END,T2.KFID
--SELECT * FROM #CREATE CLUSTERED INDEX IX_KFID ON #(KFID)
CREATE INDEX IX_KFID2 ON #(KFID2)
CREATE INDEX IX_KFNO2 ON #(KFNO2)
CREATE UNIQUE INDEX IX_ID ON #(ID)DECLARE @GRP INT, @ID INT, @KFID VARCHAR(3), @KFID2 VARCHAR(3),@KFNO2 VARCHAR(11), @ROWCNT INT, @MAXGRP INT
SET @GRP=1
SET @MAXGRP=1
SET @ID=1SELECT @KFID=KFID FROM # WHERE ID=@ID
UPDATE # SET GRP=@GRP WHERE KFID=@KFID
SET @ROWCNT=@@ROWCOUNTWHILE @ROWCNT>0
BEGIN
SET @ID=@ID+@ROWCNT
SELECT TOP 1 @MAXGRP=CASE WHEN T2.GRP IS NULL THEN @MAXGRP+1 ELSE @MAXGRP END,
@GRP=ISNULL(T2.GRP, @MAXGRP),
@KFID=T.KFID
FROM # AS T LEFT JOIN # AS T2
ON (T.KFID2=T2.KFID2 OR T.KFNO2=T2.KFNO2) AND T2.KFID<T.KFID
WHERE T.ID=@ID
ORDER BY T2.KFID
UPDATE # SET GRP=@GRP WHERE KFID=@KFID AND GRP=0
SET @ROWCNT=@@ROWCOUNT
END
SELECT DISTINCT KFID,GRP FROM #DROP TABLE #
/*
KFID GRP
---- -----------
001 1
002 2
003 2
004 3
005 1
006 2
007 4
008 4
010 1(9 行受影响)
*/