2015-06-16 15 views
6

Aşağıdaki sorgu için daha verimli bir çözüm var mıdır? ... benim yeteneği en iyi şekilde konuyu araştırma çalıştık ama aslında aramak ne bilmek zorPHP ve MySQL kullanılarak iki koşullu olarak bağlanmış tablodan SUM ve SUBTRACT nasıl verimli kullanılır

Ben veritabanı tablo yapısını ve aşağıda bazı verileri eklemiş
$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, '.', ','); 

.

Tablo # 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); 

Tablo # 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); 
+1

sql tabloları yapısını sağlayabilir? Sorguları tahmin edebilirim, ancak yine de soruyu basitleştirmeye yardımcı olabilir. – Mehdi

+0

Evet, benim tablo yapılarımı sunmam için en iyi/en kolay yol ne olurdu? PhpMyAdmin ekran görüntüsü? –

+0

, veri yerine yapıyı dışa aktarın, daha sonra CREATE TABLE betiğini buraya yapıştırın – Mehdi

cevap

-1

bu deneyin:

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 
+0

Bu bir UNION ALL olmalı? – winmutt

+1

Cevabınız için teşekkür ederiz, bunun nasıl daha verimli bir çözüm olduğunu açıklayabilir misiniz? –

1

noktanın birkaç sorguları kurtulmak ve iki PHP döngüler sanırım. Eğer PHP kodunda $tenancy_details['tenancy_id'] koyabilirsiniz

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 

Yerine 25: döngüler gerek, bu sorgu ile birleşme yeri bir SQL sorgusunda toplam yükü, ödemeler ve denge hesaplayın. WHERE tenant_charge_tenancy_id= ...'u kaldırarak Tüm dengeleri almak için bu sorguyu kullanabilirsiniz.

+1

Cevabınız için teşekkür ederiz, ancak her kiracı ücretine birden fazla kiracı ücreti ödemesi olabileceğinden maalesef kodunuz çalışmaz. Örneğin. Kiracı ücreti 100 sterlin olabilir, ancak ödeme yapmak için iki ödeme yapılabilir, yani 25 sterlin ve 75 sterlin. –

+0

Bir "tenant_charge_tenancy_id" veya "tenancy_id" ile ilgili tüm ödemeleri kapsar. Bir hatayı "IFNULL" ile tamir ettim. Tekrar dene. – Mehdi

+0

'WHERE’ satırını kaldırın ve sorguyu phpMyAdmin'inizde deneyin. – Mehdi

0

Eğer o sorgunun döndürülen her satır için o zaman bu

SELECT tenant_charge_id, tenant_charge_total_amount 
    FROM accounts_tenant_charge 
WHERE tenant_charge_tenancy_id= ? 

gibi bir kimliğe sahip account_tenant_charge satırları sorgulama $tenant_balance yılında tenant_charge_total_amount toplayarak ve

SELECT tenant_charge_payment_amount 
    FROM accounts_tenant_charge_payment 
WHERE tenant_charge_payment_tenant_charge_id= ? 
(her tenant_charge_id ile) sorguluyorsunuz Her bir onant_charge_payment_amount öğesini $tenant_balance'dan çıkararak

.

Her şeyden önce, bir kez derlenecek ve tek bir sonuç sağlamak için sunucu üzerinde çalıştırılan tek bir sorgu ile bunu yapabilirsiniz, derlenmesi ve sırayla yürütülmesi ve veri geri aktarılması gereken çok sayıda sorgunun yayınlanmasını önler ve web sunucusu ve dbms arasında sadece tek bir sonuç hesaplamak için.

Bu

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 

İkinci, kullanım bağlama değişkenleri ve hazırlanan tablolarda (see here) gibi bir şey olurdu. Her farklı kimlikle dinamik bir sorgu oluşturursanız, her defasında sorguyu derlemek için db'yi zorlarsınız ve yürütme süresine ek yükler eklersiniz. Ayrıca dinamik sorgular sql enjeksiyon saldırılarına karşı hassastır.

SQL, bir bildirim dilidir; bu, numaralı telefonu belirtmek istediğiniz değerini belirtmeniz anlamına gelir ve dbms bunu bulduğu en iyi şekilde çalıştırır. Sorgularınızı optimize etmek için öncelikle db motoruna güvenmelisiniz. Yinelenen sorguları yayınlamak için sonuç kümeleriyle dolaşmak, büyük olasılıkla motorun optimizasyonunu engeller ve önlenebilir bir çok yük ekler.

Bkz. DEMO here.

+0

Kodunuz aynı kiracı ücretine karşı birden çok ödeme yapılmasına izin veriyor mu? Henüz test etme şansım olmadı ve kodu anlamakta zorlanıyorum (benim hatam - seninki değil) –

+0

sendikanın ikinci kısmı. DEMO linkinde deneyebilirsiniz. – 1010

+0

soru işaretleri, geçirmeniz gereken bağlama değişkenlerini temsil eder. Test etmek için bunları bir numarayla değiştirebilirsiniz. – 1010

0

Bu sorgu, tenant_charge_id öğesinin tümünü verir ve ödenmesi gereken toplam tutarı ve ayrıca ödenen toplam tutarı listeler.

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 

Sen kiracı sadece bir alt kümesi için arama kısıtlamak için bir WHERE maddesini ekleyebilir.

The result based on the data from the question