I came across a use case where I wanted to generate a combination table where the attributes of a record had to be matched with all other records in the table. Something like creating list of edges in a Complete Graph using a nodes table.

To give you an example of the requirement, you can consider the following table (Postgres).
create table test_users
(
id uuid default uuid_generate_v4(),
first_name text,
last_name text
);
I added some records into the table using the following insert queries
INSERT INTO public.test_users (id, first_name, last_name) VALUES ('3ef309db-07cd-4e3f-95db-406f8165e54d', 'john', 'doe');
INSERT INTO public.test_users (id, first_name, last_name) VALUES ('50f33b51-1d3a-463c-9d5a-6f0b2c15cba2', 'marry', 'poppins');
INSERT INTO public.test_users (id, first_name, last_name) VALUES ('9812fbcf-d269-47a4-801d-2a8916e114e1', 'tony', 'stark');
INSERT INTO public.test_users (id, first_name, last_name) VALUES ('8d7b8d00-9602-4a12-914d-3df6a40d2716', 'idris', 'alba');
INSERT INTO public.test_users (id, first_name, last_name) VALUES ('2dee874f-f41e-4d68-a341-45e0a18079df', 'john', 'frusciante');
And you’ll get the following table in place
id | first_name | last_name --------------------------------------+------------+------------ 3ef309db-07cd-4e3f-95db-406f8165e54d | john | doe 50f33b51-1d3a-463c-9d5a-6f0b2c15cba2 | marry | poppins 9812fbcf-d269-47a4-801d-2a8916e114e1 | tony | stark 8d7b8d00-9602-4a12-914d-3df6a40d2716 | idris | alba 2dee874f-f41e-4d68-a341-45e0a18079df | john | frusciante
Now I want to create a combination of these names in such a way that the first_name of a row should have all the possible combination available such that (f1, f2) = (f2, f1). To give you some more context the expected output should be as follows.
first_name | first_name | last_name | last_name ------------+------------+------------+------------ john | marry | doe | poppins john | tony | doe | stark john | idris | doe | alba john | john | doe | frusciante marry | tony | poppins | stark marry | idris | poppins | alba marry | john | poppins | frusciante tony | idris | stark | alba tony | john | stark | frusciante idris | john | alba | frusciante
You can see that the combination of column 1 and column 2 for first_name is unique in the table.
The closest that I was able to reach was to have an inner join using the following query.
select t1.first_name,
t2.first_name,
t1.last_name,
t2.last_name
from test_users t1
left join test_users t2 on t1.id <> t2.id;
But this yields all the records where (f1, f2) != (f2, f1) hence creating redundant records. Is there a way to get unique list of edges from the list of nodes in a Complete Graph using SQL?
Advertisement
Answer
Just use < (or >) instead of <>in the join condition:
select
t1.first_name first_name1,
t2.first_name first_name2,
t1.last_name last_name1,
t2.last_name last_name2
from test_users t1
inner join test_users t2 on t1.id < t2.id
Notes:
you probably want to alias the column in the resultset to disambiguate the columns coming from both tables
no need for a
left join– aninner joindoes what you want