致力于构建一个php文件以创建一个JSON,以便在Web应用程序中使用,以跟踪特定运输路线的运输利润。目标是拥有一组数据,我可以将这些数据插入与公司合作的每个客户的下拉列表中,以跟踪每个客户的运输路线的平均收入和利润。从本质上讲,我需要查询过去两年中每个客户的清单,卡车的组合目的地/原点/类型,然后显示利润,收入和符合较早条件的发货数量的平均值。
我正在使用PHP 7,phpMyAdmin。
$currentDate = date('Y-m-d');
$twoYearsAgo = Date('Y-m-01', strtotime($currentDate . " -2 years + 1 month"));
$customers = "SELECT DISTINCT customer_name FROM `wo_main_alldata` WHERE ship_date BETWEEN '$twoYearsAgo' AND '$currentDate'";
$customerResult = mysqli_query($conn, $customers);
$customerList= array();
while ($row = mysqli_fetch_array($customerResult)) {
$customerList[] = $row[0];
}
$lanesArray = array();
foreach ($customerList as $customerName){
$laneData = "SELECT DISTINCT type_of_shipment, pickup_city, pickup_state, consignee_city, consignee_state
FROM wo_main_alldata
WHERE customer_name = '$customerName'
AND pickup_city != ''";
$lanesResult = mysqli_query($conn, $laneData);
while ($row2 = mysqli_fetch_array($lanesResult)){
$equipment = $row2[0];
$pu_city = $row2[1];
$pu_state = $row2[2];
$dest_city = $row2[3];
$dest_state = $row2[4];
$laneAverages = "SELECT AVG(proj_revenue), AVG(proj_gross_profit), COUNT(pro_num) FROM wo_main_alldata WHERE type_of_shipment = '$equipment' AND pickup_city = '$pu_city' AND pickup_state = '$pu_state' AND consignee_city = '$dest_city' AND consignee_state = '$dest_state'";
$lanesAverageResult = mysqli_query($conn, $laneAverages);
while ($row3 = mysqli_fetch_array($lanesAverageResult)){
}
mysqli_free_result($lanesAverageResult);
}
}
我还没有实现将数据推送到数组以进行输出的详细信息,但是就目前而言,由于在过去的两个客户中有2000多个运输路线,该文件可能需要10分钟才能完成处理年。
有什么方法可以更快地制作这种瓶坯?
编辑:我知道我需要使用准备好的语句,因为现在所有这些操作都是在本地完成的,而我只是在尝试优化运行时间。
编辑2:解决方案!
SELECT customer_name, type_of_shipment, pickup_city, pickup_state, consignee_city, consignee_state, AVG( proj_revenue ) , AVG( proj_gross_profit ) , COUNT( pro_num )
FROM wo_main_alldata
WHERE ship_date
BETWEEN '$twoYearsAgo'
AND '$currentDate'
AND pickup_city != ''
GROUP BY customer_name, type_of_shipment, pickup_city, pickup_state, consignee_city, consignee_state
答案 0 :(得分:4)
我真的很犹豫发布答案,因为此处的SQL导致您在PHP中所做的各种额外工作。没有数据库模式和一些示例数据,我感觉我只是在盲目地这样做。例如,DISTINCT
这些东西在这里做什么,也许它们是必需的,也许它们是多余的……我无从得知。
这就是这里
这些都是相同的表,因此再次查询相同的数据是没有意义的,例如以这两个查询为例
$customers = "SELECT DISTINCT customer_name FROM `wo_main_alldata` WHERE ship_date BETWEEN '$twoYearsAgo' AND '$currentDate'";
$laneData = "SELECT DISTINCT type_of_shipment, pickup_city, pickup_state, consignee_city, consignee_state
FROM wo_main_alldata
WHERE customer_name = '$customerName'
AND pickup_city != ''";
您可以将它们与以下内容组合:
$laneData = "SELECT DISTINCT
customer_name, -- From the first query
type_of_shipment,
pickup_city,
pickup_state,
consignee_city,
consignee_state
FROM
wo_main_alldata
WHERE
ship_date BETWEEN '$twoYearsAgo' AND '$currentDate'
AND
pickup_city != ''
";
第一个查询提取所有“不同”的客户名称,然后循环遍历并使用该名称在同一表中查找下一组数据。
此查找将使您在拳头中使用的独特字符无效,但是(是)您也可以在此处使用它。它之所以无效,是因为第二个查询说:“给我所有记录,其中customer_name =某物”,因此,如果该名称重复存在,则会在第二个查询中找到所有这些记录。当它们分开时,控制foreach ($customerList as $customerName){
循环可能很重要。但是,我们不再需要该循环。
当我们将它们组合在一起时,我们将customer_name
添加到第二个选择中,同时还添加了WHERE
位。然后,我们就可以消除将这些customer_name = '$customerName'
捆绑在一起的条件因为当它变成customer_name=customer_name
时就不再需要它了,它只是“此行”。
现在看起来还不干净。它还消除了所有这些代码:
$customers = "SELECT DISTINCT customer_name FROM `wo_main_alldata` WHERE ship_date BETWEEN '$twoYearsAgo' AND '$currentDate'";
$customerResult = mysqli_query($conn, $customers);
$customerList= array();
while ($row = mysqli_fetch_array($customerResult)) {
$customerList[] = $row[0];
}
$lanesArray = array();
foreach ($customerList as $customerName){
$laneData = "SELECT DISTINCT type_of_shipment, pickup_city, pickup_state, consignee_city, consignee_state
FROM wo_main_alldata
WHERE customer_name = '$customerName'
AND pickup_city != ''";
两个都从同一个表中选择数据,第二个(在循环中)只是从第一个查询中获取用户名,然后在同一表中再次查找它。
对于最后一个查询,您(再次)只是回引用相同的数据
$equipment = $row2[0]; //from previous query on same table
WHERE type_of_shipment = '$equipment'
where条件中的所有内容直接来自另一个查询的结果,因此您可以消除它。剩下的就是这个:
SELECT
AVG(f.proj_revenue),
AVG(f.proj_gross_profit),
COUNT(f.pro_num)
FROM (
SELECT DISTINCT
customer_name,
type_of_shipment,
pickup_city,
pickup_state,
consignee_city,
consignee_state
FROM
wo_main_alldata
WHERE
ship_date BETWEEN '$twoYearsAgo' AND '$currentDate' -- From the first query
AND
pickup_city != ''
) as f
我无法真正测试一下,因此您可能需要进行一些调整,尽管有点逻辑,但我还是有点感觉。我很确定顶级查询中的列也必须在内部子查询中。特别是f.proj_revenue
,f.proj_gross_profit
和f.pro_num
。可能您会得到类似Unknown column 'f.proj_gross_profit' in 'field list'
有几种方法可以通过再次加入表格来解决此问题。
SELECT
AVG(m.proj_revenue),
AVG(m.proj_gross_profit),
COUNT(m.pro_num)
FROM
wo_main_alldata AS m
JOIN
(
SELECT DISTINCT
id, //<--- id is an issue
customer_name,
type_of_shipment,
pickup_city,
pickup_state,
consignee_city,
consignee_state
FROM
wo_main_alldata
JOIN
WHERE
ship_date BETWEEN '$twoYearsAgo' AND '$currentDate'
AND
pickup_city != ''
) as f
ON f.id = m.id
我真的不确定最好的解决方法,因为我不知道什么必须与众不同。这确实使它复杂化,因为如果您按上述方式放置ID,则可能因每行唯一而使Distinct呼叫中毒。您也许可以在一个查询中完成所有操作:
SELECT DISTINCT
customer_name,
type_of_shipment,
pickup_city,
pickup_state,
consignee_city,
consignee_state,
AVG(m.proj_revenue),
AVG(m.proj_gross_profit),
COUNT(m.pro_num)
FROM
wo_main_alldata
WHERE
ship_date BETWEEN '$twoYearsAgo' AND '$currentDate'
AND
pickup_city != ''
但是我说的太抽象了。不要害怕采用PHPmyAdmin(或您用来管理数据库的任何东西)并在那里直接进行查询。这样一来,您就可以在任何编码之外使用它,并以您想要的方式获得它。
在任何情况下,如果您发现自己来回访问DB以获得相同的数据机会,则可以在一个稍微复杂一些的查询中进行。如果您不太了解SQL,但在PHP上可以执行简单查询并在PHP中进行处理,这是很诱人的。
乍一看,这似乎是“简单”的方法,但是您可以让数据库完成的每一项工作都可以用PHP节省2到3项工作。您的代码将更小,更轻,更简单,更易于阅读。例如(假设您可以按照建议将它们组合),您的代码将变为:
$lanesAverageResult = mysqli_query($conn, $laneAverages); //our new query
while ($row3 = mysqli_fetch_array($lanesAverageResult)){
}
因此,我们只删除了25+
行PHP,而使用了稍微复杂一些的查询。
PS 对不起,这很久了。
希望有帮助!
答案 1 :(得分:2)
耗时很长的主要原因之一是因为它对数据库进行了大量单独的调用。据我了解,在某些情况下,每个客户要进行2000多个单独的SQL查询。您将要考虑使用子查询和/或联接将其压缩。
https://www.guru99.com/sub-queries.html
修改 使用子查询来压缩获取每个客户的运输路线的示例将是这样的。 (未经测试的查询,但它给出了有关如何实现子查询的粗略思路)
SELECT AVG(final.proj_revenue), AVG(final.proj_gross_profit), COUNT(final.pro_num) FROM
(SELECT proj_revenue, proj_gross_profit, pro_num FROM
(SELECT DISTINCT
type_of_shipment, pickup_city, pickup_state, consignee_city, consignee_state
FROM wo_main_alldata WHERE customer_name = '$customername' AND pickup_city != ''
) as subquery
WHERE type_of_shipment = subquery.type_of_shipment
AND pickup_city = subquery.pickup_city
AND pickup_state = subquery.pickup_state
AND consignee_city = subquery.consignee_city
AND consignee_state = subquery.consignee_state
) as final