结合两个Postgresql查询

时间:2017-06-16 19:10:01

标签: sql postgresql

我有这个查询,它根据驱动程序编号返回驱动程序工作的天数。我检查工作天数的方法就是计算不同的order_date及其驱动程序编号。让我们称之为工作日:

SELECT driver_no, count(distinct order_date)

FROM orders o INNER JOIN order_settlements os ON o.control_no = 
os.control_no 

WHERE os.company_no = '001' and o.service_type not in (17, 30, 31, 34, 35, 
90, 94, 96, 97, 98, 99) and customer_reference != 'PARCEL ADJUSTMENT' and 
order_date between (date '2017-6-11' - integer '7') and '2017-6-11' and 
posting_status <> '9' and settlement_period_end_date is null

GROUP BY driver_no

我有这个查询,可以计算出驾驶员的收入,交付的数量等等。让我们称之为主:

    SELECT Driver_Number, Driver_Name, Branch, Driver_Type, sum(Revenue) AS Revenue, sum(Booking) as Booking, CASE WHEN round(sum(Support_Pay * Settlement_Per/100), 2) != 0 THEN round(sum(Support_Pay * Settlement_Per/100), 2) END as Support_Pay, round(sum(fuel * Settlement_Per/100), 2) as Fuel, round(sum(Booking * Settlement_Per/100), 2) as Settlement, sum(Stops) As Stops, sum(Pieces) As Pieces

    FROM 
    (  SELECT os.driver_no as Driver_Number, d.driver_name as Driver_Name, d.report_sort_key as Branch, (CASE WHEN d.driver_type = '0' THEN 'Contractor' WHEN d.driver_type = '1' THEN 'Employee' END) as Driver_Type,
      sum(o.rate_bucket1+o.rate_bucket2+o.rate_bucket3+o.rate_bucket4+o.rate_bucket5+o.rate_bucket6+ 
      o.rate_bucket7+o.rate_bucket8+o.rate_bucket9+o.rate_bucket10+o.rate_bucket11) as Revenue,
    sum(os.charge1+os.charge2+os.charge3+os.charge4+os.charge5+os.charge6) as Booking, CASE WHEN (o.service_type = '35') THEN sum(os.charge1+os.charge2+os.charge3+os.charge4+os.charge5+os.charge6) END AS Support_Pay, CASE WHEN (o.service_type = '34') THEN sum(os.charge1+os.charge2+os.charge3+os.charge4+os.charge5+os.charge6) END AS Fuel,
    os.settlement_percent as Settlement_Per, CASE WHEN (o.service_type != '17' or o.service_type != '30' or o.service_type != '31' or o.service_type != '34' or o.service_type != '35' or o.service_type != '90' or o.service_type != '94' or o.service_type != '96' or o.service_type != '97' or o.service_type != '98' or o.service_type != '99') THEN count(os.control_no) END as Stops, CASE WHEN (o.service_type != '17' or o.service_type != '30' or o.service_type != '31' or o.service_type != '34' or o.service_type != '35' or o.service_type != '90' or o.service_type != '94' or o.service_type != '96' or o.service_type != '97' or o.service_type != '98' or o.service_type != '99') THEN sum(o.pieces) END as Pieces


    FROM 
    orders o INNER JOIN order_settlements os ON o.control_no = os.control_no INNER JOIN drivers d ON os.driver_no = d.driver_no

    WHERE 
    d.company_no = '001' and 
    order_date BETWEEN '2017-4-9' AND '2017-6-11' AND
      os.company_no = '001' and o.company_no = '001' AND posting_status <> '9' AND
    settlement_period_end_date is NULL AND os.driver_no is not null and os.driver_no !=0 and d.driver_no between '1' and '7999'

    GROUP BY
    o.service_type, order_date, Settlement_Per, o.customer_no, os.driver_no, d.driver_name, d.driver_type, d.report_sort_key) Sub

    GROUP BY
    Branch, Driver_Number, Driver_Name, Driver_Type
    ORDER BY
    Driver_Number

现在我想将日期作为主要查询中的列,但我需要保持日期范围相同(工作天数应该只回顾上周,而主要查询需要回顾一下对于任何追溯输入的订单,几个月。)

