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 つのテーブルからデータを取得し、それを 1 つのレポートに出力する必要があります。レポートは次のようになります。

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>";
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

dist_idどちらのテーブルにもインデックスがないため、結合が非常に遅くなります。dist_id にインデックスを追加して、どれだけ改善されるかを確認してください。

また、ループ内のそのクエリは、非常に多くのクエリを実行するため、あなたの死です。内部クエリをメイン クエリに組み込み、データベースで 1 つのクエリのみを実行します。

于 2012-12-18T17:09:07.270 に答える
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 に答える