0

プロジェクト用に複数のテーブルがあります (セッション、料金、支払い)

セッションを取得するには、次のことを行っています。

SELECT
sess.file_id,  SUM(sess.rate * sess.length) AS total
FROM
sess
WHERE sess.sessionDone = 1 
GROUP BY sess.file_id

これは、特定の学生が支払うべき金額を返します

別のテーブル「料金」もあります

SELECT
file_charges.file_id,  SUM(file_charges.price) AS total_charges
FROM
file_charges
GROUP BY file_charges.file_id

そして最後に支払いクエリ:

SELECT
file_payments.file_id,  SUM(file_payments.paymentAmount) AS total_payment
FROM
file_payments
GROUP BY file_payments.file_id

これらの 3 つを組み合わせることはできますか :

 Total = Payments - (Session + Charges)

負になる可能性があるため、セッション、料金に存在するが支払いには存在しないfile_idを持つことができ、セッションまたは料金なしで支払いを行うことができることに注意してください...

編集: http://sqlfiddle.com/#!2/a90d9

4

2 に答える 2

3

file_id対処する必要がある 1 つの問題は、1 つまたは複数のクエリによって返される特定の行がない場合に、これらのクエリの 1 つが「ドライバー」になるかどうかです。(たとえば、 からの行はあるかもしれませんが、 からsessの行はありませんfile_payments。任意のクエリに表示されるすべての可能なものを確実に含めたい場合は、次のようなクエリでfile_id可能なすべてのリストを取得できます。file_id

SELECT ss.file_id FROM sess ss
 UNION 
SELECT fc.file_id FROM file_charges fc
 UNION 
SELECT fp.file_id FROM file_payments fp

(注: UNION 演算子は重複を削除します)

指定された結果セットを取得するには、そのクエリを他の 3 つの元のクエリの「左結合」と共に使用できます。クエリの概要は次のとおりです。

SELECT a.file_id, p.total_payment - ( s.total + c.total_charges)
  FROM a
  LEFT JOIN s ON s.file_id = a.file_id
  LEFT JOIN c ON c.file_id = a.file_id
  LEFT JOIN p ON p.file_id = a.file_id
 ORDER BY a.file_id

そのステートメントaには、すべての値のセットを取得するクエリの代用がありfile_idます (上記を参照)。sとはcpそれぞれ sess、file_charges、file_payments に関する 3 つの元のクエリの代用です。

いずれかfile_idのクエリで値が「欠落」している場合は、欠落している値をゼロに置き換える必要があります。IFNULL 関数を使用して、それを処理できます。

このクエリは、指定された結果セットを返す必要があります。

SELECT a.file_id
     , IFNULL(p.total_payment,0) - ( IFNULL(s.total,0) + IFNULL(c.total_charges,0)) AS t
  FROM ( -- all possible values of file_id
         SELECT ss.file_id FROM sess ss
          UNION 
         SELECT fc.file_id FROM file_charges fc
          UNION 
         SELECT fp.file_id FROM file_payments fp
       ) a
  LEFT
  JOIN ( -- the amount that a specific student should pay
         SELECT sess.file_id,  SUM(sess.rate * sess.length) AS total
           FROM sess
          WHERE sess.sessionDone = 1 
          GROUP BY sess.file_id
       ) s 
    ON s.file_id = a.file_id
  LEFT
  JOIN ( -- charges 
         SELECT file_charges.file_id,  SUM(file_charges.price) AS total_charges
           FROM file_charges
          GROUP BY file_charges.file_id
       ) c
    ON c.file_id = a.file_id
  LEFT
  JOIN ( -- payments 
         SELECT file_payments.file_id,  SUM(file_payments.paymentAmount) AS total_payment
           FROM file_payments
          GROUP BY file_payments.file_id
       ) p
    ON p.file_id = a.file_id
 ORDER BY a.file_id

(このクエリの EXPLAIN は、派生テーブルが 4 つあるため、見栄えがよくありません。非常に大きなセットでは、パフォーマンスが大幅に低下する可能性があります。ただし、返される結果セットは仕様を満たす必要があります。)

3 つのテーブルすべてを JOIN するクエリに注意してください。(たとえば) テーブルに同じ行が 2 つ (またはそれ以上) ある場合、誤った結果が返される可能性がありfile_idますfile_payment

同等の結果セットを取得する方法は他にもありますが、上記のクエリは、「これらのクエリの結果を合計に結合するにはどうすればよいか」という質問に答えています。


相関サブクエリの使用

SELECT リストで相関サブクエリを使用する別のアプローチを次に示します...

SELECT a.file_id
     , IFNULL( ( SELECT SUM(file_payments.paymentAmount) FROM file_payments
                    WHERE file_payments.file_id = a.file_id )
           ,0)
     - ( IFNULL( ( SELECT SUM(sess.rate * sess.length) FROM sess 
                    WHERE sess.file_id = a.file_id )
             ,0)
       + IFNULL( ( SELECT SUM(file_charges.price) FROM file_charges
                    WHERE file_charges.file_id = a.file_id )
             ,0)
       ) AS tot
  FROM ( -- all file_id values 
         SELECT ss.file_id FROM sess ss
          UNION 
         SELECT fc.file_id FROM file_charges fc
          UNION 
         SELECT fp.file_id FROM file_payments fp
       ) a
 ORDER BY a.file_id
于 2012-12-28T20:56:54.880 に答える
1

これを試して

 SELECT  sess.file_id,  SUM(file_payments.paymentAmount) - (SUM(sess.rate * sess.length)+SUM(file_charges.price)) as total_payment FROM sess , file_charges , file_payments 
   WHERE sess.sessionDone = 1 
  GROUP BY total_payment 

編集。

SELECT a.file_id
 , IFNULL(p.total_payment,0) - ( IFNULL(s.total,0) + IFNULL(c.total_charges,0)) AS tot
FROM ( 
     SELECT ss.file_id FROM sess ss
      UNION 
     SELECT fc.file_id FROM file_charges fc
      UNION 
     SELECT fp.file_id FROM file_payments fp
   ) a
 LEFT JOIN ( 
     SELECT sess.file_id,  SUM(sess.rate * sess.length) AS total
       FROM sess
      WHERE sess.sessionDone = 1 
      GROUP BY sess.file_id
   ) s 
ON s.file_id = a.file_id
 LEFT JOIN ( 
     SELECT file_charges.file_id,  SUM(file_charges.price) AS total_charges
       FROM file_charges
      GROUP BY file_charges.file_id
   ) c
ON c.file_id = a.file_id
LEFT JOIN ( 
     SELECT file_payments.file_id,  SUM(file_payments.paymentAmount) AS total_payment
       FROM file_payments
      GROUP BY file_payments.file_id
   ) p
 ON p.file_id = a.file_id
ORDER BY a.file_id

デモはこちら

于 2012-12-28T19:45:47.987 に答える