繁体   English   中英

如何使用PHP和MySQL从两个有条件链接的表中有效地SUM和SUBTRACT

[英]How to efficiently SUM and SUBTRACT from two conditionally linked tables using PHP and MySQL

对于以下查询是否有更有效的解决方案。 我尽力研究这个话题,但很难知道实际搜索的内容......

$tenant_balance = 0;

$total_charge_amount_query = mysqli_query($con, "
    SELECT  tenant_charge_id, tenant_charge_total_amount
        FROM  accounts_tenant_charge
        WHERE  tenant_charge_tenancy_id='{$tenancy_details['tenancy_id']}'"
     ) or die(mysql_error());  

while($total_charge_amount_row = mysqli_fetch_array( $total_charge_amount_query )) {

    $tenant_balance = $tenant_balance +  $total_charge_amount_row['tenant_charge_total_amount'];

    $total_payment_amount_query = mysqli_query($con, "
        SELECT  tenant_charge_payment_amount
            FROM  accounts_tenant_charge_payment
            WHERE  tenant_charge_payment_tenant_charge_id =
                    '{$total_charge_amount_row['tenant_charge_id']}"
                 ) or die(mysql_error());

    while($total_payment_amount_row = mysqli_fetch_array( $total_payment_amount_query )) {

        $tenant_balance = $tenant_balance - $total_payment_amount_row['tenant_charge_payment_amount'];

    }
}

echo '£' . number_format($tenant_balance, 2, '.', ',');

我在下面添加了数据库表结构和一些数据。

表格1

-- phpMyAdmin SQL Dump
-- version 4.0.10.7
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Jun 16, 2015 at 01:50 PM
-- Server version: 5.1.73-cll
-- PHP Version: 5.4.23

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";

--
-- Database: `propsyst_atlas`
--

-- --------------------------------------------------------

--
-- Table structure for table `accounts_tenant_charge`
--

