Как извлечь строки из таблицы 1, которые не имеют связанных строк в таблице 2 в MySQL - PullRequest
1 голос
/ 20 июля 2011

У меня есть интересный вопрос - мне нужен точный обратный оператор JOIN.

У меня есть таблица под названием счета-фактуры, а другая таблица называется платежами. Я хочу получить по порядку счета-фактуры, к которым вообще не прикреплены никакие платежи, но за которыми следуют строки, к которым после этого прикреплены платежи.

* Таблица 1004 * счетов имеет следующие поля:
  • ID
  • CustomerID
  • 1012 * Отметка времени *
Таблица платежей

имеет следующие поля:

  • ID
  • InvoiceID

Не все платежи являются полными суммами, поэтому к каждому счету может быть прикреплено несколько платежей.

Я хочу, чтобы сначала выставлялись неоплаченные счета-фактуры (без платежей), затем следовали счета-фактуры с частичными, но не полными платежами, а затем с последующими полностью оплаченными счетами.

Я хочу выполнить это, не выполняя отдельные запросы SQL, если смогу - я бы предпочел, чтобы это был один запрос, чтобы я мог выплюнуть один раз. Есть идеи?

- ОБНОВЛЕНО -

На основании ответа от DCP я обновил метод запроса. Я работал до тех пор, пока мне не нужно было добавить этот оператор JOIN для упорядочения по моей таблице sub_to_inv, которая выглядит следующим образом:

идентификатор подписки 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 ссылается на идентификатор счетов-фактур. tab.e

Ответы [ 6 ]

2 голосов
/ 20 июля 2011

Вы не сказали нам, как определить общую сумму счета, но я предполагаю, что у вас есть поле в таблице счетов для этого.В приведенном ниже примере я предположил, что он называется 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 голосов
/ 20 июля 2011

Если бы я предположил, что у вас есть таблица 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 = оплачено

0 голосов
/ 20 июля 2011
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

это даст вам счета, отсортированные так, как вы хотели, а также сумму оплаченной суммы за счет

0 голосов
/ 20 июля 2011
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

Если это сработает, я буду поражен.

0 голосов
/ 20 июля 2011

По вашему вопросу я не вижу способа определить, полностью ли оплачен счет, но ниже приведен список счетов без платежей, за которым следует список счетов с платежами.

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
 )
0 голосов
/ 20 июля 2011

выберите * из таблицы1, где не существует (выберите * из таблицы2, где table2.foreignkey = table1.primarykey)

Это работает?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...