Mysql 如果没有第二个连接到第一个连接,如何将第一个连接的筛选器列表中的值添加到第一个连接的结果中,以及添加的行值中?

Mysql 如果没有第二个连接到第一个连接,如何将第一个连接的筛选器列表中的值添加到第一个连接的结果中,以及添加的行值中?,mysql,join,set,union,Mysql,Join,Set,Union,导言 标题尽可能通用,以扩大受众范围,问题尽可能针对我的问题,尽可能与我的问题相同,这样我可以获得最大的受众覆盖率,但可以获得具体的解决方案 摘要 我缺少了应该显示在所需查询中但没有显示的记录,因为它们不存在于联接的一个表中。我想在不使用第二次联接的情况下完成对丢失记录的添加。下面是我的问题,以及一个最小的完整的可验证示例,得到了预期的结果。详情见下文 问题 如何从联接查询的结果中选择两列,然后使用where子句显示来自联接的结果并显示不匹配的行 从现场 我的in子句中有一列的 不在片场 以尽可

导言

标题尽可能通用,以扩大受众范围,问题尽可能针对我的问题,尽可能与我的问题相同,这样我可以获得最大的受众覆盖率,但可以获得具体的解决方案

摘要

我缺少了应该显示在所需查询中但没有显示的记录,因为它们不存在于联接的一个表中。我想在不使用第二次联接的情况下完成对丢失记录的添加。下面是我的问题,以及一个最小的完整的可验证示例,得到了预期的结果。详情见下文

问题

如何从联接查询的结果中选择两列,然后使用where子句显示来自联接的结果并显示不匹配的行

从现场

我的in子句中有一列的

不在片场

以尽可能最具时间效率的方式

我想要什么?10行

columna columnb     columnc

val01   (null)      (null)
val02   2020-01-01  2020-01-01
val03   2020-01-01  2020-01-01
val04   2020-01-01  2020-01-01
val05   2020-01-01  2020-01-01
val06   2020-01-01  2020-01-01
val07   2020-01-01  2020-01-01
val08   2020-01-01  2020-01-01
val09   2020-01-01  2020-01-01
val10   2020-01-01  2020-01-01

num rows returned: 10
我得到了什么?9行-从10行预期中减去一行

columna columnb     columnc
val02   2020-01-01  2020-01-01
val03   2020-01-01  2020-01-01
val04   2020-01-01  2020-01-01
val05   2020-01-01  2020-01-01
val06   2020-01-01  2020-01-01
val07   2020-01-01  2020-01-01
val08   2020-01-01  2020-01-01
val09   2020-01-01  2020-01-01
val10   2020-01-01  2020-01-01

num rows returned: 9
我试过什么?

我尝试过联合(下面没有显示,但如果需要,可以添加到问题细节中),从而得到比需要多得多的记录。但从分析上看,主要问题在于我在join上滥用了过滤器,其中不包括columnA上丢失的记录

模式

CREATE TABLE IF NOT EXISTS `tableb` (
  `col1` char NOT NULL,
  `columna` char(5) NOT NULL,
  `columnb` date,
  `columnc` date
) DEFAULT CHARSET=utf8;
INSERT INTO `tableb` (`col1`, `columna`, `columnb`, `columnc`) VALUES
  ('a', 'val01', '2020-01-01', '2020-01-01'),
  ('b', 'val02', '2020-01-01', '2020-01-01'),
  ('c', 'val03', '2020-01-01', '2020-01-01'),
  ('d', 'val04', '2020-01-01', '2020-01-01'),
  ('e', 'val05', '2020-01-01', '2020-01-01'),
  ('f', 'val06', '2020-01-01', '2020-01-01'),
  ('g', 'val07', '2020-01-01', '2020-01-01'),
  ('h', 'val08', '2020-01-01', '2020-01-01'),
  ('i', 'val09', '2020-01-01', '2020-01-01'),
  ('j', 'val10', '2020-01-01', '2020-01-01');
  
  
  
