How to do join on multiple criteria, returning all combinations of both criteria

SqlSql ServerJoin

Sql Problem Overview


I am willing to bet that this is a really simple answer as I am a noob to SQL.

table 1 has column 1 (criteria 1) column 2 (criteria 2) column 3 (metric 1)

table 2 has column 1 (criteria 1) column 2 (criteria 2) column 3 (metric 2 specific to table2.criteria2)

There can be anywhere from 1 - 5 values of criteria 2 for each criteria 1 on the table.

when I use the join statement here (assuming I identify table 1 as One prior to this):

Select WeddingTable, TableSeat, TableSeatID, Name, Two.Meal
FROM table1 as One
inner join table2 as Two
on One.WeddingTable = Two.WeddingTable and One.TableSeat = Two.TableSeat

I only get one of the criteria 1/criteria 2 combinations even when I know for a fact that there are 3 or 4. How do I get all combinations?

Take the situation where there is a wedding where table 1 is basically a seating chart, and table 2 is the meal option that each table/seat has chosen. Table 1 has the convenient TableSeatID, but Table 2 does not have a comparable ID.

Sample Data:

enter image description here

The results needs to show all 4 lines, being all 3 seats at WeddingTable 001 and the one seat at WeddingTable 002.

Desired Results:

enter image description here

Sql Solutions


Solution 1 - Sql

select one.*, two.meal
from table1 as one
left join table2 as two
on (one.weddingtable = two.weddingtable and one.tableseat = two.tableseat)

Solution 2 - Sql

SELECT  aa.*,
        bb.meal
FROM    table1 aa
        INNER JOIN table2 bb
            ON aa.tableseat = bb.tableseat AND
                aa.weddingtable = bb.weddingtable
        INNER JOIN
        (
            SELECT  a.tableSeat
            FROM    table1 a
                    INNER JOIN table2 b
                        ON a.tableseat = b.tableseat AND
                            a.weddingtable = b.weddingtable
            WHERE b.meal IN ('chicken', 'steak')
            GROUP by a.tableSeat
            HAVING COUNT(DISTINCT b.Meal) = 2
        ) c ON aa.tableseat = c.tableSeat

Solution 3 - Sql

create table a1
(weddingTable INT(3),
 tableSeat INT(3),
 tableSeatID INT(6),
 Name varchar(10));

insert into a1
 (weddingTable, tableSeat, tableSeatID, Name)
 values (001,001,001001,'Bob'),
 (001,002,001002,'Joe'),
 (001,003,001003,'Dan'),
 (002,001,002001,'Mark');

create table a2
 (weddingTable int(3),
 tableSeat int(3),
 Meal varchar(10));

insert into a2
(weddingTable, tableSeat, Meal)
values 
(001,001,'Chicken'),
(001,002,'Steak'),
(001,003,'Salmon'),
(002,001,'Steak');

select x.*, y.Meal

from a1 as x
JOIN a2 as y ON (x.weddingTable = y.weddingTable) AND (x.tableSeat = y. tableSeat);

Solution 4 - Sql

It sounds like you want to list all the metrics?

SELECT Criteria1, Criteria2, Metric1 As Metric
FROM Table1
UNION ALL
SELECT Criteria1, Criteria2, Metric2 As Metric
FROM Table2
ORDER BY 1, 2

If you only want one Criteria1+Criteria2 combination, group them:

SELECT Criteria1, Criteia2, SUM(Metric) AS Metric
FROM (
    SELECT Criteria1, Criteria2, Metric1 As Metric
    FROM Table1
    UNION ALL
    SELECT Criteria1, Criteria2, Metric2 As Metric
    FROM Table2
)
ORDER BY Criteria1, Criteria2

Solution 5 - Sql

First, I would suggest being more explicit with referencing column names. Since WeddingTable and TableSeat appear as column names in both tables and depending on your environment, there may be ambiguity.

Select One.WeddingTable, One.TableSeat, TableSeatID, Name, Two.Meal
FROM table1 as One
inner join table2 as Two
on One.WeddingTable = Two.WeddingTable and One.TableSeat = Two.TableSeat

Once I resolve this ambiguity in my environment, the INNER JOIN returns 4 records for the data listed in your tables. There are 4 records that match between the two tables.

From the sample provided, I fail to see why you are only obtaining one combination. The only other possibility I can think of is if the values in the WeddingTable and TableSeat columns of your actual data tables, in fact, do not match.

For example, assuming TableSeat is CHAR type and table1.TableSeat contains ('001', '002', '003', '001') and table2.TableSeat contains ('01', '002', '3', '01'), then this would be a situation where it would limit to one match due to the TableSeat component of the ON predicate.


Other considerations are for when there is data in one table that has no match in the other.

Anom's response uses a LEFT OUTER JOIN. This returns all records from table1 regardless of whether there is a match in table2. Where there is no match, the Meal column will contain a NULL value. Since all records match, the result is the same as the INNER JOIN.

However, adding a record to table1 for which there is no match in table2

INSERT INTO 
  table1 (WeddingTable, TableSeat, TableSeatID, Name)
VALUES
  (003, 002, 003002, 'Arielle');

the LEFT OUTER JOIN query will now produce a different result than the INNER JOIN.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiontarheelView Question on Stackoverflow
Solution 1 - SqlAnomView Answer on Stackoverflow
Solution 2 - SqlJohn WooView Answer on Stackoverflow
Solution 3 - Sqluser3499666View Answer on Stackoverflow
Solution 4 - SqlChris LattaView Answer on Stackoverflow
Solution 5 - SqlSteve BView Answer on Stackoverflow