繁体   English   中英

如何从表 1 中检索在 MySQL 中表 2 中没有相关行的行

[英]How to retrieve rows from table 1 that have no related rows in table 2 in MySQL

我有一个有趣的问题 - 我需要 JOIN 语句的完全相反的内容。

我有一张叫做发票的表格,还有一张叫做付款的表格。 我想按顺序检索没有附加任何付款的发票,但随后是附加了付款的行。

发票表具有以下字段:

  • ID
  • 客户ID
  • 时间戳

付款表具有以下字段:

  • ID
  • invoiceid
  • 数量

并非所有付款都是全额付款,因此每张发票可能附有多笔付款。

我希望首先出现未付款的发票(不付款),然后是部分付款但未全额付款的发票,然后是全额付款的发票。

如果可以的话,我希望在不必运行单独的 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM