I have a simple table that looks like this:
ClientID ItemID
1 1
1 2
1 3
2 1
2 2
3 3
4 3
5 1
5 2
5 4
5 5
where both columns combine to be the primary key. I am now tasked with identifying all the unique sets of ItemIDs assigned to ClientIDs. So in my example, the sets would be:
ItemIDs 1,2,3 (used by ClientID 1)
ItemIDs 1,2 (used by C开发者_如何学JAVAlientID 2)
ItemIDs 3 (used by ClientIDs 3 and 4)
ItemIDs 1,2,4,5 (used by ClientID 5)
Ideally the output would be two tables:
SetID ItemID
1 1
1 2
1 3
2 1
2 2
3 3
4 1
4 2
4 4
4 5
ClientID SetID
1 1
2 2
3 3
4 3
5 4
where SetID would be a new field for use elsewhere.
Currently the way I have of identifying the unique sets involves using a cursor to build a string of the ordered ItemIDs for each ClientID, then comparing the output to get the unique strings, and finally parsing it back. It was quick enough to write but feels horrible.
I'm sure there must be a better way than this. Any ideas?
-- Table to hold test data
declare @T table
(
ClientID int,
ItemID int
)
insert into @T values
(1, 1),(1, 2),(1, 3),
(2, 1),(2, 2),
(3, 3),(4, 3),
(5, 1),(5, 2),(5, 4),(5, 5)
-- Temp table that will hold the generated set's
declare @Tmp table
(
ClientID int,
ItemIDSet varchar(max),
SetID int
)
-- Query the sets using rank() over a comma separated ItemIDSet
insert into @Tmp
select ClientID,
ItemIDSet,
rank() over(order by ItemIDSet) as SetID
from (
select T1.ClientID,
stuff((select ','+cast(T2.ItemID as varchar(10))
from @T as T2
where T1.ClientID = T2.ClientID
order by T2.ItemID
for xml path('')), 1, 1, '') as ItemIDSet
from @T as T1
group by T1.ClientID
) as T
-- Get ClientID and SetID from @Tmp
select ClientID,
SetID
from @Tmp
order by ClientID
-- Get SetID and ItemID from @Tmp
select SetID,
T3.N.value('.', 'int') as ItemID
from (
select distinct
SetID,
'<i>'+replace(ItemIDSet, ',', '</i><i>')+'</i>' as ItemIDSet
from @Tmp
) as T1
cross apply
(
select cast(T1.ItemIDSet as xml) as ItemIDSet
) as T2
cross apply T2.ItemIDSet.nodes('i') as T3(N)
Result:
ClientID SetID
----------- -----------
1 2
2 1
3 4
4 4
5 3
SetID ItemID
----------- -----------
1 1
1 2
2 1
2 2
2 3
3 1
3 2
3 4
3 5
4 3
The values of SetID's is not exactly the same as in the output you have provided but I don't think that would be a big issue. The SetID's are generated from the rank function rank() over(order by ItemIDSet)
ordered by ItemIDSet.
Take it for a spin.
精彩评论