HiveBrain v1.2.0
Get Started
← Back to all entries
patternsqlMinor

SQL: finding unique multi-column value triplet matching multiple rows?

Submitted by: @import:stackexchange-dba··
0
Viewed 0 times
uniquerowsmulticolumnsqlvaluetripletmultiplefindingmatching

Problem

TL;DR: using Transact-SQL/SQL Server, how can I find the rows of a table which match a single "solution" triplet of column values (ColA, ColB, ColC) for some set of values in another column?

More info:
Let's say I've got a table similar to this (ID column removed for focus):

FID
ColA
ColB
ColC

1
1
1
1

1
2
2
2

2
1
1
1

2
3
3
3

3
1
1
1

3
2
2
2

I'm trying to find the common triplet of values for (ColA, ColB, ColC) that exists for each value of FID. In this example, (1, 1, 1) would be that triplet, so I'd like to return something like:

FID
ColA
ColB
ColC

1
1
1
1

2
1
1
1

3
1
1
1

This feels like it should be some kind of set operation using intersect but I'm stumped in how best to model and code this up declaratively. Thoughts? And many thanks in advance for your help!

Clarification: A few points that hopefully will help explain my question.

  • I'm looking for a query to find whatever the triplet may be. I won't necessarily know what it is in the data.



  • The triplet values are not dependent on the FID value, and vice versa. My example just happened to use (1,1,1) which matched one of the FID values. The data could look more like:



FID
ColA
ColB
ColC

13
1
305
507

13
1
415
928

17
2
5
57

17
1
415
928

210
12
305
507

210
1
415
928

So in this case, I'm looking for how to write the query that would find out that (1,415,928) is the triplet common to all FIDs.

Hopefully that helps better frame my question and what I'm looking for :) Please let me know if you need more info.

Solution

One way to find the common tuple:

DECLARE @T table
(
    FID integer NOT NULL,
    ColA integer NOT NULL,
    ColB integer NOT NULL,
    ColC integer NOT NULL
);

INSERT @T
    (FID, ColA, ColB, ColC)
VALUES
    (13,1,305,507),
    (13,1,415,928),
    (17,2,5,57),
    (17,1,415,928),
    (210,12,305,507),
    (210,1,415,928);

SELECT 
    T.ColA, 
    T.ColB, 
    T.ColC
FROM @T AS T
GROUP BY 
    T.ColA, 
    T.ColB, 
    T.ColC
HAVING COUNT_BIG(*) =
(
    SELECT COUNT_BIG(DISTINCT T2.FID) 
    FROM @T AS T2
);


ColA
ColB
ColC

1
415
928

To return all matching tuples:

SELECT 
    T.FID, 
    T.ColA, 
    T.ColB, 
    T.ColC
FROM @T AS T
WHERE EXISTS
(
    SELECT T.ColA, T.ColB, T.ColC
    INTERSECT
    SELECT T2.ColA, T2.ColB, T2.ColC 
    FROM @T AS T2
    WHERE T2.FID <> T.FID
)
AND NOT EXISTS
(
    SELECT T.ColA, T.ColB, T.ColC
    EXCEPT
    SELECT T3.ColA, T3.ColB, T3.ColC 
    FROM @T AS T3
    WHERE T3.FID <> T.FID
);


or

SELECT
    T1.FID, T2.ColA, T2.ColB, T2.ColC
FROM
(
    SELECT T2.FID, rc = COUNT_BIG(*) OVER ()
    FROM @T AS T2
    GROUP BY T2.FID
) AS T1
JOIN 
(
    SELECT T.ColA, T.ColB, T.ColC, rc = COUNT_BIG(DISTINCT T.FID)
    FROM @T AS T
    GROUP BY T.ColA, T.ColB, T.ColC
) AS T2
    ON T2.rc = T1.rc;


both give:

FID
ColA
ColB
ColC

13
1
415
928

17
1
415
928

210
1
415
928

db<>fiddle

Code Snippets

DECLARE @T table
(
    FID integer NOT NULL,
    ColA integer NOT NULL,
    ColB integer NOT NULL,
    ColC integer NOT NULL
);

INSERT @T
    (FID, ColA, ColB, ColC)
VALUES
    (13,1,305,507),
    (13,1,415,928),
    (17,2,5,57),
    (17,1,415,928),
    (210,12,305,507),
    (210,1,415,928);

SELECT 
    T.ColA, 
    T.ColB, 
    T.ColC
FROM @T AS T
GROUP BY 
    T.ColA, 
    T.ColB, 
    T.ColC
HAVING COUNT_BIG(*) =
(
    SELECT COUNT_BIG(DISTINCT T2.FID) 
    FROM @T AS T2
);
SELECT 
    T.FID, 
    T.ColA, 
    T.ColB, 
    T.ColC
FROM @T AS T
WHERE EXISTS
(
    SELECT T.ColA, T.ColB, T.ColC
    INTERSECT
    SELECT T2.ColA, T2.ColB, T2.ColC 
    FROM @T AS T2
    WHERE T2.FID <> T.FID
)
AND NOT EXISTS
(
    SELECT T.ColA, T.ColB, T.ColC
    EXCEPT
    SELECT T3.ColA, T3.ColB, T3.ColC 
    FROM @T AS T3
    WHERE T3.FID <> T.FID
);
SELECT
    T1.FID, T2.ColA, T2.ColB, T2.ColC
FROM
(
    SELECT T2.FID, rc = COUNT_BIG(*) OVER ()
    FROM @T AS T2
    GROUP BY T2.FID
) AS T1
JOIN 
(
    SELECT T.ColA, T.ColB, T.ColC, rc = COUNT_BIG(DISTINCT T.FID)
    FROM @T AS T
    GROUP BY T.ColA, T.ColB, T.ColC
) AS T2
    ON T2.rc = T1.rc;

Context

StackExchange Database Administrators Q#315564, answer score: 7

Revisions (0)

No revisions yet.