我有这个查询,它根据驱动程序编号返回驱动程序工作的天数。我检查工作天数的方法就是计算不同的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上。谢谢你的帮助。
答案 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) ;