简体   繁体   English

结合两个Postgresql查询

[英]Combining two Postgresql queries

I have this query that returns how many days a driver worked based on driver number. 我有这个查询,它根据驱动程序编号返回驱动程序工作的天数。 The way I check for days worked is just to count distinct order_date with their driver number on it. 我检查工作天数的方法就是计算不同的order_date及其驱动程序编号。 Let's call it days worked: 我们称之为工作日:

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

And I have this query that calculates how much the driver earned, how much he delivered, etc. Let's call it main: 我有这个查询来计算司机赚了多少钱,交付了多少等等。让我们称之为主要:

    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

Now I want to put the days worked as a column in the main query, but I need to keep the date ranges the same (days worked should only look back at the last week, whereas the main query needs to look back for a couple months for any orders that got entered retroactively). 现在我想把日期作为主要查询中的列,但我需要保持日期范围相同(工作天数应该只回顾上周,而主要查询需要回顾几个月对于任何追溯输入的订单)。

I tried putting the days worked query into a "CASE WHEN" statement at the end of the main query, and it returned incorrect data (I think it was excluding any days where those service types registered instead of just passing over them). 我尝试在主查询结束时将日期工作查询放入“CASE WHEN”语句,并返回不正确的数据(我认为它排除了这些服务类型注册的任何日期而不是仅仅通过它们)。 I tried putting an inner select statement at the end of the Main query where it would match driver_no from days_worked to main query and it took forever to run. 我尝试在Main查询的末尾添加一个内部select语句,它将从days_worked到main查询匹配driver_no,并且它需要永远运行。 I tried creating two different queries in the main "FROM" statement, one looking at the Sub and one looking at days_worked, and it returned way too many records and not how I wanted at all. 我尝试在主“FROM”语句中创建两个不同的查询,一个查看Sub,一个查看days_worked,它返回了太多记录,而不是我想要的。

What's the best way to get this information returned into one query? 将此信息返回到一个查询的最佳方法是什么? This is on Postgresql 8.1 by the way. 顺便说一下,这是在Postgresql 8.1上。 Thanks for all your help. 感谢你的帮助。

I would advise against combining both of those large queries into one mega query. 我建议不要将这两个大型查询合并到一个大型查询中。 It'll unnecessarily add complexity and make debugging more difficult. 它会不必要地增加复杂性并使调试变得更加困难。

I'd suggest that you put your two queries into stored procedures. 我建议您将两个查询放入存储过程中。 You can query other stored procedures from inside a stored procedure. 您可以从存储过程内查询其他存储过程。 This will allow you to use the output from your larger query in your smaller query without the complexity of mashing the queries together. 这将允许您在较小的查询中使用较大查询的输出,而不会将查询混合在一起的复杂性。

Without knowing the data types of your fields, it's not possible to give a full working example, but here is a rough approximation of how you would setup the two stored procedures: 在不知道字段的数据类型的情况下,不可能提供完整的工作示例,但这里是对如何设置两个存储过程的粗略近似:

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;

The key here is that you can store the output of your larger query (now in the stored procedure get_driver_stats ) into the variable vout and use it to complete the your smaller query (now in the stored procedure get_driver_report ). 这里的关键是,你可以(在存储过程现在存储您的较大查询的输出get_driver_stats )为变量vout和(在存储过程中现在使用它来完成你的小查询get_driver_report )。

In my example above, I am assume that get_driver_stats returns a single record. 在上面的例子中,我假设get_driver_stats返回一条记录。 This may or may not be accurate. 这可能是也可能不准确。

The queries are way to big. 查询是大的。 There must be some ways to split them up into smaller subqueries. 必须有一些方法将它们分成更小的子查询。 At least formatting them better would help. 至少更好地格式化它们会有所帮助。 The following might work (with no data or working example this is, of course, hard to test): 以下可能有效(没有数据或工作示例,这当然很难测试):

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) ;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM