SQL Server Returning values from three tables in different lines

cl25kdpy  于 2023-02-18  发布在  其他
关注(0)|答案(2)|浏览(146)

I have three tables:

Table_1 - Main, where Global_ID is the primary key used in all tables.
| Global_ID |
| ------------ |
| 001 |

Table_2 - Using Global_ID to query for F_ID values

Global_IDF_ID
0011111
001222222
00133333

Table_3 - Using Global_ID to query for F_ID values

Global_IDF_ID
001444444

So, I need to do a query that returns The Global_ID and the values that are both equal and different in Table_2 and Table_3.

  • If Table_2 and Table_3 have the same values, they need to be show in the same line.
  • If Table_2 and Table_3 have different values, they need to be show in a new line Like this:
    | Global ID | T2_F_ID | T3_F_ID |
    | ------------ | ------------ | ------------ |
    | 001 | 1111 | - |
    | 001 | 222222 | - |
    | 001 | 33333 | - |
    | 001 | - | 444444 |

The way I am doing (case) is returning like this

Global IDT2_F_IDT3_F_ID
0011111-
001222222-
00133333-

This return is due to this query that I have poorly done

SELECT
   DISTINCT T1.*    "Global_ID",
   ISNULL(CONVERT(VARCHAR,T2.F_ID),'-')    "T2_F_ID",
   CASE WHEN T2.F_ID IS NULL AND T3.F_ID IS NOT NULL THEN CONVERT(VARCHAR,T3.F_ID)
        WHEN T2.F_ID IS NULL AND T3.F_ID IS NULL THEN '-'
        WHEN T2.F_ID = T3.F_ID THEN T3.F_ID
        WHEN T2.F_ID <> T3.F_ID THEN '-'
   END    "T3_F_ID"
FROM T1 
LEFT JOIN T2 ON T2.Global_ID = T1.Global_ID
LEFT JOIN T3 ON T3.GLOBAL_ID = T1.Global_ID

This way I know there is some logic issues and that if Table_2 returns even 1 value, the values that are not the same in Table_3 will not be returned but I can't find out what to do and I am stuck...

Some other returns that might happen:

  • When there might be the same F_ID in Table_2 and Table_3, but also when the F_ID is not fouind in one of the tables.
    | Global ID | T2_F_ID | T3_F_ID |
    | ------------ | ------------ | ------------ |
    | 001 | 1111 | 1111 |
    | 001 | 222222 | - |
    | 001 | 33333 | - |
    | 001 | - | 444444 |

  • When there are no F_ID in Table_2 and only in Table_3
    | Global ID | T2_F_ID | T3_F_ID |
    | ------------ | ------------ | ------------ |
    | 001 | - | 444444 |

  • When there are not the same F_ID in Table_3 and only in Table_2
    | Global ID | T2_F_ID | T3_F_ID |
    | ------------ | ------------ | ------------ |
    | 001 | 1111 | - |
    | 001 | 222222 | - |
    | 001 | 33333 | - |

  • When there are no values in Table_2 and Table_3
    | Global ID | T2_F_ID | T3_F_ID |
    | ------------ | ------------ | ------------ |
    | 001 | - | - |

  • When all values in Table_2 were found in Table_3
    | Global ID | T2_F_ID | T3_F_ID |
    | ------------ | ------------ | ------------ |
    | 001 | 1111 | 1111 |
    | 001 | 222222 | 222222 |
    | 001 | 33333 | 33333 |
    | 001 | 444444 | 444444 |

Another example with more Global_IDs:

Global IDT2_F_IDT3_F_ID
00111111111
001222222-
0013333333333
001444444444444
0021234-
00256785678
0033333333333
00312121212
003-1111
004--
0053333333333
005444444444444
005-1111
005-222222
005-33333

Please help.

9rygscc1

9rygscc11#

You can union 2 queries together to obtain the results you want.

create table Table_1 (Global_ID int);
create table Table_2 (Global_ID int, F_ID int);
create table Table_3 (Global_ID int, F_ID int);

insert into Table_1 (Global_ID) values (1);
insert into Table_2 (Global_ID, F_ID) values (1,1111),(1,22222), (1,33333);
insert into Table_3 (Global_ID, F_ID) values (1,1111),(1,44444);

select t1.Global_Id, t2.F_ID T2_F_ID, t3.F_ID T3_F_ID
from Table_1 t1
left join Table_2 t2 on t2.Global_ID = t1.Global_ID
left join Table_3 t3 on t3.Global_ID = t1.Global_ID and t2.F_ID = t3.F_ID

union all
  
select t1.Global_Id, null, t3.F_ID
from Table_1 t1
inner join Table_3 t3 on t3.Global_ID = t1.Global_ID
-- Exclude because already handled in the first part of the union
where not exists (
  select 1
  from Table_2 t2
  where t2.Global_ID = t1.Global_ID
  and t2.F_ID = t3.F_ID
)

Returns:

Global_IdT2_F_IDT3_F_ID
111111111
122222null
133333null
1null44444

DBFiddle

Note: Providing the DDL+DML as shown here makes it much easier to assist.

bprjcwpo

bprjcwpo2#

Here is a solution that uses a FULL OUTER JOIN to join the two data tables (Table_2 and Table_3). That join (grouped using parentheses) is then joined back with the ID table (Table_1).

Note the the parentheses after the LEFT JOIN causes the outer join between the Table_2 and Table_3 to be evaluated first. This is not a subselect.

SELECT T1.Global_Id, T2.F_ID AS T2_F_ID, T3.F_ID AS T3_F_ID
FROM Table_1 T1
LEFT JOIN (
    Table_2 T2
    FULL OUTER JOIN Table_3 T3
        ON T3.Global_ID = T2.Global_ID
        AND T3.F_ID = T2.F_ID
)
    ON COALESCE(T2.Global_ID, T3.Global_ID) = T1.Global_ID
ORDER BY
    T1.Global_Id,
    COALESCE(T2.F_ID, T3.F_ID)

The problem with the above is that it doesn't properly handle duplicate values such as those that are present for Global_ID = 005. To handle duplicates, we need to assign distinct row values and add that to our logic. This can be done with some Common Table Expressions (CTEs) and a ROW_NUMBER() window function.

;WITH Table_2N AS (
     SELECT *,
         ROW_NUMBER() OVER(PARTITION BY Global_ID, F_ID ORDER BY (SELECT NULL)) AS RowNum
     FROM Table_2
),
Table_3N AS (
     SELECT *,
         ROW_NUMBER() OVER(PARTITION BY Global_ID, F_ID ORDER BY (SELECT NULL)) AS RowNum
     FROM Table_3
)
SELECT T1.Global_Id, T2.F_ID AS T2_F_ID, T3.F_ID AS T3_F_ID
FROM Table_1 T1
LEFT JOIN (
    Table_2N T2
    FULL OUTER JOIN Table_3N T3
        ON T3.Global_ID = T2.Global_ID
        AND T3.F_ID = T2.F_ID
        AND T3.RowNum = T2.RowNum
)
    ON COALESCE(T2.Global_ID, T3.Global_ID) = T1.Global_ID
ORDER BY
    T1.Global_Id,
    COALESCE(T2.F_ID, T3.F_ID),
    COALESCE(T2.RowNum, T3.RowNum)

The ORDER BY (SELECT NULL) is just a don't care placeholder to satisfy the required syntax.

Results:
| Global_Id | T2_F_ID | T3_F_ID |
| ------------ | ------------ | ------------ |
| 001 | 1111 | 1111 |
| 001 | 222222 | null |
| 001 | 33333 | 33333 |
| 001 | 444444 | 444444 |
| 002 | 1234 | null |
| 002 | 5678 | 5678 |
| 003 | null | 1111 |
| 003 | 1212 | 1212 |
| 003 | 33333 | 33333 |
| 004 | null | null |
| 005 | null | 1111 |
| 005 | null | 222222 |
| 005 | 33333 | 33333 |
| 005 | null | 33333 |
| 005 | 444444 | 444444 |

See this db<>fiddle .

It is worth noting that the table joins could also be rearranged and rewritten as:

FROM Table_2N T2
FULL OUTER JOIN Table_3N T3
    ON T3.Global_ID = T2.Global_ID
    AND T3.F_ID = T2.F_ID
    AND T3.RowNum = T2.RowNum
RIGHT JOIN Table_1 T1
    ON T1.Global_ID = COALESCE(T2.Global_ID, T3.Global_ID)

The results are identical. Which is more readable and best conveys intent is subjective.

相关问题