【问题标题】:MySQL query to display all paid and unpaid invoices where invoices can have multiple paymentsMySQL 查询显示所有已付和未付发票,其中发票可以有多次付款
【发布时间】:2015-08-09 14:45:42
【问题描述】:

我有两张表,请看下面的结构。基本上,使用 MySQL/PHP,我需要构造两个查询。一个显示已付发票列表,另一个显示未付发票。一张发票可以针对它进行多次付款。例如,一张 100 英镑的发票可以使用任意数量的不同金额的付款来支付。发票也可以没有付款,这意味着全部余额未结。

你能帮忙查询一下吗?

我自己也尝试过查询(请参阅Is this 'paid or unpaid invoices' MySQL query possible?),但我没有提到发票可以有不止一次的付款。

表结构;

CREATE TABLE IF NOT EXISTS `accounts_invoice` (
  `invoice_id` int(11) NOT NULL AUTO_INCREMENT,
  `invoice_customer_type` tinyint(4) DEFAULT NULL,
  `invoice_customer` int(11) DEFAULT NULL,
  `invoice_date` date DEFAULT NULL,
  `invoice_due_date` date DEFAULT NULL,
  `invoice_property_id` int(11) DEFAULT NULL,
  `invoice_tenancy_id` int(11) DEFAULT NULL,
  `invoice_branch` int(11) DEFAULT NULL,
  `invoice_payment_terms` tinyint(4) DEFAULT NULL,
  `invoice_notes` text COLLATE utf8_bin,
  `invoice_total_amount_exc_vat` decimal(10,2) DEFAULT NULL,
  `invoice_total_vat_amount` decimal(10,2) DEFAULT NULL,
  `invoice_posted` tinyint(4) DEFAULT '0',
  `invoice_date_created` datetime DEFAULT NULL,
  `invoice_date_updated` datetime DEFAULT NULL,
  `invoice_date_posted` datetime DEFAULT NULL,
  `invoice_created_by` int(11) DEFAULT NULL,
  `invoice_updated_by` int(11) DEFAULT NULL,
  `invoice_posted_by` int(11) DEFAULT NULL,
  PRIMARY KEY (`invoice_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=87 ;

CREATE TABLE IF NOT EXISTS `accounts_invoice_payment` (
  `invoice_payment_id` int(11) NOT NULL AUTO_INCREMENT,
  `invoice_payment_date` date DEFAULT NULL,
  `invoice_payment_amount` decimal(10,2) DEFAULT NULL,
  `invoice_payment_method` tinyint(4) DEFAULT NULL,
  `invoice_payment_invoice_id` int(11) DEFAULT NULL,
  `invoice_payment_notes` text COLLATE utf8_bin,
  `invoice_payment_date_created` datetime DEFAULT NULL,
  `invoice_payment_date_updated` datetime DEFAULT NULL,
  `invoice_payment_created_by` int(11) DEFAULT NULL,
  `invoice_payment_updated_by` int(11) DEFAULT NULL,
  PRIMARY KEY (`invoice_payment_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=71 ;

【问题讨论】:

  • I did have a go at the query myself 查询在哪里?
  • invoice_payment_invoice_id == invoice_id ?
  • 您的数据和预期结果是什么?
  • Michael invoice_payment_invoice_id == invoice_id 当他们都是 AUTO_INCREMENT

标签: php mysql


【解决方案1】:

尽可能少地使用 PHP。它不是数据库引擎。即使是中等大小的数据集,它也会极大地拖累。

架构:

CREATE TABLE invoice
(
  invId int auto_increment primary key,
  custId int(11) not null,
  invAmt decimal(10,2) not null
);

CREATE TABLE payment
(
  pdId int auto_increment primary key,
  invId int not null,
  amt decimal(10,2) not null
);

-- NOTE you need foreign key (FK) constraints on your real table

insert invoice (custId,invAmt) values (101,9999);   -- 1
insert invoice (custId,invAmt) values (101,100);    -- 2
insert invoice (custId,invAmt) values (101,40);     -- 3
insert invoice (custId,invAmt) values (101,20);     -- 4
insert invoice (custId,invAmt) values (201,100);    -- 5

truncate table payment;
insert payment (invId,amt) values (1,10);   -- inv 1 pymt
insert payment (invId,amt) values (1,20);   -- inv 1 pymt
insert payment (invId,amt) values (1,30);   -- inv 1 pymt
insert payment (invId,amt) values (2,30);   -- inv 2 pymt
insert payment (invId,amt) values (2,70);   -- inv 2 pymt, now paid in full

insert payment (invId,amt) values (3,99);   -- inv 3 Overpayment

一次全部:

select i.invId,i.invAmt,ifnull(sum(p.amt),0) as paid,i.invAmt-ifnull(sum(p.amt),0) as due
from invoice i
left join payment p
on p.invId=i.invId
where i.custId=101
group by i.invId
order by i.invId

过期:

select i.invId,i.invAmt,ifnull(sum(p.amt),0) as paid,i.invAmt-ifnull(sum(p.amt),0) as due
from invoice i
left join payment p
on p.invId=i.invId
where i.custId=101
group by i.invId
having due>0
order by i.invId
+-------+---------+-------+---------+
| invId | invAmt  | paid  | due     |
+-------+---------+-------+---------+
|     1 | 9999.00 | 60.00 | 9939.00 |
|     4 |   20.00 |  0.00 |   20.00 |
+-------+---------+-------+---------+

全额支付:

select i.invId,i.invAmt,ifnull(sum(p.amt),0) as paid,i.invAmt-ifnull(sum(p.amt),0) as due
from invoice i
left join payment p
on p.invId=i.invId
where i.custId=101
group by i.invId
having due=0
order by i.invId
+-------+--------+--------+------+
| invId | invAmt | paid   | due  |
+-------+--------+--------+------+
|     2 | 100.00 | 100.00 | 0.00 |
+-------+--------+--------+------+

欠款:

select i.invId,i.invAmt,ifnull(sum(p.amt),0) as paid,i.invAmt-ifnull(sum(p.amt),0) as due
from invoice i
left join payment p
on p.invId=i.invId
where i.custId=101
group by i.invId
having due<0
order by i.invId

【讨论】:

  • due=0 的相同查询将显示所有已付清。负到期金额是多付款项。祝你好运
  • 你的意思是'WHERE due=0'吗?
  • 是的,我相信您不能在查询中引用“到期”
  • 你去。测试了所有 4 个。您可能需要其中的 1 个或 2 个
  • 做得很好,谢谢!完美运行,非常有效的解决方案!
【解决方案2】:

也许是这样的?有两个问题。

<?php

try
{
    $s = $conn->query("SELECT * from accounts_invoice");
}
catch(PDOException $e)
{
    echo $e->getMEssage();
}

try
{
    $p = $conn->prepare("SELECT * from accounts_invoice_payment where invoice_payment_invoice_id = :id");
}
catch(PDOException $e)
{
    echo $e->getMEssage();
}
while($main_invoies = $s->fetch(PDO::FETCH_OBJ))
{
    $invc_sum=0;
    $invoiceid = $main_invoies->invoice_id;
    $totalAmount = ($main_invoies->invoice_total_amount_exc_vat) + ($main_invoies->invoice_total_vat_amount);
    $p->bindParam(':id', $invoiceid);
    while($sub_invoices = $p->fetch(PDO::FETCH_OBJ))
    {
        $invc_sum = $invc_sum + ($sub_invoices->invoice_payment_amount);
    }
    if($invc_sum == $totalAmount)
    {
        echo "Invoice Paid";
    }
    else
    {
        echo "Invoice unpaid";
    }
}
?>

【讨论】:

  • 您的查询仍会返回所有发票,然后使用 if 语句对其进行处理。我希望查询只返回所有已付或未付的发票。
  • 能否上传一些测试数据?
  • 您的解决方案确实有效,但不如公认的答案有效。
  • @MichaelLB 很高兴您找到了解决方案 :)
  • 它确实工作得很好,只是没有那么快。永远不要在 php 中做 mysql 可以做得更快的事情。想象一下有 10k 行返回,而 sql 将答案交给您。 PHP 是一个很棒的东西……它不是一个高性能的数据库引擎
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多