CREATE TABLE IF NOT EXISTS `accounts_tenant_charge` (
  `tenant_charge_id` int(11) NOT NULL AUTO_INCREMENT,
  `tenant_charge_date` date DEFAULT NULL,
  `tenant_charge_payment_terms` tinyint(4) DEFAULT NULL,
  `tenant_charge_tenancy_id` int(11) DEFAULT NULL,
  `tenant_charge_notes` text COLLATE utf8_bin,
  `tenant_charge_total_amount` decimal(10,2) DEFAULT NULL,
  `tenant_charge_date_created` date DEFAULT NULL,
  `tenant_charge_date_updated` date DEFAULT NULL,
  `tenant_charge_created_by` int(11) DEFAULT NULL,
  `tenant_charge_updated_by` int(11) DEFAULT NULL,
  PRIMARY KEY (`tenant_charge_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=17 ;

--
-- Dumping data for table `accounts_tenant_charge`
--

INSERT INTO `accounts_tenant_charge` (`tenant_charge_id`, `tenant_charge_date`, `tenant_charge_payment_terms`, `tenant_charge_tenancy_id`, `tenant_charge_notes`, `tenant_charge_total_amount`, `tenant_charge_date_created`, `tenant_charge_date_updated`, `tenant_charge_created_by`, `tenant_charge_updated_by`) VALUES
(15, '2015-06-22', 1, 25, '', '180.00', '2015-06-14', '2015-06-14', 1, 1),
(14, '2015-06-15', 1, 25, '', '550.00', '2015-06-14', '2015-06-14', 1, 1),
(16, '2015-06-27', 1, 25, '', '10.00', '2015-06-14', '2015-06-14', 1, 1);

表#2

-- phpMyAdmin SQL Dump
-- version 4.0.10.7
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Jun 16, 2015 at 01:51 PM
-- Server version: 5.1.73-cll
-- PHP Version: 5.4.23

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";

--
-- Database: `propsyst_atlas`
--

-- --------------------------------------------------------

--
-- Table structure for table `accounts_tenant_charge_payment`
--

CREATE TABLE IF NOT EXISTS `accounts_tenant_charge_payment` (
  `tenant_charge_payment_id` int(11) NOT NULL AUTO_INCREMENT,
  `tenant_charge_payment_date` date DEFAULT NULL,
  `tenant_charge_payment_amount` decimal(10,2) DEFAULT NULL,
  `tenant_charge_payment_method` tinyint(4) DEFAULT NULL,
  `tenant_charge_payment_tenant_charge_id` int(11) DEFAULT NULL,
  `tenant_charge_payment_notes` text COLLATE utf8_bin,
  `tenant_charge_payment_date_created` date DEFAULT NULL,
  `tenant_charge_payment_date_updated` date DEFAULT NULL,
  `tenant_charge_payment_created_by` int(11) DEFAULT NULL,
  `tenant_charge_payment_updated_by` int(11) DEFAULT NULL,
  PRIMARY KEY (`tenant_charge_payment_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=12 ;

--
-- Dumping data for table `accounts_tenant_charge_payment`
--

INSERT INTO `accounts_tenant_charge_payment` (`tenant_charge_payment_id`, `tenant_charge_payment_date`, `tenant_charge_payment_amount`, `tenant_charge_payment_method`, `tenant_charge_payment_tenant_charge_id`, `tenant_charge_payment_notes`, `tenant_charge_payment_date_created`, `tenant_charge_payment_date_updated`, `tenant_charge_payment_created_by`, `tenant_charge_payment_updated_by`) VALUES
(9, '2015-06-15', '550.00', 2, 14, '', '2015-06-14', '2015-06-14', 1, 1),
(10, '2015-06-22', '50.00', 2, 15, '', '2015-06-16', '2015-06-16', 1, 1);

我想重点是摆脱几个查询和两个PHP循环。 无需循环,此查询在一个SQL查询中计算总费用,付款和余额:

SELECT
    tenant_charge_tenancy_id,
    sum(tenant_charge_total_amount) as charge,
    IFNULL(sum(payments.payment), 0) as payment,
    sum(tenant_charge_total_amount) - IFNULL(sum(payments.payment), 0) as balance
FROM accounts_tenant_charge
LEFT OUTER JOIN (
    SELECT
        tenant_charge_payment_tenant_charge_id,
        sum(tenant_charge_payment_amount) as payment
    FROM accounts_tenant_charge_payment
    GROUP BY tenant_charge_payment_tenant_charge_id
) as payments ON tenant_charge_id = tenant_charge_payment_tenant_charge_id
WHERE tenant_charge_tenancy_id= 25
GROUP BY tenant_charge_tenancy_id

您可以将$tenancy_details['tenancy_id']放在PHP代码中,而不是25。 通过删除WHERE tenant_charge_tenancy_id= ...您可以使用此查询来获取所有余额。

你正在使用id来查询来自account_tenant_charge的行,就像这样

SELECT tenant_charge_id, tenant_charge_total_amount
  FROM accounts_tenant_charge
 WHERE tenant_charge_tenancy_id= ?

然后对于该查询返回的每一行,将$tenant_balance求和,并查询(使用每个tenant_charge_id

SELECT tenant_charge_payment_amount 
  FROM accounts_tenant_charge_payment 
 WHERE tenant_charge_payment_tenant_charge_id= ?

$tenant_balance减去每个$tenant_balance

首先,您可以使用单个查询来执行此操作,该查询将被编译一次并在服务器上执行以提供单个结果,从而防止发出大量必须按顺序编译和执行的查询以及在Web之间来回传输数据服务器和dbms只是为了计算单个结果。

它就是这样的

SELECT SUM(x.amount)
  FROM (SELECT tenant_charge_total_amount amount
          FROM accounts_tenant_charge
         WHERE tenant_charge_tenancy_id= ?
        UNION
        SELECT -tenant_charge_payment_amount amount
          FROM accounts_tenant_charge a
               JOIN accounts_tenant_charge_payment b
               ON tenant_charge_payment_tenant_charge_id = a.tenant_charge_id
         WHERE tenant_charge_tenancy_id= ?) x

其次,使用绑定变量和预处理语句( 参见此处 )。 如果使用每个不同的id构建动态查询,则每次都强制db编译查询,从而增加执行时间的开销。 动态查询也容易受到SQL注入攻击。

SQL是一个说明性语言,这意味着你指定你想要得到什么和DBMS会找到最好的方式执行。 您应该首先依靠db引擎来优化查询。 循环遍历结果集以发出重复查询很可能会阻止引擎进行优化,并且会增加许多可预防的开销。

在这里查看DEMO

此查询返回所有tenant_charge_id并列出需要支付的总金额以及已支付的总金额。

SELECT
    charge.tenant_charge_id,
    charge.tenant_charge_total_amount,
    SUM(payment.tenant_charge_payment_amount) total_payments
FROM  accounts_tenant_charge charge
LEFT JOIN accounts_tenant_charge_payment payment
    ON payment.tenant_charge_payment_tenant_charge_id = charge.tenant_charge_id
GROUP BY tenant_charge_id

您可以添加WHERE子句以限制仅搜索租户的子集。

结果基于问题的数据

试试这个:

SELECT tenant_charge_payment_tenant_charge_id, SUM(amount) balance
FROM (
   SELECT tenant_charge_payment_tenant_charge_id, tenant_charge_total_amount amount
   FROM accounts_tenant_charge 
   WHERE tenant_charge_tenancy_id='" . $tenancy_details['tenancy_id'] . "'   
   UNION
   SELECT tenant_charge_payment_tenant_charge_id, CONCAT('-',tenant_charge_payment_amount) amount
   FROM accounts_tenant_charge_payment 
   WHERE tenant_charge_payment_tenant_charge_id='" . $total_charge_amount_row['tenant_charge_id'] . "'
) temp
GROUP BY tenant_charge_payment_tenant_charge_id

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM