SQL 两列完全连接

SQL Full join on two columns

我正在尝试连接两个 table,但是 emp_id 和 scheme_id 列可能为空或未填充在任一 table 中,但如果已填充在任一情况下,我都需要 return 每个计划的该员工的总数 pen_ee(下面进一步 table 描述)。我无法编辑 table 结构,必须使用现有的结构。

我一直在尝试使用完全联接来执行此操作,但不明白是否可以对两个字段 emp_id 和 scheme_id 进行完全联接以获得所需的结果。

Table PAYAUDPEN
这是一年的前两个月。
- 员工 A 已将 44.06 捐给计划 BMAL。
- 员工 B 已将 98.06 捐给计划 BMAL。
- 员工 B 已将 98.06 捐给计划 CLFL。

emp_id, period_id, scheme_id, pen_ee
A,      201601,         BMAL, 22.03
A,      201602,         BMAL, 22.03
B,      201601,         BMAL, 98.06
B,      201602,         CLFL, 98.06

Table PAYISPEN
这是一年中的第三个月和当前月份。系统总是把当前月份放入这个table)
- 员工 A 给出了 22.03.
- 员工 B 给出了 98.06.
(请注意,员工 B 在第 3 个月没有再次向 BMAL 计划供款,这是问题的一部分)。

emp_id, scheme_id, pen_ee
A, BMAL, 22.03
B, CLFL, 98.06

要求的结果 SQL 声明需要 return 将 3 个时期加在一起,对于每个员工他们贡献的每个计划。
- 对于方案 BMAL,员工 A 为 44.06 + 22.03=66.09。
- 对于方案 BMAL,员工 B 将为 98.06 + NULL =98.06。
- 对于方案 CLFL,员工 B 为 98.06 + 98.06=196.12。

A, BMAL, 66.09  
B, BMAL, 98.06
B, CLFL, 196.12

创建两个 table 的基础知识并使用上面的示例数据填充 运行 以下查询。

CREATE TABLE [dbo].[payaudpen](
[emp_id] [char](10) NOT NULL,
[period_id] [char](6) NOT NULL,
[scheme_id] [char](10) NOT NULL,
[pen_ee] [numeric](15, 2) NULL)

CREATE TABLE [dbo].[payispen](
[emp_id] [char](10) NOT NULL,
[scheme_id] [char](10) NOT NULL,
[pen_ee] [numeric](15, 2) NULL )

INSERT INTO payaudpen VALUES ('A','201601','BMAL','22.03'), ('A','201602','BMAL','22.03'), ('B','201601','BMAL','98.06'), ('B','201602','CLFL','98.06')
INSERT INTO payispen VALUES ('A','BMAL','22.03'), ('B','CLFL','98.06')

我正在使用的当前声明:

SELECT a.emp_id,
       a.scheme_id,
       SUM(a.pen_ee)+AVG(b.pen_ee)
FROM payaudpen a 
FULL JOIN payispen b 
  ON a.emp_id=b.emp_id
GROUP BY a.scheme_id, a.emp_id

结果不正确
return 每个方案的员工 B 的正确值。

A, BMAL, 66.09  
B, BMAL, 196.12
B, CLFL, 196.12

您需要在解决方案中更改的关键是使用 ISNULL() 来确保当 table b 有数据但 table a 没有数据时密钥出现。否则,您将得到如下所示的行:

空 |空 | 98.06

我推荐:

SELECT ISNULL(a.emp_id,b.emp_id) AS emp_id
       ISNULL(a.scheme_id, b.scheme_id) AS scheme_id
       SUM(a.pen_ee)+AVG(b.pen_ee) AS pen_ee
FROM payaudpen a 
FULL JOIN payispen b 
  ON a.emp_id=b.emp_id
  AND a.scheme_id=b.scheme_id
WHERE a.emp_id in ('A','B') 
      and period_id in ('201601','201602')
GROUP BY ISNULL(a.emp_id,b.emp_id), ISNULL(a.scheme_id, b.scheme_id)

显然您只想连接具有相同 emp_id 相同 scheme_id 的行。这在外连接中是可能的,就像在内连接中一样。我推断您还想合并两个 table 中的 emp_idscheme_id 列,以便当 a 不提供它们时,它们来自 b, 反而。这将做到:

SELECT
  COALESCE(a.emp_id, b.emp_id) AS emp_id,
  COALESCE(a.scheme_id, b.scheme_id) AS scheme_id,
  SUM(a.pen_ee)+AVG(b.pen_ee) AS pen_ee
FROM
  payaudpen a 
  FULL JOIN payispen b 
    ON a.emp_id = b.emp_id AND a.scheme_id = b.scheme_id
WHERE
  COALESCE(a.emp_id, b.emp_id) in ('A','B') 
    AND (a.period_id IS NULL OR a.period_id in ('201601','201602'))
GROUP BY COALESCE(a.scheme_id, b.scheme_id), COALESCE(a.emp_id, b.emp_id)

注意使用COALESCE()来处理tablea不提供emp_idscheme_id的情况;使用 SQL 服务器,您也可以使用 ISNULL() 代替它。还要注意 WHERE 条件中 a.period_id IS NULL 的余量——这是必要的(与 COALESCE()ing 结合)以包含来自 b 行但没有对应的数据a 行。

您正在尝试对两个表求和,使用 union all 使表成为具有更多行的关系,而不是使用 join 使表成为具有更多列的关系:

WITH all_records AS (SELECT emp_id
            , scheme_id
            , pen_ee 
        FROM payispen
    UNION ALL 
    SELECT emp_id
        , scheme_id
        , pen_ee FROM payaudpen)
SELECT emp_id, scheme_id, SUM(pen_ee)
FROM all_records    
GROUP BY emp_id, scheme_id

结果:

emp_id  scheme_id   (No column name)
A           BMAL        66.09
B           BMAL        98.06
B           CLFL        196.12