簡體   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