1

要求的表定义

                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、路由、类型和计数(*)以及从表 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>";
4

3 回答 3

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
于 2012-12-18T17:03:12.353 回答
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 注入的影响。尝试使用参数化查询

于 2012-12-18T16:48:24.517 回答
1

您在任何一个表中都没有任何索引dist_id,这将使您的连接非常缓慢。在 dist_id 上添加索引,看看它改进了多少。

此外,循环内的查询将是您的死亡,因为您将执行很多很多查询。将内部查询工作到您的主查询中,这样您就只在数据库中执行一个查询。

于 2012-12-18T17:09:07.270 回答