Php 如何构建一个查询,对交换发件人和收件人的交易余额进行求和

Php 如何构建一个查询,对交换发件人和收件人的交易余额进行求和,php,mysql,sql,Php,Mysql,Sql,我正在设置一个脚本,它只使用一个事务表而不使用余额表来计算用户的余额。现在我想试着做一个这样的查询,这可能吗?如果可能,我该怎么做 这适用于使用现有代码库/数据库的内部应用程序。目前,我只使用php完成了这项工作 $outgoing = $this->entityManager->getRepository(Transaction::class)->findBy([ 'sender' => $user, 'contract' => $contract

我正在设置一个脚本,它只使用一个事务表而不使用余额表来计算用户的余额。现在我想试着做一个这样的查询,这可能吗?如果可能,我该怎么做

这适用于使用现有代码库/数据库的内部应用程序。目前,我只使用php完成了这项工作

$outgoing = $this->entityManager->getRepository(Transaction::class)->findBy([
    'sender' => $user,
    'contract' => $contract
]);

$incoming = $this->entityManager->getRepository(Transaction::class)->findBy([
    'recipient' => $user,
    'contract' => $contract
]);

$history = $outgoing + $incoming;

foreach ($history as $index => $transaction) {
    if ($transaction->getTokens() > 0) {
        continue;
    }

    unset($history[$index]);
}

usort($history, function ($a, $b) {
    if ($a->getCreatedOn() === $b->getCreatedOn()) {
        return 0;
    }

    return $a->getCreatedOn() > $b->getCreatedOn() ? 1 : -1;
});

$balance = 0;

foreach ($history as $row) {
    if ($row->getSender() === $user) {
        $balance -= $row->getTokens();
    }

    if ($row->getRecipient() === $user) {
        $balance += $row->getTokens();
    }
}

return $balance;
表的结构:

交易

  • 身份证
  • 发送者身份证
  • 收件人id
  • 合同编号
  • 代币
  • 价格
  • 创建于

我希望使用一个int作为余额编号。

我不知道如何将其转换为对entitymanager接口的调用,但以下是一些SQL,它们应该可以完成这项工作,并且非常容易阅读:

SELECT credits.total - debits.total AS balance
FROM 
 (SELECT SUM(tokens) AS total 
  FROM `transaction`
  WHERE sender_id = :user
  AND contract_id = :contract) AS debits
CROSS JOIN 
 (SELECT SUM(tokens) AS total
  FROM `transaction`
  WHERE recipient_id = :user 
  AND contract_id = :contract) AS credits
您应该拥有以下两个索引,以优化此功能:

  • (发件人id、合同id、代币)
  • (收件人id、合同id、代币)
为了进行测试,我创建了以下表:

CREATE TABLE `transaction` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `sender_id` int(11) NOT NULL,
  `recipient_id` int(11) NOT NULL,
  `contract_id` int(11) NOT NULL,
  `tokens` int(11) NOT NULL,
  `price` decimal(9,2) NOT NULL,
  `created_on` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `sender_id` (`sender_id`,`contract_id`,`tokens`),
  KEY `recipient_id` (`recipient_id`,`contract_id`,`tokens`)
);
下面是一些示例数据。两个借项和三个贷项,每笔交易中有三个代币:

INSERT INTO `transaction` VALUES 
(1,10,20,1,3,19.95,'2019-01-20 15:41:47'),
(2,10,20,1,3,19.95,'2019-01-20 15:41:47'),
(3,30,10,1,3,19.95,'2019-01-20 15:41:47'),
(4,30,10,1,3,19.95,'2019-01-20 15:41:47'),
(5,20,10,1,3,19.95,'2019-01-20 15:41:47');
下面是查询解释报告,显示了每个子查询中覆盖索引的使用情况:

+----+-------------+-------------+--------+---------------+--------------+---------+-------------+------+-------------+
| id | select_type | table       | type   | possible_keys | key          | key_len | ref         | rows | Extra       |
+----+-------------+-------------+--------+---------------+--------------+---------+-------------+------+-------------+
|  1 | PRIMARY     | <derived2>  | system | NULL          | NULL         | NULL    | NULL        |    1 | NULL        |
|  1 | PRIMARY     | <derived3>  | system | NULL          | NULL         | NULL    | NULL        |    1 | NULL        |
|  3 | DERIVED     | transaction | ref    | recipient_id  | recipient_id | 8       | const,const |    3 | Using index |
|  2 | DERIVED     | transaction | ref    | sender_id     | sender_id    | 8       | const,const |    2 | Using index |
+----+-------------+-------------+--------+---------------+--------------+---------+-------------+------+-------------+

我添加了表结构和我想要的输出。
+---------+
| balance |
+---------+
|       3 |
+---------+