SQL開発者が、機能するプロシージャに別の形式を提案するのはなぜですか?
これは美しく機能する私のオリジナルの手順です:
create or replace PROCEDURE EXTRACT_0_CPP AS
CURSOR c_data IS
SELECT cpp,
rfu1,
rfu2,
mean_rfu,
charge_ph7_4,
hydropathy
FROM cpp
ORDER BY LENGTH(cpp);
F1 UTL_FILE.FILE_TYPE;
BEGIN
F1 := UTL_FILE.FOPEN( location => 'EXTRACT_DIR',
filename => '0_cpp.TXT',
open_mode => 'w',
max_linesize => 32767);
FOR cur_rec IN c_data LOOP
UTL_FILE.PUT_LINE (F1,
cur_rec.cpp || ':' ||
cur_rec.rfu1 || ':' ||
cur_rec.rfu2 || ':' ||
cur_rec.mean_rfu || ':' ||
cur_rec.charge_ph7_4 || ':' ||
cur_rec.hydropathy);
END LOOP;
UTL_FILE.FCLOSE(F1);
END;
しかし、SQL Developerは下に波線の赤い線を表示しSELECT
、これに変更することを提案します。
create or replace PROCEDURE EXTRACT_0_CPP AS
CURSOR c_data IS
SELECT
"A1"."CPP" "CPP",
"A1"."RFU1" "RFU1",
"A1"."RFU2" "RFU2",
"A1"."MEAN_RFU" "MEAN_RFU",
"A1"."CHARGE_PH7_4" "CHARGE_PH7_4",
"A1"."HYDROPATHY" "HYDROPATHY"
FROM
"C##ELLIE"."CPP" "A1"
ORDER BY
length("A1"."CPP");
F1 UTL_FILE.FILE_TYPE;
BEGIN
F1 := UTL_FILE.FOPEN( location => 'EXTRACT_DIR',
filename => '0_cpp.TXT',
open_mode => 'w',
max_linesize => 32767);
FOR cur_rec IN c_data LOOP
UTL_FILE.PUT_LINE (F1,
cur_rec.pk_cpp || ':' ||
cur_rec.rfu1 || ':' ||
cur_rec.rfu2 || ':' ||
cur_rec.mean_rfu || ':' ||
cur_rec.charge_ph7_4 || ':' ||
cur_rec.hydropathy);
END LOOP;
UTL_FILE.FCLOSE(F1);
END;
私の質問は(なぜ)これが良いのですか?「A1」とは?
回答
A1
テーブルのエイリアスです "C##ELLIE"."CPP"
手順は同じですが、あなたとOracleは、テーブルcppがどのスキーマに属しているかも知っています。
さらに、手順の内容についてコメントを追加する必要があります。3年後に戻ってきた場合は、使用したスキーマとその目的を簡単に知ることができます。
コードがすでに機能しているときに別の形式を提案する理由については、もちろん、機能するコードの形式が不十分である可能性があるため、原則として、レイアウトやリファクタリングの改善を検討する必要がない理由はありません。コードをより堅牢、効率的、または保守しやすくします。
ただし、二重引用符で囲まれた名前は、名前の誤りを隠し、大文字/小文字を指定する必要があり、結果が元の名前よりも読みにくくなるため、お勧めできません。これらは実際には、奇妙なテーブル名を持つサードパーティアプリケーションで使用するための移植性機能です。コードジェネレーターは、それぞれの場合に実際に必要かどうかを検出するよりも簡単であるため、すべてを二重引用符で囲む傾向があります。その方法はありません
from "C##ELLIE"."CPP" "A1"
のあらゆる種類の改善です
from cpp
おそらくテーブルエイリアスの使用を除いて。テーブルにエイリアス(二重引用符なし!)を付けて、列を参照するときに使用することをお勧めします。しかし"A1"
(またはa1
)は、コンピューターだけが夢見るような種類のテーブルエイリアスです。おそらくこの場合、テーブル名のある種の省略形であるエイリアスを使用する方がはるかに良いでしょうc
。6つのテーブルを結合していると想像してみてくださいa3
。そうそう、そうですORDER_DETAILS
。(ただし、この場合、テーブル名は非常に短いため、エイリアスを作成する意味はありません。)したがって、
SELECT "A1"."CPP" "CPP"
FROM "C##ELLIE"."CPP" "A1"
ちょうどとしてはるかに良いでしょう
SELECT c.cpp
FROM cpp c
(これは1974年ではなく、エディターが色と太字を使用して言語キーワードを強調表示しているため、小文字にしますが、それは手放します。)
スキーマ名のハードコーディングは、せいぜい冗長であるため(オブジェクトは既に作業しているスキーマ内にあるため、不必要な複雑さ以外は何も追加されないため)、さらに悪いことに、移植性が制限されます(スキーマの名前を変更したり、コードを移動したりした場合)。ハードコードされた参照をクリーンアップする必要があります)。
これは賢い機能だと思いますが、この場合は良いアドバイスではありません。
これは、オブジェクト名を二重引用符で囲むことの問題点のデモです。各コマンドを注意深く読み、引用符で囲まれたテーブル名と引用符で囲まれていないテーブル名の大文字と小文字の区別に注意してください。
SQL> create table test_table_1 (dob date);
Table created.
SQL> create table "test_table_2" ("dob" date);
Table created.
SQL> select * from test_table_1;
no rows selected
SQL> select * from test_table_2;
select * from test_table_2
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> select * from "test_table_2";
no rows selected
SQL>
SQL> select table_name
2 from user_tables
3 where upper(table_name) like 'TEST_TABLE%'
4 order by table_name;
TABLE_NAME
--------------------------------------------------------------------------------
TEST_TABLE_1
test_table_2
2 rows selected.
SQL>
SQL> drop table test_table_1;
Table dropped.
SQL> drop table test_table_2;
drop table test_table_2
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> drop table "test_table_2";
Table dropped.
SQL> --
SQL> spo off
私はおそらくあなたのコードのためにこれをお勧めします:
...
CURSOR c_data IS
SELECT c.cpp,
c.rfu1,
c.rfu2,
c.mean_rfu,
c.charge_ph7_4,
c.hydropathy
FROM cpp c
ORDER BY LENGTH(c.cpp);
...
1つのテーブル/ビューのみを使用しているcpp
ため、エイリアスを作成する必要はありませんが、将来、このクエリに別のテーブルが追加された場合に役立ちます。
特に2つ以上のテーブルクエリでは、SELECTの名前が完全に修飾されていない場合(列名の前にテーブル名またはエイリアスを記載)、別の列の別の列と同じ名前の列がテーブルに追加されると、クエリが中断する可能性がありますテーブル:
PersonTable: id, name, status, addressid
AddressTable id, street
--this is ok for now
SELECT name, status, street FROM person INNER JOIN street ON person.addressid = address.id
ステータス列をアドレスに追加すると、あいまいになったため、上記のクエリは失敗します。この種の問題を引き起こす列を追加しても、DBは「追加しましたが、スキーマと依存システム全体の他のすべてのクエリは失敗します」とアナウンスすることはありません。見つける必要があるだけです。テストによって失敗したクエリ。または顧客が不満を言っている;)
完全修飾した場合:
SELECT
person.name,
person.status,
address.street
FROM
person
INNER JOIN adress a ON person.addressid = address.id
それは働き続けるでしょう。
列でテーブル名を繰り返すのは少し面倒で言葉が多いです。短い名前を使用すると、読みやすさが向上するだけではありません。
SELECT
p.name,
p.status,
a.street
FROM
person p
INNER JOIN address a ON p.addressid = a.id
..しかし、心理的には、さまざまな理由でテーブルを複数回結合できることを思い出させてくれます。
SELECT
p.name,
p.status,
a_work.street as workstreet,
a_home.street as homestreet
FROM
person p
INNER JOIN address a_work ON p.work_addressid = a.id --note, i've silently upgraded Person here to track two addresses
INNER JOIN address a_home ON p.home_addressid = a.id
全体として、SQLDeveloperは、次のような良識に向かって進んでいるという点で、ここで良いことをしようとしています。
- テーブルに、わかりやすく、読みやすく、状況に応じたエイリアスを与える
- 列名は常にエイリアスで完全修飾してください
それが落ちているところは:
- それ
A1
はあなたが何も覚えるのを助けないがらくたエイリアス名を選んでいます。私がp
人とa
住所のために選んだのは偶然ではありません、あなたが感謝できると確信しています。パーティー、そしてプロジェクトがあった場合は、私が使用する可能性がありますに参加するper
、pro
とpar
。私は避けたいpr
人、党とプロジェクトがすべて持っているためp
とr
単語の関連する初期子音ように、pr
(私は確かにあなたが主張受け入れるん3つの文字を使用したとして、明らかに「プロジェクトのために、それは別名だ」叫びはありませんpe
、pa
そしてpr
、あなたはいくつかのキーストロークを:))保存したい場合 - おそらく「安全のため」だけでなく、抵抗が最も少ないパスであるため、どこでも盲目的に二重引用符を押し込みます-
builder.addcolumn( '"' || alias_name || '"."' || col_name || '",')
列名を調べて必要かどうかを確認するよりも、盲目的に引用符を追加するロジックをコーディングする方がはるかに簡単です引用し、必要な場合にのみ追加してください。残念ながら、これはコードが"
どこでも読めない混乱に終わることを意味します。 - ..そして、「すべてを盲目的に引用する」ということから、「すべての識別子をすべて大文字にします。現在、テーブル/列名では大文字と小文字が区別されない
SELECT pErSon.NaME ...
ためです。table.columnはPERSONですが、問題ありません。 NAMEそれは大文字と小文字を区別しません。しかし、盲目的に引用符を追加した場合、引用符を追加すると大文字と小文字が区別されるように扱われるため、名前をすべて大文字にする必要があります。機能SELECT "pErSon"."NaME"
しません。そのため、注意深く書き出され、美しく読みやすい*小文字の識別子はなくなりました。
SQLDeveloperは、ファンキーな文字、スペース、大文字小文字の区別などが原因であるかどうかにかかわらず、引用する必要があるものを解決するための内省とロジックのすべてに実際に取り組むことができます。しかし、そうではありません。「ただ」のようなアプローチをコーディングするのは安全で簡単です。引用する」、「大文字にする」、「ランダム/インクリメンタルな独自のものであるエイリアスを作成する」、残念ながらこれは悪い推奨事項ですが、試行していることの精神は良い考えです。
*子供として私たちは大文字の前に小文字を学びます。大文字よりも小文字の方が常に速く読めます