次のDB設計を継承しました。テーブルは次のとおりです。
customers
---------
customerid
customernumber
invoices
--------
invoiceid
amount
invoicepayments
---------------
invoicepaymentid
invoiceid
paymentid
payments
--------
paymentid
customerid
amount
私のクエリは、指定された顧客番号に対して、請求書ID、請求書金額(請求書テーブル内)、および支払額(請求書金額から請求書に対して行われた支払いを差し引いたもの)を返す必要があります。顧客は複数の請求書を持っている場合があります。
次のクエリは、請求書に対して複数の支払いが行われたときに重複したレコードを提供します。
SELECT i.invoiceid, i.amount, i.amount - p.amount AS amountdue
FROM invoices i
LEFT JOIN invoicepayments ip ON i.invoiceid = ip.invoiceid
LEFT JOIN payments p ON ip.paymentid = p.paymentid
LEFT JOIN customers c ON p.customerid = c.customerid
WHERE c.customernumber = '100'
どうすれば解決できますか?
私はあなたを手に入れたかはわかりませんが、これはあなたが探しているものかもしれません:
SELECT i.invoiceid, sum(case when i.amount is not null then i.amount else 0 end), sum(case when i.amount is not null then i.amount else 0 end) - sum(case when p.amount is not null then p.amount else 0 end) AS amountdue
FROM invoices i
LEFT JOIN invoicepayments ip ON i.invoiceid = ip.invoiceid
LEFT JOIN payments p ON ip.paymentid = p.paymentid
LEFT JOIN customers c ON p.customerid = c.customerid
WHERE c.customernumber = '100'
GROUP BY i.invoiceid
これにより、各請求書に複数の支払い行がある場合の金額の合計が得られます
返信ありがとうございました!
Saggi Malachi、このクエリは、残念ながら複数の支払いがある場合の請求額を合計します。 18ドルと12ドルの39ドルの請求書に対して2回の支払いがあるとします。結果は次のようになります:
1 39.00 9.00
次のようになります。
1 78.00 48.00
Charles Bretanaは、クエリを可能な限り単純なクエリにトリミングする過程で、顧客と請求書間のリンクを提供する追加のテーブルcustomerinvoicesを(愚かに)省略しました。これは、支払いが行われていない請求書を確認するために使用できます。
多くの苦労の末、次のクエリは必要なものを返すと思います。
SELECT DISTINCT i.invoiceid, i.amount, ISNULL(i.amount - p.amount, i.amount) AS amountdue
FROM invoices i
LEFT JOIN invoicepayments ip ON i.invoiceid = ip.invoiceid
LEFT JOIN customerinvoices ci ON i.invoiceid = ci.invoiceid
LEFT JOIN (
SELECT invoiceid, SUM(p.amount) amount
FROM invoicepayments ip
LEFT JOIN payments p ON ip.paymentid = p.paymentid
GROUP BY ip.invoiceid
) p
ON p.invoiceid = ip.invoiceid
LEFT JOIN payments p2 ON ip.paymentid = p2.paymentid
LEFT JOIN customers c ON ci.customerid = c.customerid
WHERE c.customernumber='100'
同意しますか?
同じテーブルからさまざまな集計値を取得したい人のためのヒントがあります。
ユーザーのテーブルとユーザーが獲得したポイントのテーブルがあるとしましょう。したがって、それらの間の接続は1:N(1人のユーザー、多くのポイントレコード)です。
ここで、「ポイント」テーブルに、ユーザーがポイントを獲得した理由(ログイン、バナーをクリックなど)に関する情報も保存します。そして、SUM(points)
AND SUM(points WHERE type = x)
の順に並べられたすべてのユーザーをリストしたいと思います。つまり、ユーザーが持つすべてのポイントで並べ替えられ、特定のアクション(ログインなど)でユーザーが獲得したポイントで並べ替えられます。
SQLは次のようになります。
_SELECT SUM(points.points) AS points_all, SUM(points.points * (points.type = 7)) AS points_login
FROM user
LEFT JOIN points ON user.id = points.user_id
GROUP BY user.id
_
これの美しさはSUM(points.points * (points.type = 7))
にあり、内側の括弧が0または1のいずれかに評価されるため、指定されたポイント値に0または1を掛けます。
まず、InvoicesテーブルにCustomerIdを含めるべきではありませんか?現状では、まだ支払いのない請求書に対してこのクエリを実行することはできません。請求書に支払いがない場合、その請求書は外部結合であってもクエリの出力に表示されません...
また、顧客が支払いを行うとき、どの請求書を添付するのかをどのように知るのですか?支払いとともに到着するスタブ上のInvoiceIdによる唯一の方法である場合、請求書を注文した顧客ではなく、支払った顧客に(おそらく不適切に)関連付けています。 (請求書は、サービスを注文した顧客以外の誰かが支払う場合があります)
これは遅いことはわかっていますが、元の質問には答えています。
/*Read the comments the same way that SQL runs the query
1) FROM
2) GROUP
3) SELECT
4) My final notes at the bottom
*/
SELECT
list.invoiceid
, cust.customernumber
, MAX(list.inv_amount) AS invoice_amount/* we select the max because it will be the same for each payment to that invoice (presumably invoice amounts do not vary based on payment) */
, MAX(list.inv_amount) - SUM(list.pay_amount) AS [amount_due]
FROM
Customers AS cust
INNER JOIN
Payments AS pay
ON
pay.customerid = cust.customerid
INNER JOIN ( /* generate a list of payment_ids, their amounts, and the totals of the invoices they billed to*/
SELECT
inpay.paymentid AS paymentid
, inv.invoiceid AS invoiceid
, inv.amount AS inv_amount
, pay.amount AS pay_amount
FROM
InvoicePayments AS inpay
INNER JOIN
Invoices AS inv
ON inv.invoiceid = inpay.invoiceid
INNER JOIN
Payments AS pay
ON pay.paymentid = inpay.paymentid
) AS list
ON
list.paymentid = pay.paymentid
/* so at this point my result set would look like:
-- All my customers (crossed by) every paymentid they are associated to (I'll call this A)
-- Every invoice payment and its association to: its own ammount, the total invoice ammount, its own paymentid (what I call list)
-- Filter out all records in A that do not have a paymentid matching in (list)
-- we filter the result because there may be payments that did not go towards invoices!
*/
GROUP BY
/* we want a record line for each customer and invoice ( or basically each invoice but i believe this makes more sense logically */
cust.customernumber
, list.invoiceid
/*
-- we can improve this query by only hitting the Payments table once by moving it inside of our list subquery,
-- but this is what made sense to me when I was planning.
-- Hopefully it makes it clearer how the thought process works to leave it in there
-- as several people have already pointed out, the data structure of the DB prevents us from looking at customers with invoices that have no payments towards them.
*/