一個1年前的T-SQL問題


還記得年前的一個SQL問題,當時對SQL剛接觸,因此繞開了它。用了別的辦法。昨天看SQL突然想起了這個問題。百思不得其解,然后去SQL Server技術交流群,也請教了,大神高文佳,何志勇提示我因為先分組然后再鏈接。但由於小弟技術是在是太菜,因此沒能弄出我想要的結果來。后來由於太晚的原因或者是問題太簡單(當然大神們實在是很熱情),大神們都睡覺了。今天還是在糾結這個問題的解決方法。

先給出測試用的初始化表和數據:

CREATE TABLE [dbo].tab_1(
	[Id] [int] NOT NULL,
	[SkillId] [int] NOT NULL
) ON [PRIMARY]

CREATE TABLE [dbo].tab_2(
	[Id] [int] NOT NULL,
	[SkillId] [int] NOT NULL
) ON [PRIMARY]

GO

insert into tab_1 values(1,1)
insert into tab_1 values(1,2)
insert into tab_1 values(2,1)
insert into tab_1 values(2,3)
insert into tab_1 values(2,6)

insert into tab_2 values(5,1)
insert into tab_2 values(5,2)
insert into tab_2 values(5,4)
insert into tab_2 values(7,1)
insert into tab_2 values(7,3)
insert into tab_2 values(7,6)

查詢表數據如下:

 tab_1

tab_2

問題1:現在的問題是想查出這部分數據(語言表達能力不好,我就直接給圖了^_^):

也就是每組根據Id分組后,取tab_1和tab_2有完全相同的SkillId分組項。

開始就一直思考如何用分組、聯接來實現。后來發現有各種不同的問題(當然是我的問題),最終換了思路,將每個表根據主鍵分組(為了測試方便我沒有設主鍵),然后使用合並列的方法來曲線實現了一下:

with cte1 as(
	select Id, stuff((select ','+ CONVERT(varchar,SkillId) from tab_1 t where t.Id=t1.Id  for xml path('')),1,1,'') as Skills from tab_1 t1
	group by Id
),
cte2 as(
	select Id, stuff((select ','+ CONVERT(varchar,SkillId) from tab_2 tt where tt.Id=tt1.Id for xml path('')),1,1,'') as Skills from tab_2 tt1
	group by Id
)select * from cte1 join cte2 on cte1.Skills=cte2.Skills

但是我想這個方法是不好的。因為如果此時我給表tab_1添加一列:

insert into tab_1 values(2,5)

問題2:我想取出這部分數據:

也就是每組根據Id分組后,判斷tab_1的某個分組的SkillId是否完整包含tab_2的某個分組的SkillId。這個時候再用分組合並的辦法就不管用了。

當然呢,大神們很快就發現了使用charindex來實現:

with cte1 as(
    select Id, stuff((select ','+ CONVERT(varchar,SkillId) from tab_1 t where t.Id=t1.Id  for xml path('')),1,1,'') as Skills from tab_1 t1
    group by Id
),
cte2 as(
    select Id, stuff((select ','+ CONVERT(varchar,SkillId) from tab_2 tt where tt.Id=tt1.Id for xml path('')),1,1,'') as Skills from tab_2 tt1
    group by Id
)select * from cte1 join cte2 on CHARINDEX(cte2.Skills,cte1.Skills)=1

以上只是用到了SQL Server的for xml path()列轉行,stuff()字符串函數截取以及charindex()字符串函數來比較字符串。

另外根據@小飛蝦、@小不正經提供的思路:

1.對2各表分別根據主鍵字段組內排序計算出每組的總數

2.對結果1的2個表根據關聯字段SkillId進行表聯接,並根據1中2個表的主鍵字段進行組內排序,計算出此結果集的每組的總數

3.將2得出的結果集進行條件運算。如果問題1的要求則用等號計算;如果是問題2的要求則用>=計算。T-SQL如下:

with cte1 as(
   select id,SkillId,count(1) over (partition by Id) as count1 from tab_1
),cte2 as(
   select id,SkillId,count(1) over (partition by Id) as count2 from tab_2
),cte3 as(
   select cte1.Id,cte1.Skillid,count1,cte2.Id as Id2,cte2.SkillId as SkillId2,cte2.count2,
   COUNT(1) over (partition by cte1.Id,cte2.Id) as count3
   from cte1  full join cte2
   on cte1.SkillId=cte2.SkillId
)select Id,SkillId,Id2,SkillId2 from cte3
where count1 >=count2 and count3 >=count2

那么有什么更多的好的辦法沒有呢?肯定是有的對吧。請各抒己見,在此肯求大伙兒熱心指教。不勝感激!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM