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

时间:2011-07-19 20:28:53

标签: mysql join

我有一个有趣的问题 - 我需要与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 column not found”错误,但我没有收到。在最终通过UNION语句组合的每个语句块上,我指定invoices i以确保i.id引用发票的id。 tab.e

6 个答案:

答案 0 :(得分:2)

如果我假设你有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

paystatus:

1 =无薪
2 =部分支付的 3 =付费

答案 1 :(得分:2)

您没有告诉我们如何确定总发票金额,但我假设您的发票表上有一些字段。在下面的例子中,我假设它叫做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

答案 2 :(得分:0)

select * from table1 where not exists(select * from table2 where table2.foreignkey = table1.primarykey)

这有用吗?

答案 3 :(得分:0)

根据您的问题,我看不出任何方法可以判断发票是否已全额付款,但以下内容会为您提供一张没有付款的发票清单,后面会列出已付款的发票清单。

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
 )

答案 4 :(得分:0)

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

如果这样可行,我会感到惊讶。

答案 5 :(得分:0)

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

这将为您提供按照您想要的方式分类的发票,以及每张发票的付款金额总和