我尝试将日常工作查询放入&#34; CASE WHEN&#34;在主查询结束时的语句,它返回了不正确的数据(我认为它排除了那些服务类型注册而不是仅仅通过它们的日子)。我尝试在Main查询的末尾添加一个内部select语句,它将从days_worked到main查询匹配driver_no,并且它需要永远运行。我尝试在主要&#34; FROM&#34;中创建两个不同的查询。声明,一个看着Sub,一个看着days_worked,它返回了太多的记录,而不是我想要的。

将此信息返回到一个查询的最佳方法是什么?顺便说一下,这是在Postgresql 8.1上。谢谢你的帮助。

2 个答案:

答案 0 :(得分:2)

我建议不要将这两个大型查询合并到一个大型查询中。它会不必要地增加复杂性并使调试变得更加困难。

我建议您将两个查询放入存储过程中。您可以从存储过程内查询其他存储过程。这将允许您在较小的查询中使用较大查询的输出,而不会将查询混合在一起的复杂性。

在不知道字段的数据类型的情况下,不可能提供完整的工作示例,但这里粗略估计了如何设置两个存储过程:

CREATE OR REPLACE FUNCTION get_driver_stats (
    _company_no bigint
    ,_start_date text
    ,_end_date text
    ,_posting_status bigint
) RETURNS RECORD (
    Driver_Number
    ,Driver_Name text
    ,Branch text
    ,Driver_Type text
    ,Revenue text
    ,Booking text
    ,Support_Pay text
    ,Fuel text
    ,Settlement text
    ,Stops text
    ,Pieces text
) AS $$
DECLARE vout RECORD;
BEGIN


    SELECT driver_number, 
           driver_name, 
           branch, 
           driver_type, 
           Sum(revenue)                                  AS Revenue, 
           Sum(booking)                                  AS Booking, 
           CASE 
             WHEN Round(Sum(support_pay * settlement_per / 100), 2) != 0 THEN 
             Round(Sum(support_pay * settlement_per / 100), 2) 
           END                                           AS Support_Pay, 
           Round(Sum(fuel * settlement_per / 100), 2)    AS Fuel, 
           Round(Sum(booking * settlement_per / 100), 2) AS Settlement, 
           Sum(stops)                                    AS Stops, 
           Sum(pieces)                                   AS Pieces 
    FROM   (SELECT os.driver_no                   AS Driver_Number, 
                   d.driver_name                  AS Driver_Name, 
                   d.report_sort_key              AS Branch, 
                   ( CASE 
                       WHEN d.driver_type = '0' THEN 'Contractor' 
                       WHEN d.driver_type = '1' THEN 'Employee' 
                     END )                        AS Driver_Type, 
                   Sum(o.rate_bucket1 + o.rate_bucket2 
                       + o.rate_bucket3 + o.rate_bucket4 
                       + o.rate_bucket5 + o.rate_bucket6 
                       + o.rate_bucket7 + o.rate_bucket8 
                       + o.rate_bucket9 + o.rate_bucket10 
                       + o.rate_bucket11)         AS Revenue, 
                   Sum(os.charge1 + os.charge2 + os.charge3 + os.charge4 
                       + os.charge5 + os.charge6) AS Booking, 
                   CASE 
                     WHEN ( o.service_type = '35' ) THEN Sum( 
                     os.charge1 + os.charge2 + os.charge3 + os.charge4 
                     + os.charge5 + os.charge6) 
                   END                            AS Support_Pay, 
                   CASE 
                     WHEN ( o.service_type = '34' ) THEN Sum( 
                     os.charge1 + os.charge2 + os.charge3 + os.charge4 
                     + os.charge5 + os.charge6) 
                   END                            AS Fuel, 
                   os.settlement_percent          AS Settlement_Per, 
                   CASE 
                     WHEN ( o.service_type != '17' 
                             OR o.service_type != '30' 
                             OR o.service_type != '31' 
                             OR o.service_type != '34' 
                             OR o.service_type != '35' 
                             OR o.service_type != '90' 
                             OR o.service_type != '94' 
                             OR o.service_type != '96' 
                             OR o.service_type != '97' 
                             OR o.service_type != '98' 
                             OR o.service_type != '99' ) THEN Count(os.control_no) 
                   END                            AS Stops, 
                   CASE 
                     WHEN ( o.service_type != '17' 
                             OR o.service_type != '30' 
                             OR o.service_type != '31' 
                             OR o.service_type != '34' 
                             OR o.service_type != '35' 
                             OR o.service_type != '90' 
                             OR o.service_type != '94' 
                             OR o.service_type != '96' 
                             OR o.service_type != '97' 
                             OR o.service_type != '98' 
                             OR o.service_type != '99' ) THEN Sum(o.pieces) 
                   END                            AS Pieces 
            FROM   orders o 
                   INNER JOIN order_settlements os 
                           ON o.control_no = os.control_no 
                   INNER JOIN drivers d 
                           ON os.driver_no = d.driver_no 
            WHERE  d.company_no = _company_no 
                   AND order_date BETWEEN _start_date AND _end_date 
                   AND os.company_no = _company_no 
                   AND o.company_no = _company_no 
                   AND posting_status <> _posting_status 
                   AND settlement_period_end_date IS NULL 
                   AND os.driver_no IS NOT NULL 
                   AND os.driver_no != 0 
                   AND d.driver_no BETWEEN '1' AND '7999' 
            GROUP  BY o.service_type, 
                      order_date, 
                      settlement_per, 
                      o.customer_no, 
                      os.driver_no, 
                      d.driver_name, 
                      d.driver_type, 
                      d.report_sort_key) Sub 
    GROUP  BY branch, 
              driver_number, 
              driver_name, 
              driver_type 
    ORDER  BY driver_number 
    INTO vout;

    RETURN vout;


