要求的表格定义
Table "public.call_record"
Column | Type | Modifiers
-----------------+------------------------+---------------
cntrct_id | character varying(15) | not null
call_regard | text |
port_type | character varying(9) |
inst | text |
info_taken | character varying(40) |
log_date | date | not null
log_time | time without time zone | not null
act_taken | text |
use_material | text |
targ_pest | integer |
work_comp_by | text |
emp_no | integer |
comp_date | date |
job_start_time | time without time zone |
job_leave_time | time without time zone |
comp_val | boolean | default false
fti_call_regd | public.tsvector |
fti_inst | public.tsvector |
fti_act_take | public.tsvector |
route | character(3) |
act_port | text |
targ_pest_opt | text |
call_regard_opt | text |
targpest_other | text |
date_sched | date |
custord_num | integer |
dist_id | integer |
phone_slot | integer | default 0
Indexes:
"call_record_pkey" PRIMARY KEY, btree (cntrct_id, log_date, log_time)
"route_index" hash (route)
Check constraints:
"call_record_targ_pest_check" CHECK (targ_pest <= 100)
"call_record_targ_pest_check1" CHECK (targ_pest >= 0)
Table "public.per_call"
Column | Type | Modifiers
---------+----------------------+-----------
dist_id | character varying(2) |
route | character varying(2) |
type | character(1) |
total | integer |
我需要从2个表中获取数据并将其打印在一个报告中。该报告应如下所示:
district | route | type | total | callbacks
| 01 | T | 12 | 5
| 02 | P | 0 | 0
| 03 | P | 3 | 1
2 | 01 | T | 4 | 1
| 02 | T | 1 | 0
| 03 | P | 0 | 0
etc... (this is theoretical sample data)
所以,实质上我需要从表per_call中获取dist_id,route,type和count(*) 和call_record表中的call_backs计数
问题:循环遍历表格使得它变得非常缓慢。如何调整以下PSQL查询,以便我不必循环,我可以正确回显表格数据?
如果有任何不透明的情况,请告诉我,我会尽力澄清
echo '<table align="center" border = 2>
<th>DISTRICT</th>
<th>ROUTE</th>
<th>TYPE</th>
<th>TOTAL</th>
<th>CALL BACKS</th>';
$SQL = " SELECT per_call.dist_id, per_call.route, per_call.type, per_call.total
FROM per_call, call_record
WHERE TRUE ";
if($type == 'termite'){
$SQL = $SQL." AND per_call.type = 'T' ";
}
else{
$SQL = $SQL." AND per_call.type = 'P' ";
}
$SQL = $SQL." AND call_record.dist_id = per_call.dist_id
AND call_record.log_date >= '$startDate'
AND call_record.log_date <= '$endDate'
ORDER BY per_call.dist_id, per_call.route, per_call.type ASC ";
echo $SQL;
/*AND call_record.log_date = '$startDate'
AND call_record.log_date = '$endDate'*/
$Q = pg_query($connect,$SQL);
while($row = pg_fetch_row($Q)){
$dist = $row[0];
$route = $row[1];
$type = $row[2];
$total = $row[3];
echo '<tr>';
echo '<td align="center">'.$dist.'</td>';
echo '<td align="center">'.$route.'</td>';
echo '<td align="center">'.$type.'</td>';
echo '<td align="center">'.$total.'</td>';
$SQL2 = "SELECT COUNT(*)
FROM call_record
WHERE dist_id = $dist
AND route = '$route'
AND substring(cntrct_id from 2 for 1) = '$type'
AND substring(call_regard_opt from 2 for 1) = '1'
";
$Q2 = pg_query($connect,$SQL2);
$row2 = pg_fetch_row($Q2);
$callbacks = $row2[0];
echo '<td align="center">'.$callbacks.'</td>';
echo '</tr>';
}
echo "</table>";
答案 0 :(得分:2)
select pc.dist_id, pc.route, pc.type, pc.total,
count(
substring(cntrct_id from 2 for 1) = '$type'
AND substring(call_regard_opt from 2 for 1) = '1'
or null
) callbacks
from
per_call pc
inner join
call_record cr on cr.dist_id = pc.dist_id
where cr.log_date between '$startdate' and cr.log_date <= '$enddate'
group by pc.dist_id, pc.route, pc.type, pc.total
order by pc.dist_id, pc.route, pc.type asc
答案 1 :(得分:1)
除非索引问题,否则您的查询写得不好,因此从查询表单的角度来看,它无法真正优化。你可以这样做虽然更干净:
$SQL = "SELECT per_call.dist_id, per_call.route, per_call.type, per_call.total
FROM per_call, call_record
WHERE call_record.dist_id = per_call.dist_id
AND per_call.type = '".($type == 'termite' ? "T" : "P")."'
AND call_record.log_date >= '$startDate'
AND call_record.log_date <= '$endDate'
ORDER BY per_call.dist_id, per_call.route, per_call.type"
无论如何,这仍然容易受到SQL注入攻击。尝试使用parameterized queries。
答案 2 :(得分:1)
在任一表中dist_id
上都没有任何索引,这会使您的加入速度变慢。在dist_id上添加索引,看看它有多大改进。
此外,循环中的查询将是您的死亡,因为您将要做很多很多查询。将内部查询处理到主查询中,以便只在数据库中执行一个查询。