MySQL LEFT JOIN with SUM before a date and SUM before and at that date

Posted

技术标签:

【中文标题】MySQL LEFT JOIN with SUM before a date and SUM before and at that date【英文标题】: 【发布时间】:2017-12-07 17:04:41 【问题描述】:

我有三张桌子(pagu、realisasi 和 perencanaan)。我正在使用左连接。我想在某个日期之前对一个字段求​​和,而在该日期之前和那个日期对另一个字段求​​和。

我的帕古桌:

idpagu  kode    komponen    pagu    target_kinerja  tahun   keterangan
1   2217.057.056    Pengembangan Sistem Manajemen Mutu UPTP     52740000    1   2017    tes123
2   2220.051.051    Pelatihan Peningkatan Produktivitas     4732755000  120     2017    tes123
3   2220.052.051    Calon Wirausaha Baru yang Dilatih (RM)  12464938000     240     2017    TES123

我的现实表:

idrealisasi     idpagu  kode    komponen    realisasi   target_kinerja  tgl     keterangan
5   1   2217.057.056    Pengembangan Sistem Manajemen Mutu UPTP     52740000    1   1/14/2017   tes
6   2   2220.051.051    Pelatihan Peningkatan Produktivitas     10000000    10  1/14/2017   tes
7   2   2220.051.051    Pelatihan Peningkatan Produktivitas     20000000    20  2/14/2017   tes2
8   2   2220.051.051    Pelatihan Peningkatan Produktivitas     10000000    10  3/14/2017   tes3
9   2   2220.051.051    Pelatihan Peningkatan Produktivitas     10000000    10  6/14/2017   tes4
10  2   2220.051.051    Pelatihan Peningkatan Produktivitas     10000000    10  1/15/2017   tes

我的 perencanaan 表(无记录):

idperencanaan   idpagu  kode    komponen    penarikan   target_kinerja  tgl     keterangan

我的查询:

select p.idpagu,p.kode,p.komponen,p.pagu,p.target_kinerja,
if(pr.penarikan is null,0,sum(pr.penarikan)) as perenuang,
if(pr.target_kinerja is null,0,sum(pr.target_kinerja)) as perenfis,
if(r.realisasi is null,0,sum(r.realisasi)) as realuang,
if(r.target_kinerja is null,0,sum(r.target_kinerja)) as realfis,
p.pagu-if(r.realisasi is null,0,sum(r.realisasi)) as sisauang,
p.target_kinerja-if(r.target_kinerja is null,0,sum(r.target_kinerja)) as sisafis,
if(sum(rr.realisasi) is null,0,sum(rr.realisasi)) as tes
from pagu p 
left join realisasi r on p.idpagu=r.idpagu and r.tgl BETWEEN "2017-01-01" and "2017-01-15"
left join perencanaan pr on p.idpagu=pr.idpagu and r.tgl BETWEEN "2017-01-01" and "2017-01-15"
left join realisasi rr on p.idpagu=rr.idpagu and rr.tgl < "2017-01-15"
group by p.idpagu,r.idpagu,rr.idpagu

我的结果:

idpagu  kode    komponen    pagu    target_kinerja  perenuang   perenfis    realuang    realfis     sisauang    sisafis     tes
1   2217.057.056    Pengembangan Sistem Manajemen Mutu UPTP     52740000    1   0   0   52740000    1   0   0   52740000
2   2220.051.051    Pelatihan Peningkatan Produktivitas     4732755000  120     0   0   20000000    20  4712755000  100     20000000
3   2220.052.051    Calon Wirausaha Baru yang Dilatih (RM)  12464938000     240     0   0   0   0   12464938000     240     0

我的问题:

tes 列在当前日期“2017-01-15”之前是 pagu - realuang,第二行应该是 10.000.000,但我的查询给出了 20.000.000。 如何编写查询,以便在第二条记录中 tes 列是 10.000.000?

我的架构:

SET FOREIGN_KEY_CHECKS=0;

DROP TABLE IF EXISTS `pagu`;
CREATE TABLE `pagu` (
  `idpagu` int(11) NOT NULL AUTO_INCREMENT,
  `kode` varchar(45) NOT NULL,
  `komponen` varchar(250) NOT NULL,
  `pagu` bigint(20) NOT NULL,
  `target_kinerja` int(11) NOT NULL,
  `tahun` varchar(4) NOT NULL,
  `keterangan` varchar(250) DEFAULT NULL,
  PRIMARY KEY (`idpagu`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

INSERT INTO `pagu` VALUES ('1', '2217.057.056', 'Pengembangan Sistem Manajemen Mutu UPTP', '52740000', '1', '2017', 'tes123');
INSERT INTO `pagu` VALUES ('2', '2220.051.051', 'Pelatihan Peningkatan Produktivitas', '4732755000', '120', '2017', 'tes123');
INSERT INTO `pagu` VALUES ('3', '2220.052.051', 'Calon Wirausaha Baru yang Dilatih (RM)', '12464938000', '240', '2017', 'TES123');

DROP TABLE IF EXISTS `perencanaan`;
CREATE TABLE `perencanaan` (
  `idperencanaan` int(11) NOT NULL AUTO_INCREMENT,
  `idpagu` int(11) NOT NULL,
  `kode` varchar(45) NOT NULL,
  `komponen` varchar(250) NOT NULL,
  `penarikan` bigint(20) NOT NULL,
  `target_kinerja` int(11) NOT NULL,
  `tgl` date NOT NULL,
  `keterangan` varchar(250) DEFAULT NULL,
  PRIMARY KEY (`idperencanaan`),
  KEY `fk_perencanaan_pagu1_idx` (`idpagu`),
  CONSTRAINT `fk_perencanaan_pagu1` FOREIGN KEY (`idpagu`) REFERENCES `pagu` (`idpagu`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `realisasi`;
CREATE TABLE `realisasi` (
  `idrealisasi` int(11) NOT NULL AUTO_INCREMENT,
  `idpagu` int(11) NOT NULL,
  `kode` varchar(45) NOT NULL,
  `komponen` varchar(250) NOT NULL,
  `realisasi` bigint(20) NOT NULL,
  `target_kinerja` int(11) NOT NULL,
  `tgl` date NOT NULL,
  `keterangan` varchar(250) DEFAULT NULL,
  PRIMARY KEY (`idrealisasi`),
  KEY `fk_perencanaan_pagu1_idx` (`idpagu`),
  CONSTRAINT `fk_perencanaan_pagu10` FOREIGN KEY (`idpagu`) REFERENCES `pagu` (`idpagu`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

INSERT INTO `realisasi` VALUES ('5', '1', '2217.057.056', 'Pengembangan Sistem Manajemen Mutu UPTP', '52740000', '1', '2017-01-14', 'tes');
INSERT INTO `realisasi` VALUES ('6', '2', '2220.051.051', 'Pelatihan Peningkatan Produktivitas', '10000000', '10', '2017-01-14', 'tes');
INSERT INTO `realisasi` VALUES ('7', '2', '2220.051.051', 'Pelatihan Peningkatan Produktivitas', '20000000', '20', '2017-02-14', 'tes2');
INSERT INTO `realisasi` VALUES ('8', '2', '2220.051.051', 'Pelatihan Peningkatan Produktivitas', '10000000', '10', '2017-03-14', 'tes3');
INSERT INTO `realisasi` VALUES ('9', '2', '2220.051.051', 'Pelatihan Peningkatan Produktivitas', '10000000', '10', '2017-06-14', 'tes4');
INSERT INTO `realisasi` VALUES ('10', '2', '2220.051.051', 'Pelatihan Peningkatan Produktivitas', '10000000', '10', '2017-01-15', 'tes');

【问题讨论】:

感谢您的快速回复@philipxy。您之前的总和是正确的,并且在某个日期总和。我添加了架构和代码片段(我的表很长),所以用户可以复制粘贴它。 感谢您的编辑。请:不要使用链接。不要使用图像。即使是 ER 图,也要以文本形式提供信息。如果您的问题不是 php/html/javascript,请不要使用 sn-ps。将您的代码编辑为“代码块”。 (缩进 4 个空格或单击“”。)转到 sqlfiddle.com。 (没有其他语言的固定站点。)查询以显示您的表值。运行您的查询。将 sqlfiddle 链接编辑到您的问题中。您还可以在代码块中包含使用对齐列重新格式化的 sqlfiddle 输出;或者您可以将代码的 INSERT VALUES 格式化为对齐列。 (对齐 = 人类可读。) 请不要保留旧的不清楚的文字;编辑您的问题以明确。你所有的原文都不清楚。在我上一条评论中,我猜想两个部分说的是同一件事;但我不知道那是什么。我也无法理解你的新描述。用小步骤说事情。此外,您仍然只是通过示例描述您想要的内容。但举个什么例子?试着告诉我们一行在表格中时的含义。再举例:请阅读minimal reproducible example。你的 desired 输出表是什么?也许使用一个更简单/经过编辑的示例来显示您的问题/需求。 我猜你的意思是 tes = pagu - ("sisauang before the current date") = pagu - (pagu - ("realuang before the current date")),即 tes = "realuang before the current日期”?不幸的是,这仍然只是单词沙拉。您的意思是给定 pagu 和(当前)日期的 tes 是该日期前几天该 pagu 的 realisasi 值的总和。如果你强迫自己去写/写你真正的意思,你就会开始清楚地思考/写。 PS您提供的原始文本查询与您提供的链接中的文本不同。我已将其从链接复制到您的问题中。 【参考方案1】:

根据您的查询和表名和列名(pagu = 上限、realisasi = 实际、perencanaan = 计划)猜测,对于每个上限,您将在特定范围内的天数的实际值、那些天的计划值、其那些日子的实际值,以及一些相关的目标值,将 NULL 值视为 0。

我假设如果上限在某个日期具有实际值,那么它在该日期具有计划值。否则,您的查询将涉及 FULL JOIN,而 LEFT JOIN 有时会错误地形成具有不同日期的行等。所以我怀疑您缺少 FK(外键)。

您的第一个 LEFT JOIN 获取某些日期每个上限的实际值。然后,您需要 上限和日期 的任何计划值。所以你错过了and r.tgl = pr.tgl。然后,您需要其中一些日期的 ceiling & date 的任何实际值。所以你的第三个 LEFT JOIN 丢失了and r.tgl = rr.tgl

您的分组和求和不正确。如果 SELECT 使用聚合调用之外的列,那么对于 GROUPed 列的每个子行,它应该是单值的。 (GROUP BY 为 GROUPed 列的每个子行返回一行。)(SET sql_mode = 'ONLY_FULL_GROUP_BY' 不允许 mysql 的非标准行为。)

select p.idpagu, count(*), p.pagu, p.target_kinerja,
    sum(coalesce(pr.penarikan,0)) as pr_penarikan,
    sum(coalesce(pr.target_kinerja,0)) as pr_target_kinerja,
    sum(coalesce(r.realisasi,0)) as r_realisasi,
    sum(coalesce(r.target_kinerja,0)) as r_target_kinerja,
    p.pagu-sum(coalesce(r.realisasi,0)) as d_realisasi,
    p.target_kinerja-sum(coalesce(r.target_kinerja,0)) as d_target_kinerja,
    sum(coalesce(rr.realisasi,0)) as rr_realisasi
from pagu p
left join realisasi r on p.idpagu=r.idpagu and r.tgl BETWEEN "2017-01-01" and "2017-01-15"
left join perencanaan pr on p.idpagu=pr.idpagu and r.tgl = pr.tgl and r.tgl BETWEEN "2017-01-01" and "2017-01-15"
left join realisasi rr on p.idpagu=rr.idpagu and r.tgl = rr.tgl and r.tgl < "2017-01-15"
group by p.idpagu, p.pagu, p.target_kinerja;

idpagu  pagu                    pr_penarikan    r_realisasi     d_realisasi             rr_target_kinerja 
    count(*)        target_kinerja  pr_target_kinerja       r_target_kinerja    d_target_kinerja    
1   1   52740000    1           0   0           52740000    1   0               0       52740000
2   2   4732755000  120         0   0           20000000    20  4712755000      100     10000000
3   1   12464938000 240         0   0           0           0   12464938000     240     0

【讨论】:

以上是关于MySQL LEFT JOIN with SUM before a date and SUM before and at that date的主要内容,如果未能解决你的问题,请参考以下文章