Finding Common Groups

Hi All,

I’ve been out of the SQL game for a while now and am trying to get back into it. I have some data I’m trying to find matching groups of. I’m not even really sure how to describe what I’m looking for.

I have two data points. Teams and people. Each team has one or more people in it, and I want to find any teams that have the same people in them.

Column 1 Column 2
X Adam
X Dana
X Fiona
Y Adam
Y Becky
Y Carl
Y Eric
Z Adam
Z Becky
Z Carl
Z Eric

We can query the data and get the following.

Teams Adam Becky Carl Dana Eric Fiona
X 1 1 1
Y 1 1 1 1
Z 1 1 1 1

We can see that team Y and Z are the same. There are hundreds of teams and a thousand plus people so I’m trying to build a query that will more readily identify the teams that match each other.

Here’s a quick and naive way:

DROP TABLE IF EXISTS #;

CREATE TABLE # (
    team   CHAR (1)     NOT NULL,
    member VARCHAR (32) NOT NULL,
    PRIMARY KEY (team, member)
);

INSERT  #
VALUES ('X', 'Adam'),
('X', 'Dana'),
('X', 'Fiona'),
('Y', 'Adam'),
('Y', 'Becky'),
('Y', 'Carl'),
('Y', 'Eric'),
('Z', 'Adam'),
('Z', 'Becky'),
('Z', 'Carl'),
('Z', 'Eric');

WITH   checks
AS     (SELECT   team,
                 CHECKSUM_AGG(binary_checksum(member)) AS check_
        FROM     #
        GROUP BY team),
       ties
AS     (SELECT   check_
        FROM     checks
        GROUP BY check_
        HAVING   count(*) > 1)
SELECT b.team as identical_teams
FROM   ties AS a
       INNER JOIN
       checks AS b
       ON a.check_ = b.check_;

It shows they are identical, but if there’s more than 3 groups it won’t pair them up (A=B, C=D, but A<>C). CHECKSUM_AGG() might not be the best way to determine group uniqueness.

I might have a better variation that does identify them that way but not sure I’ll get to it tonight.


DROP TABLE IF EXISTS #teams;
CREATE TABLE #teams ( team varchar(10) NOT NULL, person varchar(50) NOT NULL );
INSERT INTO #teams VALUES
    ('X', 'Adam '),
    ('X', 'Dana '),
    ('X', 'Fiona'),
    ('Y', 'Adam '),
    ('Y', 'Becky'),
    ('Y', 'Carl '),
    ('Y', 'Eric '),
    ('Z', 'Adam '),
    ('Z', 'Becky'),
    ('Z', 'Carl '),
    ('Z', 'Eric ')

DROP TABLE IF EXISTS #team_member_counts;
CREATE TABLE #team_member_counts ( team varchar(10) NOT NULL, member_count int NULL );
INSERT INTO #team_member_counts
SELECT team, COUNT(*)
FROM #teams
GROUP BY team

SELECT tmc1.team, t2.team, tmc1.member_count, t2.matching_members
FROM #team_member_counts tmc1
CROSS APPLY (
    SELECT t2.team, COUNT(*) AS matching_members
    FROM #team_member_counts tmc2
    INNER JOIN #teams t2 ON t2.team = tmc2.team
    INNER JOIN #teams t1 ON t1.team = tmc1.team AND t1.person = t2.person
    WHERE tmc2.team > t1.team AND tmc2.member_count = tmc1.member_count
    GROUP BY t2.team
) AS t2
WHERE tmc1.member_count = t2.matching_members

hi

hope this helps

please excuse me .. know this is a t-sql forum

was able to do "the same thing" using 2D array and looping :slight_smile:
consistent :+1:

image

3D array
REGEX
to do "the same thing"

 * Co Pilot = data given = asked answer
 * correct output given
 * Co pilot = My Query gibberish = still correct output

  
 DAWN of a New AGE era

 * NO programming language 
 * No need = Expensive licenses = lots money = support  

:wink: :winking_face_with_tongue:

What a nice question. I would be inclined to use STRING_AGG() with more normalized data.

Test Data

[code]

CREATE TABLE #Members
(
    member_id int not null
        CONSTRAINT PK_Members PRIMARY KEY
    ,member_name varchar(20) NOT NULL
);
INSERT INTO #Members
VALUES (1, 'Adam'),(2, 'Becky'),(3, 'Carl')
    ,(4, 'Dana'),(5,'Eric'),(6,'Fiona');
CREATE TABLE #Teams
(
    team_id int not null
        CONSTRAINT PK_Teams PRIMARY KEY
    ,team_name varchar(20) NOT NULL
);
INSERT INTO #Teams
VALUES (1, 'X'),(2, 'Y'),(3, 'Z');

CREATE TABLE #TeamMembers
(
    team_id int not null
    ,member_id int not null
    ,CONSTRAINT PK_TeamMembers  PRIMARY KEY (team_id, member_id)
);
INSERT INTO #TeamMembers
VALUES (1, 1),(1, 4),(1, 6),(2, 1),(2, 2),(2, 3)
    ,(2, 5),(3, 1),(3, 2),(3, 3),(3, 5);

[/code]

Try something like:

[code]

WITH MemberGroups
AS
(
    SELECT team_id
        ,STRING_AGG(CAST(member_id AS varchar(MAX)), '-')
            WITHIN GROUP (ORDER BY member_id) AS MemberGroup
    FROM #TeamMembers
    GROUP BY team_id
)
,MultipleGroups
AS
(
    SELECT MemberGroup
    FROM MemberGroups
    GROUP BY MemberGroup
    HAVING COUNT(*) > 1
)
SELECT G.team_id, G.MemberGroup
FROM MemberGroups G
    JOIN MultipleGroups M
        ON G.MemberGroup = M.MemberGroup;
-- etc

[/code]

hi hope this helps JOINS `

create data script

``
DROP TABLE IF EXISTS #data

CREATE TABLE #data (
team CHAR (1) NOT NULL,
member VARCHAR (32) NOT NULL,
PRIMARY KEY (team, member)
);

INSERT #data
VALUES ('X', 'Adam'),
('X', 'Dana'),
('X', 'Fiona'),
('Y', 'Adam'),
('Y', 'Becky'),
('Y', 'Carl'),
('Y', 'Eric'),
('Z', 'Adam'),
('Z', 'Becky'),
('Z', 'Carl'),
('Z', 'Eric');

select 
      a.team
      ,count(b.team) 
from 
    #data a join #data  b 
        on  a.member = b.member 
group by 
       a.team