【问题标题】:SQL for balance due without grouping all selectSQL for balance due without grouping all select
【发布时间】:2012-09-01 18:14:08
【问题描述】:

我已经提供了我的表的摘要,并且我在 SQL 方面有了一个良好的开端,但是我一直在弄清楚如何限制返回的项目数。我应该能够选择一个或多个条款,并从这些条款中取回应得的余额。

一个学生应该有 1 条记录,他们可以在多个学期进行多次预订,但付款不是针对预订的,而是针对学生的。那是让我失望的部分。

表结构、日期和我的 SQL 的开始如下。有人可以帮我吗?此结果不应显示 Sue Smith 从第 3 学期开始支付的 500 美元。

我正在使用 PostgreSQL,但我认为这是一个非常基本的问题,不需要任何特定于 Postgres 的内容。

当前结果集:

Student ID  Last        First   Total Fees  Reservation Count   Amount Paid Amount Due
123456      Jones       Amy     50          1                   50          0
412365      Smith       Sue     100         3                   545         -445
741258      Anderson    Jon     50          1                   0.00        50.00
963258      Holmes      Fred    100         2                   30          70

架构:

SET search_path TO temp, public;
CREATE TABLE term
(term_id                SERIAL PRIMARY KEY,
term_title              VARCHAR(100));

CREATE TABLE student
(student_id                 SERIAL PRIMARY KEY,
student_sis_id              VARCHAR(15),   
student_first_name              VARCHAR(30),
student_last_name               VARCHAR(100)); 

CREATE TABLE reservation
(reservation_id                      SERIAL PRIMARY KEY,
student_id                          INTEGER REFERENCES student ON UPDATE CASCADE,
term_id                             INTEGER REFERENCES term ON UPDATE CASCADE,   
reservation_fee_amount              NUMERIC DEFAULT 0.00);

CREATE TABLE payment
(payment_id                  SERIAL PRIMARY KEY,
student_id                  INTEGER REFERENCES student ON UPDATE CASCADE,
term_id                     INTEGER REFERENCES term ON UPDATE CASCADE,
payment_cash_amount         NUMERIC,
payment_credit_card_amount  NUMERIC,
payment_check_amount        NUMERIC);

INSERT INTO term VALUES (DEFAULT, 'SESSION 1');
INSERT INTO term VALUES (DEFAULT, 'SESSION 2');
INSERT INTO term VALUES (DEFAULT, 'SESSION 3'); 

INSERT INTO student VALUES (DEFAULT, 412365, 'Sue', 'Smith');
INSERT INTO student VALUES (DEFAULT, 123456, 'Amy', 'Jones');
INSERT INTO student VALUES (DEFAULT, 741258, 'Jon', 'Anderson');
INSERT INTO student VALUES (DEFAULT, 963258, 'Fred', 'Holmes');

INSERT INTO reservation VALUES (DEFAULT, 1, 1, 50);
INSERT INTO reservation VALUES (DEFAULT, 1, 2, 50);
INSERT INTO reservation VALUES (DEFAULT, 2, 1, 50);
INSERT INTO reservation VALUES (DEFAULT, 3, 2, 50);
INSERT INTO reservation VALUES (DEFAULT, 4, 1, 50);
INSERT INTO reservation VALUES (DEFAULT, 4, 2, 50);
INSERT INTO reservation VALUES (DEFAULT, 1, 3, 50);

INSERT INTO payment VALUES (DEFAULT, 1, 1, 25, 0, 0);
INSERT INTO payment VALUES (DEFAULT, 1, 1, 0, 20, 0);
INSERT INTO payment VALUES (DEFAULT, 2, 1, 25, 25, 0);
INSERT INTO payment VALUES (DEFAULT, 4, 1, 10, 10, 10);
INSERT INTO payment VALUES (DEFAULT, 1, 3, 500, 0, 0);

查询:

SELECT      
    student.student_sis_id AS "Student ID",        
    student.student_last_name AS Last,
    student.student_first_name AS First,
    SUM(reservation.reservation_fee_amount) AS "Total Fees",
    (
        SELECT COUNT(reservation.reservation_id)
        FROM reservation
        WHERE student.student_id = reservation.student_id
    ) AS "Reservation Count",
    (
        SELECT 
            COALESCE(SUM(
                payment.payment_check_amount
                + payment.payment_cash_amount
                + payment.payment_credit_card_amount
            ), 0.00)  
        FROM payment 
        WHERE payment.student_id = student.student_id
    ) AS "Amount Paid",
    SUM(reservation.reservation_fee_amount) - (
        SELECT 
            COALESCE(SUM(
                payment.payment_check_amount
                + payment.payment_cash_amount
                + payment.payment_credit_card_amount
            ), 0.00)  
        FROM payment WHERE payment.student_id = student.student_id
    ) AS "Amount Due" 
