[英]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.