END; $$ LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION get_driver_report (
    _company_no bigint
) RETURNS TABLE (
    driver_no text
) AS $$
    DECLARE vout record;
BEGIN

    RETURN QUERY
    SELECT * 
    FROM   get_driver_stats(_company_no) 
    INTO   vout;SELECT     driver_no, 
               Count(DISTINCT order_date), 
               vout.revenue AS revenue 
    FROM       orders o 
    INNER JOIN order_settlements os 
    ON         o.control_no = os.control_no 
    WHERE      os.company_no = '001' 
    AND        o.service_type NOT IN (17,30, 31, 34, 35, 90, 94, 96, 97, 98, 99) 
    AND        customer_reference != 'PARCEL ADJUSTMENT' 
    AND        order_date BETWEEN (date '2017-6-11' - integer '7') AND        '2017-6-11' 
    AND        posting_status <> '9' 
    AND        settlement_period_end_date IS NULL 
    GROUP BY   driver_no;

END; $$ LANGUAGE plpgsql;

这里的关键是你可以将较大查询的输出(现在存储过程get_driver_stats)存储到变量vout中并使用它来完成较小的查询(现在在存储过程get_driver_report)。

在上面的示例中,我假设get_driver_stats返回单个记录。这可能是准确的,也可能是不准确的。

答案 1 :(得分:1)

查询很重要。必须有一些方法将它们分成更小的子查询。至少更好地格式化它们会有所帮助。以下可能有效(没有数据或工作示例,这当然很难测试):

