简体   繁体   中英

Forcing SQL result to to fill in missing values

I have a table similar to the one below:

timeUnit    country    name    count
    1          UK      Fred     12
    1          GE      Bob      1
    1          GE      John     3
    2          UK      Fred     6
    2          GE      Bob      5
    2          GE      John     8
    3          UK      Fred     4
    3          GE      Bob      6
    3          GE      John     5
    4          UK      Fred     4
    4          GE      Bob      8
    4          GE      John     9
    4          UK      Philip   6
    5          UK      Fred     3
    5          GE      Bob      2
    5          GE      John     1
    5          UK      Philip   5
    6          UK      Fred     8
    6          GE      Bob      9
    7          UK      Fred     8
    7          GE      Bob      9
    7          GE      John     8
    7          UK      Philip   6
    8          UK      Fred     5
    8          GE      Bob      1
    8          GE      John     1

What I want to do is the equivalent of:

SELECT * FROM table1 WHERE country ='UK'

But have the result include missing timeUnit results for Philip with counts of zero, ie return:

timeUnit    country    name    count
   1           UK      Fred      12
   1           UK      Philip    0
   2           UK      Fred      6
   2           UK      Philip    0
   3           UK      Fred      4
   3           UK      Philip    0
etc...

I have a feeling this should be possible with some form of join on a temp table or query but really struggling to get my head around it.

Thanks for any help.

If the name coluimn is the only source of names, you can perform a subquery to get all the distinct names from the table and then LEFT JOIN the results of the subquery to the main table, using aggregation to get the values you are looking for.

SELECT
    t.timeUnit AS timeUnit,
    t.country AS country,
    names.name AS name,
    SUM(t.`count`) AS `count`
FROM (
    SELECT DISTINCT name FROM table1
) AS names
LEFT JOIN table1 AS t
    ON names.name = t.name
WHERE country = ?
GROUP BY timeUnit, name

Assuming that timeUnit , name values are comprehensively included in your table, you can use a query like the following:

SELECT t1.timeUnit, 
       COALESCE(t3.country, 'UK') AS country, 
       t2.name,  
       COALESCE(SUM(count), 0) AS count
FROM (
   SELECT DISTINCT timeUnit
   FROM Table1) AS t1
CROSS JOIN (
   SELECT DISTINCT name
   FROM Table1
   WHERE country = 'UK') AS t2
LEFT JOIN (
   SELECT timeUnit, country, name, count
   FROM Table1
   WHERE country = 'UK'
) AS t3 ON t1.timeUnit = t3.timeUnit AND t2.name = t3.name
GROUP BY t1.timeUnit, t3.country, t2.name
ORDER BY t1.timeUnit, t2.name

CROSS JOIN is used to create an in-line table containing all possible ( timeUnit , name ) pairs for the case where country = 'UK' . Performing a LEFT JOIN to this table gives a result set containing all possible ( timeUnit , name ) pairs along with the corresponding count.

Demo here

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