需要基于另一列对一列取反,作为总和的一部分

问题描述 投票:0回答:1

我无法在会计系统中生成损益报告。

每个普通日记帐分录都有一个金额,一个源帐户和一个目标帐户。这是一个简化的模式:

CREATE TABLE `sa_general_journal` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Date` timestamp NOT NULL DEFAULT current_timestamp(),
  `Item` varchar(1024) NOT NULL DEFAULT '',
  `Amount` decimal(9,2) NOT NULL DEFAULT 0.00,
  `Source` int(10) unsigned NOT NULL,
  `Destination` int(10) unsigned NOT NULL,
  PRIMARY KEY (`ID`),
  KEY `Date` (`Date`),
  KEY `Source` (`Source`),
  KEY `Destination` (`Destination`),
  CONSTRAINT `sa_credit-account` FOREIGN KEY (`Destination`) REFERENCES `sa_accounts` (`ID`),
  CONSTRAINT `sa_debit-account` FOREIGN KEY (`Source`) REFERENCES `sa_accounts` (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=21561 DEFAULT CHARSET=utf8;

CREATE TABLE `sa_accounts` (
  `ID` int(10) unsigned NOT NULL,
  `Name` varchar(255) NOT NULL,
  `Type` enum('Asset','Liability','Income','Expense'),
  `Report` enum('BS','PL'), -- for "Balance Sheet" or "Profit & Loss"
  PRIMARY KEY (`ID`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

这里有一些简单的测试数据:

INSERT INTO sa_account (`ID`, `Name`, `Type`, `Report`)
  VALUES (1009999, "Test chequing account", "Asset", "BS"),
         (4059999, "Test Income account", "Income", "PL"),
         (5059999, "Test Income account", "Expense", "PL");
INSERT INTO sa_general_journal (`ID`, `Date`, `Item`, `Amount`, `Source`, `Destination`)
  VALUES (NULL, "2020-05-03", "Test income transaction", 10.10, 4059999, 1009999),
 (NULL, "2020-05-03", "Test expense transaction", 1.01, 1009999, 5059999);

这是收入$ 10.10,存入支票帐户,而支出$ 1.01来自支票帐户。

[要获得损益表的余额,您需要对Amount列中每个出现的帐户的所有Source项求和,然后减去该帐户所在的所有AmountDestination列。

预期结果将是:

<table>
<th>ID</th><th>Name</th><th>Debits</th><th>Credits</th><th>Net</th></tr>
<tr><td>1009999</td><td>Test chequing account</td><td>-1.01</td><td>10.10</td><td>9.09</td></tr>
<tr><td>4059999</td><td>Test income transaction</td><td>-10.10</td><td><i>NULL</i></td><td>-10.10</td></tr>
<tr><td>5059999</td><td>Test expense transaction</td><td><i>NULL</i></td><td>1.01</td><td>1.01</td></tr>
</table>

[我的第一个方法有些天真,要查询由sa_general_journalsa_accounts列选择的与Source表联接的Destination表,如果[[ C0]包含感兴趣的帐户。使用准备好的语句查询单个帐户时,我可以成功完成此操作:

Amount

其中所有四个占位符都具有相同的帐户ID。

但是,如果按不带WHERE子句的帐户ID进行分组以获取所有帐户余额的列表,则该操作将失败-用动态帐户ID代替占位符中的静态帐户ID似乎永远不会达到“ 0-exp.Amount ”代码……Du!该查询被选择为一个集合,而不是过程中的步骤。我明白了。

使SUM语句子查询有效,但速度非常慢,显然对数万条记录中的每一个都进行三个子查询!

所以,我以为我可以使用几个Common Table Expressions来分解子查询,但这似乎也无法正常工作,因为它似乎仍然只是返回SUM(Destination),而没有减去[C0是SELECT DATE_FORMAT(exp.Date, '%Y') AS `Year`, AVG(exp.Amount) AS `Avg`, SUM(IF(Source = ?, 0 - exp.Amount, NULL)) AS `Debits`, SUM(IF(Destination = ?, exp.Amount, NULL)) AS `Credits`, SUM(IF(Source = ?, 0 - exp.Amount, exp.Amount)) AS `Net` FROM sa_general_journal exp LEFT JOIN sa_accounts Destination ON exp.Destination = Destination.ID WHERE Destination = ? OR Source = ? GROUP BY `Year` 而不是Amount的]。

Amount

我猜我在做一些愚蠢的假设,或者做一些愚蠢的事情,所以任何建议都值得赞赏!

mysql common-table-expression accounting
1个回答
1
投票

没有示例数据,很难100%确定,但是此查询应提供所需的结果。它使用Destination查询将交易分为SourceWITH source1 AS (SELECT src.ID, src.Name, SUM(Amount) Amount FROM sa_general_journal gj LEFT JOIN sa_accounts src ON gj.`Source` = src.ID WHERE src.Report = "PL" -- AND YEAR(`Date`) = 2019 GROUP BY src.ID), destination1 AS (SELECT dst.ID, dst.Name, SUM(0-Amount) Amount FROM sa_general_journal gj LEFT JOIN sa_accounts dst ON gj.`Destination` = dst.ID WHERE dst.Report = "PL" -- AND YEAR(`Date`) = 2019 GROUP BY dst.ID) SELECT ID, Name, sum(Amount) FROM source1 UNION ALL SELECT ID, Name, sum(Amount) FROM destination1 GROUP BY ID 帐户,然后使用条件聚合将UNION每个帐户的交易。

Source

输出(用于样本数据):

Destination

SUM

© www.soinside.com 2019 - 2024. All rights reserved.