CREATE TABLE IF NOT EXISTS `tablea` (
  `col1` char(2) NOT NULL
) DEFAULT CHARSET=utf8;
INSERT INTO `tablea` (`col1`) VALUES
  ('b'),
  ('c'),
  ('d'),
  ('e'),
  ('f'),
  ('g'),
  ('h'),
  ('i'),
  ('j');
预期结果查询:

select desired.columna, desired.columnb, desired.columnc from 
        (select * from (select 'val01' as columna, null as columnb, null as columnc) `t1` union
         select * from (select 'val02' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t2` union
         select * from (select 'val03' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t3` union
         select * from (select 'val04' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t4` union
         select * from (select 'val05' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t5` union
         select * from (select 'val06' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t6` union
         select * from (select 'val07' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t7` union
         select * from (select 'val08' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t8` union
         select * from (select 'val09' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t9` union
         select * from (select 'val10' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t10`) desired;
 #Actual Result

/*Goal: Basically, alongside the join results, I want to 
                                               also display the rows from the set of the NOT IN clause based upon 
                                               the column, that are not in the result set of the 
                                               join, which would show columnb, columnc as null*/
SELECT   columna, 
         columnb, 
         columnc 
FROM     tablea a, tableb b   # inner join
WHERE    a.col1 = b.col1      # on a.col1 = b.col1  
AND      b.columna  IN ('val01', 'val02', 'val03', 'val04', 'val05', 'val06', 'val07', 'val08', 'val09', 'val10')   
                                             /* 
                                               Presently: Using IN returns 9 rows in this query
                                             */
UNION
SELECT   columna, 
         columnb, 
         columnc 
FROM     tablea a, tableb b   # inner join
WHERE    a.col1 = b.col1      # on a.col1 = b.col1
AND      b.columna NOT IN ('val01', 'val02', 'val03', 'val04', 'val05', 'val06', 'val07', 'val08', 'val09', 'val10')   
                                             /* 
                                               Presently: Using NOT IN returns 0 rows in this query because my 
                                               join is returning result of that join 
                                               BUT not adding the values not present in the join from the "not in" 
                                               set to the set of results.
                                             */
GROUP BY b.columna ,find_in_set("b.columna", "val01, val02, val03, val04, val05, val06, val07, val08, val09, val10")    # find_in_set is here to adhere to original order of a.col1
实际查询:

select desired.columna, desired.columnb, desired.columnc from 
        (select * from (select 'val01' as columna, null as columnb, null as columnc) `t1` union
         select * from (select 'val02' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t2` union
         select * from (select 'val03' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t3` union
         select * from (select 'val04' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t4` union
         select * from (select 'val05' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t5` union
         select * from (select 'val06' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t6` union
         select * from (select 'val07' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t7` union
         select * from (select 'val08' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t8` union
         select * from (select 'val09' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t9` union
         select * from (select 'val10' as columna, '2020-01-01' as columnb, '2020-01-01' as columnc) `t10`) desired;
 #Actual Result

/*Goal: Basically, alongside the join results, I want to 
                                               also display the rows from the set of the NOT IN clause based upon 
                                               the column, that are not in the result set of the 
                                               join, which would show columnb, columnc as null*/
SELECT   columna, 
         columnb, 
         columnc 
FROM     tablea a, tableb b   # inner join
WHERE    a.col1 = b.col1      # on a.col1 = b.col1  
AND      b.columna  IN ('val01', 'val02', 'val03', 'val04', 'val05', 'val06', 'val07', 'val08', 'val09', 'val10')   
                                             /* 
                                               Presently: Using IN returns 9 rows in this query
                                             */
UNION
SELECT   columna, 
         columnb, 
         columnc 
FROM     tablea a, tableb b   # inner join
WHERE    a.col1 = b.col1      # on a.col1 = b.col1
AND      b.columna NOT IN ('val01', 'val02', 'val03', 'val04', 'val05', 'val06', 'val07', 'val08', 'val09', 'val10')   
                                             /* 
                                               Presently: Using NOT IN returns 0 rows in this query because my 
                                               join is returning result of that join 
                                               BUT not adding the values not present in the join from the "not in" 
                                               set to the set of results.
                                             */
GROUP BY b.columna ,find_in_set("b.columna", "val01, val02, val03, val04, val05, val06, val07, val08, val09, val10")    # find_in_set is here to adhere to original order of a.col1
SQL小提琴

使用
左连接和
中的条件选择
列表:

SELECT tb.columnA, 
     IF(ta.col1 IS NULL, NULL, tb.columnb) AS columnb, 
     IF(ta.col1 IS NULL, NULL, tb.columnc) AS columnc
FROM tableb tb
LEFT JOIN tablea ta
  ON tb.col1 = ta.col1;

使用
CASE
表达式(更通用):


如果我们要连接的列是唯一的,则可以使用double
LEFT JOIN

SELECT tb.columnA, 
       tb2.columnb, 
       tb2.columnc
FROM tableb tb
LEFT JOIN tablea ta
  ON tb.col1 = ta.col1
LEFT JOIN tableb tb2
  ON ta.col1 = tb2.col1;


编辑:

你能帮我回答一下,除了加入,还有什么其他的方法可以完成这个任务吗

使用相关子查询:

SELECT tb.columnA, 
     CASE WHEN EXISTS (SELECT 1 FROM tablea ta WHERE tb.col1 = ta.col1)
          THEN tb.columnb 
     END AS columnb, 
     CASE WHEN EXISTS (SELECT 1 FROM tablea ta WHERE tb.col1 = ta.col1)
         THEN tb.columnc 
     END AS columnc
FROM tableb tb

横向连接
,但与常规
左侧连接
相比没有真正的优势:

SELECT tb.columnA, 
     CASE WHEN s.c IS NOT NULL THEN tb.columnb END AS columnb, 
     CASE WHEN s.c IS NOT NULL THEN tb.columnc END AS columnc
FROM tableb tb
LEFT JOIN LATERAL (SELECT 1 c FROM tablea ta WHERE tb.col1 = ta.col1 LIMIT 1) s ON TRUE

并使用互斥的
联合所有

SELECT tb.columnA, 
       tb.columnB,
       tb.columnC
FROM tableb tb
WHERE EXISTS (SELECT 1 FROM tablea ta WHERE ta.col1 = tb.col1)
UNION ALL
SELECT tb.columnA, 
       NULL AS columnB,
       NULL AS columnC
FROM tableb tb
WHERE NOT EXISTS (SELECT 1 FROM tablea ta WHERE ta.col1 = tb.col1)

方法如下:@草莓,感谢您的帮助提醒,在这种情况下,MCRE是非常必要的,以便更清楚地了解当前问题,避免任何语法错误,或回答者不必要的努力。请参阅编辑的sql fiddle-fiddle是一个良好的开端,但是如果您显示了您希望的结果集,这会有所帮助。我们可以看到您开始使用的表,但是很难理解查询的预期结果。有了预期的结果,就更容易理解查询需要做什么了。我将修改fiddle以显示预期的结果,然后再授予赏金。您能否帮助回答除了连接之外是否还有其他方法来完成此任务。@VaheJabagchourian从技术上讲,您可以使用相关子查询(横向是一种连接),但它不会更快、更容易阅读。让我准备一下demo@VaheJabagchourian当然done@VaheJabagchourian这里的挑战是,您需要为希望以这种方式处理的每个列提供CASE表达式。我已经提供了最后的方法,结合了
UNION ALL
EXISTS
Lukasz,非常感谢您的努力和全面的回答。非常感谢。我有两个小时的等待时间来奖励赏金。