SELECT a.*, b.days_worked FROM (
    SELECT driver_number, 
        driver_name, 
        branch, 
        driver_type, 
        SUM(revenue)                                  AS Revenue, 
        SUM(booking)                                  AS Booking, 
        CASE 
            WHEN Round(SUM(support_pay * settlement_per / 100), 2) != 0 THEN 
            Round(SUM(support_pay * settlement_per / 100), 2) 
        END                                           AS Support_Pay, 
        Round(SUM(fuel * settlement_per / 100), 2)    AS Fuel, 
        Round(SUM(booking * settlement_per / 100), 2) AS Settlement, 
        SUM(stops)                                    AS Stops, 
        SUM(pieces)                                   AS Pieces
    FROM   (SELECT os.driver_no                   AS Driver_Number, 
                d.driver_name                  AS Driver_Name, 
                d.report_sort_key              AS Branch, 
                ( CASE 
                    WHEN d.driver_type = '0' THEN 'Contractor' 
                    WHEN d.driver_type = '1' THEN 'Employee' 
                    END )                        AS Driver_Type, 
                SUM(o.rate_bucket1 + o.rate_bucket2 
                    + o.rate_bucket3 + o.rate_bucket4 
                    + o.rate_bucket5 + o.rate_bucket6 
                    + o.rate_bucket7 + o.rate_bucket8 
                    + o.rate_bucket9 + o.rate_bucket10 
                    + o.rate_bucket11)         AS Revenue, 
                SUM(os.charge1 + os.charge2 + os.charge3 + os.charge4 
                    + os.charge5 + os.charge6) AS Booking, 
                CASE 
                    WHEN ( o.service_type = '35' ) THEN SUM( 
                    os.charge1 + os.charge2 + os.charge3 + os.charge4 
                    + os.charge5 + os.charge6) 
                END                            AS Support_Pay, 
                CASE 
                    WHEN ( o.service_type = '34' ) THEN SUM( 
                    os.charge1 + os.charge2 + os.charge3 + os.charge4 
                    + os.charge5 + os.charge6) 
                END                            AS Fuel, 
                os.settlement_percent          AS Settlement_Per, 
                CASE 
                    WHEN ( o.service_type != '17' 
                            OR o.service_type != '30' 
                            OR o.service_type != '31' 
                            OR o.service_type != '34' 
                            OR o.service_type != '35' 
                            OR o.service_type != '90' 
                            OR o.service_type != '94' 
                            OR o.service_type != '96' 
                            OR o.service_type != '97' 
                            OR o.service_type != '98' 
                            OR o.service_type != '99' ) THEN Count(os.control_no) 
                END                            AS Stops, 
                CASE 
                    WHEN ( o.service_type != '17' 
                            OR o.service_type != '30' 
                            OR o.service_type != '31' 
                            OR o.service_type != '34' 
                            OR o.service_type != '35' 
                            OR o.service_type != '90' 
                            OR o.service_type != '94' 
                            OR o.service_type != '96' 
                            OR o.service_type != '97' 
                            OR o.service_type != '98' 
                            OR o.service_type != '99' ) THEN SUM(o.pieces) 
                END                            AS Pieces 
            FROM   orders o 
                inner join order_settlements os 
                        ON o.control_no = os.control_no 
                inner join drivers d 
                        ON os.driver_no = d.driver_no 
            WHERE  d.company_no = '001' 
                AND order_date BETWEEN '2017-4-9' AND '2017-6-11' 
                AND os.company_no = '001' 
                AND o.company_no = '001' 
                AND posting_status <> '9' 
                AND settlement_period_end_date IS NULL 
                AND os.driver_no IS NOT NULL 
                AND os.driver_no != 0 
                AND d.driver_no BETWEEN '1' AND '7999' 
            GROUP  BY o.service_type, 
                    order_date, 
                    settlement_per, 
                    o.customer_no, 
                    os.driver_no, 
                    d.driver_name, 
                    d.driver_type, 
                    d.report_sort_key) Sub 
    GROUP  BY branch, 
            driver_number, 
            driver_name, 
            driver_type 
    ORDER  BY driver_number 
) a JOIN (
    SELECT     driver_no, 
            Count(DISTINCT order_date) as days_worked 
    FROM       orders o 
    inner join order_settlements os 
    ON         o.control_no = os.control_no 
    WHERE      os.company_no = '001' 
    AND        o.service_type NOT IN (17, 
                                    30, 
                                    31, 
                                    34, 
                                    35, 
                                    90, 
                                    94, 
                                    96, 
                                    97, 
                                    98, 
                                    99) 
    AND        customer_reference != 'PARCEL ADJUSTMENT' 
    AND        order_date BETWEEN (DATE '2017-6-11' - INTEGER '7') AND        '2017-6-11' 
    AND        posting_status <> '9' 
    AND        settlement_period_end_date IS NULL 
    GROUP BY   driver_no
) b ON (a.driver_number = b.driver_no) ;