2017-06-16 143 views
1

我有这个查询返回一个驱动程序基于驱动程序编号工作多少天。我检查工作天数的方法是计算不同的order_date及其驱动程序编号。让我们把它叫做天的工作:结合两个PostgreSQL查询

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 

现在我希望把这些日子在主查询中作为一个列工作,但我需要保持日期范围相同(工作天应该只回顾上一周,而主查询需要回顾几个月以获取任何获得的订单追溯地输入)。

我试着把查询的日子放到主查询末尾的“CASE WHEN”语句中,并且它返回了不正确的数据(我认为它不包括任何那些注册这些服务类型的日子,而不是仅仅传递它们)。我试着在Main查询的末尾放置一个内部select语句,它将driver_no从days_worked匹配到主要查询,并且永久运行。我试图在主要的“FROM”语句中创建两个不同的查询,一个查看Sub,一个查看days_worked,它返回的方式太多记录,而不是我想要的。

将这些信息返回到一个查询中的最佳方式是什么?顺便说一下,这在Postgresql 8.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) ; 
+1

工作正常!你们太棒了。 也许你是对的,查询太大,但我只是想把它所有的数据返回到一个地方。它只能成为11列,这只是一种复杂的方式。 – Emac

+1

@Emac BTW:一堆条件o.service_type!='17'或o.service_type!='30'...'可以替换为o.service_type!= any(数组[17,30,31 ,34,35,90,94,96,97,98,99])'(但是检查表演) – Abelisto

+0

感谢您的提示Abelisto!我从来没有想过把它们放入数组中。在我的“Days Worked”查询中,我实际上使用“o.service_type not in(17,30,31,34,35,90,94,96,97,98,99)”,但是当我编写第一个查询,我不知道这一点,并列出了大量冗余的“或”声明中的每一种类型。所以至少我自第一次查询以来做了一些改进。 – Emac

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返回一条记录。这可能会也可能不准确。