[pgsql-jp: 29259] Re: SQL文の SELECT について

Naofumi Kondoh nkon @ shonan.ne.jp
2003年 3月 2日 (日) 03:35:42 JST


ソフト工房の近藤です。こんばんは。

naoki kishida wrote:
> きしだです
> 
> 
>>私たちのチームでは、SELECT * FROM 〜 を使うのも禁止しています。

本運用のプログラムで、SELECT * FROM を禁止するのは当然です。

...略...

> 「select * from 〜」としていたために、列を追加したときにその列を利用しな
> いのにプログラムを変更する必要がある、という事態に遭遇したことがないので
> すが、どういった場合にそうなるのでしょうか?

EMBEDED SQL で、ホスト変数を使っている場合は、SELECT
された列数とホスト変数の数が合わないのでエラーになり
ます。というか、EMBEDED SQL では、SELECT * なんて書き
ません。

最近の PHP などの言語は便利にできているので、SELECT *
でも結構動くと思いますが、それがあだになってなかなか
気づきにくいとんでもないバグになる場合もあります。

簡単な例をひとつ。

CREATE TABLE atab(aid integer, name text, mnt timestamp);
CREATE TABLE btab(bid integer, price integer);

$dbcon = pg_connect('dbname=test') or die("");
$exeid = pg_exec($dbcon, 'select * from atab inner join btab on ( aid = bid ); ') or die("");
$excnt = pg_numrows($exeid);
for($ii=0; $ii<$excnt; ++$ii){
    $r = pg_fetch_object($exeid, $ii);
    echo "{$r->aid} : {$r->name} : {$r->mnt} : {$r->price} <br>\n";
}
このプログラムは、この時点では正しい出力を出します。

問題になるのは、表 atab の列名と同じ名の列名を別の表 btab
に追加した場合です。

ALTER TABLE btab ADD COLUMN mnt timestamp;

SELECT * FROM と書くと、同じ名の列名 mnt が2つ出現するので、
 {$r->mnt} がどちらの表の mnt かわからなくなります。しかも、
PHP では、エラーにならずに動いてしまうので、なかなか気が付
かずに、とんでもない バグ となって大問題になる可能性もあ
ります。(環境 PHP 4.2.1 + PostgreSQL 7.3 )。

やはり、基本にかえって、SELECT * は、本運用のプログラム
では、禁止して、次のように書くべきです。

$exeid = pg_exec($dbcon,
  'SELECT
        atab.aid,
        atab.name,
        atab.mnt     AS a_mnt,
        btab.price
    FROM atab INNER JOIN btab ON ( aid = bid ); ') or die("");
$excnt = pg_numrows($exeid);
for($ii=0; $ii<$excnt; ++$ii){
    $r = pg_fetch_object($exeid, $ii);
    echo "{$r->aid} : {$r->name} : {$r->a_mnt} : {$r->price} <br>\n";
}

_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
 (株)ソフト工房   近藤直文        Email:  nkon @ shonan.ne.jp
http://www.SOFTKOUBOU.co.jp/      http://www.shonan.ne.jp/~nkon/
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/





pgsql-jp メーリングリストの案内