[英]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引擎来优化查询。 循环遍历结果集以发出重复查询很可能会阻止引擎进行优化,并且会增加许多可预防的开销。
此查询返回所有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.