简体   繁体   中英

Full outer join missing values with null

I'm trying to use full outer join on postgresql database to get a union of tables that has null values for the missing rows. However, it is not working for me.

Here is the example:

create temp table nutrient_names (
    name text
);

insert into nutrient_names values
('fat'),
('sugar'),
('sodium'),
('total fat');

create temp table nutrients (
    food_id int,
    name text,
    quantity float8
);

insert into nutrients values
(1, 'fat', 0.3),
(1, 'sugar', 15),
(1, 'sodium', 10),
(1, 'total fat', 25),
(2, 'sugar', 10),
(2, 'sodium', 4);

Here is the output:

select n.name, n.food_id, n.quantity from nutrient_names nn
full outer join nutrients n
on nn.name = n.name
order by n.food_id, n.name;

+---------------------------------+
|name           |food_id |quantity|
+---------------------------------+
|    'fat'      |1       |'0.3'   |
|    'sodium'   |1       |'10'    |
|    'sugar'    |1       |'15'    |
|    'total fat'|1       |'25'    |
|    'sodium'   |2       |'4'     |
|    'sugar'    |2       |'10'    |
+---------------------------------+

What I want:

+---------------------------------+
|name           |food_id |quantity|
+---------------------------------+
|    'fat'      |1       |'0.3'   |
|    'sodium'   |1       |'10'    |
|    'sugar'    |1       |'15'    |
|    'total fat'|1       |'25'    |
|    'fat'      |2       |null    | <----
|    'sodium'   |2       |'4'     |
|    'sugar'    |2       |'10'    |
|    'total fat'|2       |null    | <----
+---------------------------------+

I suggest having two tables representing nutrition types and types of food. Then have an extra table specifying the nutrition values.

You can do a cross join on food and nutritions and then do a left join on the nutrition values to get your results.

I made a fiddle for you to look at here http://sqlfiddle.com/#!17/d974b/3

The reason that you cannot do a full outer join is that if you have the quantity on a row you have the id aswell. They are in the same dataset.

It doesn't look like FULL JOIN suits here. Based on your example you want to list all rows from nutrient_names as many times as you have food IDs. This is usually done with CROSS JOIN .

If you don't have a separate table with the list of food IDs, you can build it on the fly and then join to it:

WITH
CTE_IDs
AS
(
    SELECT DISTINCT
        food_id
    FROM nutrients
)
SELECT
    nutrient_names.name
    ,CTE_IDs.food_id
    ,nutrients.quantity
FROM
    CTE_IDs
    CROSS JOIN nutrient_names
    LEFT JOIN nutrients 
        ON  nutrients.name = nutrient_names.name
        AND nutrients.food_id = CTE_IDs.food_id
;

if you have 2 tables (t1 and t2) with cols: dimension_1, dimension_2, measure_1, measure_2

you can write

select dimension_1, dimension_2, sum(measure_1) as measure_1, sum(measure_2) as measure_2
from t1
full join t2 using(dimension_1, dimension_2)
group by dimension_1, dimension_2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM