![](/img/trans.png)
[英]How to retrieve few random rows of left table and all the related rows from right table in 1 to n relationship
[英]How to retrieve rows from table 1 that have no related rows in table 2 in MySQL
我有一个有趣的问题 - 我需要 JOIN 语句的完全相反的内容。
我有一张叫做发票的表格,还有一张叫做付款的表格。 我想按顺序检索没有附加任何付款的发票,但随后是附加了付款的行。
发票表具有以下字段:
付款表具有以下字段:
并非所有付款都是全额付款,因此每张发票可能附有多笔付款。
我希望首先出现未付款的发票(不付款),然后是部分付款但未全额付款的发票,然后是全额付款的发票。
如果可以的话,我希望在不必运行单独的 SQL 查询的情况下执行此操作 - 我宁愿它是一个查询,这样我就可以吐出一次。 有任何想法吗?
- 更新 -
根据 DCP 的回答,我更新了查询方法。 我让它工作,直到我需要添加该 JOIN 语句以也按我的 sub_to_inv 表排序,如下所示:
id 订阅发票 0 12 18 1 13 18 2 14 19
等等
因此,基于此,我想出了这个(在页面限制的末尾添加了 LIMIT ..)
SELECT i.id AS id, i.modify_date as modify_date, s.subscription as subscriptionid, 0 paidratio FROM invoices i
LEFT JOIN sub_to_inv s ON i.id=s.invoice
WHERE NOT EXISTS (SELECT id FROM payments p WHERE p.invoice=i.id) AND i.corporation='3' AND i.payer=1
UNION ALL
SELECT i.id AS id, i.modify_date as modify_date, s.subscription as subscriptionid, p.paid/i.total AS paidratio FROM invoices i,
(SELECT p.invoice, sum(amount) AS paid FROM payments p GROUP BY p.invoice) p
LEFT JOIN sub_to_inv s ON i.id=s.invoice
WHERE p.invoice=i.id AND i.corporation='3' AND i.payer=1
AND p.paid UNION ALL
SELECT i.id AS id, i.modify_date as modify_date, s.subscription as subscriptionid, p.paid/i.total AS paitratio FROM invoices i,
(SELECT p.invoice, sum(amount) AS paid FROM payments p WHERE p.invoice=id GROUP BY p.invoice) p
LEFT JOIN sub_to_inv s ON i.id=s.invoice
WHERE p.invoice = i.id AND i.corporation='3' AND i.payer=1
AND p.paid=i.total
ORDER BY paidratio DESC, modify_date DESC, subscriptionid ASC LIMIT 0,40
我收到一个“未找到 i.id 列”错误,但我没有收到。 在最终通过 UNION 语句组合的每个语句块上,我指定invoices i
以确保 i.id 指的是发票的 id。 选项卡.e
如果我假设您有一个包含总金额的invoice_details
表:
SELECT i.id as invoiceid,
case
when (select sum(amount) from payments where invoiceid = i.id group by invoiceid) = d.amount
then 3
when (select sum(amount) from payments where invoiceid = i.id group by invoiceid) < d.amount
then 2
else 1
end
as paidstatus
FROM invoices i
INNER JOIN invoice_details d
ON i.id = d.invoiceid
LEFT JOIN payments p
ON i.id = p.invoiceid
GROUP BY i.id, d.amount
ORDER BY paidstatus
支付状态:
1 = 未付
2 = 部分支付
3 = 付费
您没有告诉我们如何确定总发票金额,但我假设您的发票表中有一些字段用于此。 在下面的示例中,我假设它称为 TOT_AMT。
这种方法背后的想法是,我们通过三个独立的步骤获取数据,并使用 UNION ALL 将这三个部分粘合在一起。 我们使用一个名为 PAY_TYPE 的伪列来获取您想要的顺序,即首先是未付款的发票,然后是部分付款的发票,最后是全额付款的发票。
一个完整的工作示例如下所示(我使用了 Oracle,但我认为您可以轻松地将其调整为 MySQL)。
CREATE TABLE invoices (ID number, tot_amt NUMBER);
CREATE TABLE payments (ID NUMBER, invoice_id NUMBER, amount NUMBER);
INSERT INTO invoices VALUES (1,100);
INSERT INTO invoices VALUES (2,200);
INSERT INTO invoices VALUES (3,300);
INSERT INTO payments VALUES (1,1,20);
INSERT INTO payments VALUES (2,1,40);
INSERT INTO payments VALUES (3,3,150);
INSERT INTO payments VALUES (4,3,120);
INSERT INTO payments VALUES (5,3,30);
/* get invoices with no payments */
SELECT i.id
, i.TOT_AMT
, 0 TOT_PAID
, '0_NO_PAYMENTS' PAY_TYPE
FROM invoices i
WHERE NOT EXISTS (SELECT * FROM PAYMENTS P WHERE P.INVOICE_ID = I.ID)
UNION ALL
/* get invoices with partial payments */
SELECT i.id
, i.TOT_AMT
, p.tot_paid
, '1_PARTIALLY_PAID' PAY_TYPE
FROM invoices i
, (SELECT P.INVOICE_ID
, SUM(AMOUNT) tot_paid
FROM PAYMENTS P
GROUP BY P.INVOICE_ID) p
WHERE P.INVOICE_ID = I.ID
AND p.TOT_PAID < i.TOT_AMT
UNION ALL
/* get invoices that are fully paid */
SELECT i.id
, i.TOT_AMT
, p.tot_paid
, '2_FULLY_PAID' PAY_TYPE
FROM invoices i
, (SELECT P.INVOICE_ID
, SUM(AMOUNT) tot_paid
FROM PAYMENTS P
GROUP BY P.INVOICE_ID) p
WHERE P.INVOICE_ID = I.ID
AND p.TOT_PAID = i.TOT_AMT
ORDER BY PAY_TYPE
结果:
ID TOT_AMT TOT_PAID PAY_TYPE
2 200 0 0_NO_PAYMENTS
1 100 60 1_PARTIALLY_PAID
3 300 300 2_FULLY_PAID
select * from table1 where not exists (select * from table2 where table2.foreignkey = table1.primarykey)
那样有用吗?
根据您的问题,我看不出有任何方法可以判断发票是否已全额支付,但以下将为您提供未付款的发票列表,然后是已付款的发票列表。
select *
from
invoices
where
not exists (
select 1
from payments
where invoices.id = payments.invoiceid
)
union
select *
from
invoices
where
exists (
select 1
from payments
where invoices.id = payments.invoiceid
)
SELECT i.id FROM invoices i
LEFT JOIN PAYMENTS p ON i.id = p.invoice_id
GROUP BY i.id, i.amount
ORDER BY SUM(p.amount) / i.amount
如果这行得通,我会感到惊讶。
select sub.*, paid/tot_amt as ordering_column
from (
select
i.id,
i.customerid,
i.timestamp,
i.tot_amt,
(select sum(ifnull(p.amount,0)) from payments p where p.invoiceid = i.id ) as paid
from invoices i
) sub
order by ordering_column
这将为您提供按您想要的方式排序的发票,以及每张发票支付金额的总和
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.