FROM 
    student
    INNER JOIN reservation ON student.student_id = reservation.student_id  
WHERE reservation.term_id IN (1,2)
GROUP BY
    student.student_id, 
    student.student_sis_id,        
    student.student_last_name,
    student.student_first_name
ORDER BY 
    student.student_sis_id
;

【问题讨论】:

    标签: sql postgresql group-by


    【解决方案1】:

    这是我的查询更新版本:

    SELECT      
        s.student_sis_id AS "Student ID",        
        s.student_last_name AS Last,
        s.student_first_name AS First,
        SUM(r.reservation_fee_amount) AS "Total Fees",
        COUNT(r.reservation_id) AS "Reservation Count",
        COALESCE(
            SUM(
                p.payment_check_amount
                + p.payment_cash_amount
                + p.payment_credit_card_amount
            ), 0.00
        ) AS "Amount Paid",
        SUM(r.reservation_fee_amount) - (
            COALESCE(
                SUM(
                    p.payment_check_amount
                    + p.payment_cash_amount
                    + p.payment_credit_card_amount
                ), 0.00
            )  
        ) AS "Amount Due" 
    FROM 
        student s
        INNER JOIN reservation r ON s.student_id = r.student_id  
        LEFT JOIN payment p ON p.student_id = r.student_id AND p.term_id = r.term_id
    WHERE r.term_id IN (1,2)
    GROUP BY
        s.student_id, 
        s.student_sis_id,        
        s.student_last_name,
        s.student_first_name
    ORDER BY 
        s.student_sis_id
    ;
    

    看点:

    • 我将payments 包含在主(外部)查询中以避免子查询

    • 连接类型为LEFT [OUTER] JOIN,因此缺少任何payment 行不会阻止其他数据出现在结果集中

    • 连接条件包括term_id(我想这基本上是你迷路的地方)

    • 最后我使用短表别名来提高可读性。

    我希望这就是你所追求的。

    【讨论】:

    • 就是这样,谢谢。感谢我的问题的标题,没有想到这一点。我试着问一个高质量的问题——它似乎会吸引高质量的答案,就像你的一样。
    • @user973828 - 你的问题确实质量很好。一个小补充:您可以使用SQLFiddle 避免粘贴太多代码(比如INSERTs)。
    • 嗨,还有一个问题。如果我在 From 子句中添加以下内容: FROM student s INNER JOIN reservation r ON s.student_id = r.student_id LEFT JOIN payment p ON p.student_id = r。 student_id AND p.term_id = r.term_id WHERE r.reservation_completed AND r.reservation_deleted_date 为 NULL 而不是 r.reservation_waitlisted AND r.term_id IN ($list) 我收到了一个错误的 reservation_completed 费用。我不明白为什么??
    • 费用翻倍,因为学生为一个预订支付了 2 次付款。我是否需要有一个付款子查询来处理这种情况?
    【解决方案2】:

    找到了 2 付款输入问题的解决方案(我在最初的问题中没有认识到)。答案如下:

    set search_path to temp, public;
    SELECT      
    s.student_sis_id AS "Student ID",        
    s.student_last_name AS "Last Name",
    s.student_first_name AS "First Name",
    SUM(r.reservation_fee_amount) AS "Total Fees",
    COALESCE(p.paid, 0.00) AS "Amount Paid",
    COALESCE(SUM(r.reservation_fee_amount) - p.paid, 0.00) AS "Amount Due"    
    FROM 
        student s       
        INNER JOIN reservation r ON s.student_id = r.student_id
        left outer join 
        (
          select student_id, term_id,
            SUM(
                p.payment_check_amount
                + p.payment_cash_amount
                + p.payment_credit_card_amount
            ) AS "paid" 
          from payment p
          group by student_id, term_id
        ) as p 
        ON p.student_id = r.student_id AND p.term_id = r.term_id
            WHERE r.reservation_completed  AND  r.term_id IN (1,2)                      
    GROUP BY
        s.student_sis_id,        
        s.student_last_name,
        s.student_first_name,
        p.paid
    ORDER BY 
        s.student_sis_id
    

    谢谢dezso和davek

    【讨论】:

      猜你喜欢
      • 2021-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-10
      • 2014-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多