Mengapa pengembang SQL menyarankan format berbeda untuk prosedur yang berfungsi?

Aug 20 2020

Ini adalah prosedur asli saya yang bekerja dengan baik:

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;

Tetapi Pengembang SQL memberi saya garis merah berlekuk-lekuk di bawah SELECTdan menyarankan saya mengubahnya menjadi ini:

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;

Pertanyaan saya adalah (mengapa) ini lebih baik? Apa itu "A1"?

Jawaban

4 nbk Aug 20 2020 at 20:04

A1 adalah alias untuk tabel "C##ELLIE"."CPP"

prosedurnya sama, tetapi jadi Anda dan oracle tahu skema mana yang dimiliki tabel cpp juga.

Tambahan Anda juga harus menambahkan komentar apa prosedurnya, jika Anda kembali dalam 3 tahun lebih mudah untuk mengetahui, skema mana yang Anda gunakan dan untuk apa

5 WilliamRobertson Aug 20 2020 at 21:49

Mengenai masalah mengapa ia menyarankan format yang berbeda ketika kode sudah berfungsi, tentu saja mungkin ada kode berformat buruk yang berfungsi, jadi pada prinsipnya tidak ada alasan mengapa Anda tidak mempertimbangkan perbaikan tata letak atau refactoring yang mungkin membuat kode lebih kuat, efisien, atau lebih mudah dikelola.

Namun, nama yang dikutip ganda adalah praktik yang buruk karena menyembunyikan kesalahan penamaan dan memaksa Anda untuk menentukan huruf besar / kecil, dan hasilnya kurang dapat dibaca daripada aslinya. Mereka benar-benar merupakan fitur portabilitas untuk digunakan dengan aplikasi pihak ketiga yang memiliki nama tabel yang aneh . Generator kode cenderung memberikan tanda kutip ganda pada segala hal karena lebih mudah melakukannya daripada mendeteksi apakah mereka benar-benar dibutuhkan dalam setiap kasus. Tidak mungkin begitu

from "C##ELLIE"."CPP" "A1"

adalah perbaikan apa pun

from cpp

kecuali mungkin untuk penggunaan alias tabel. Sebaiknya beri alias pada tabel (tanpa tanda kutip ganda!) Dan gunakan saat merujuk ke kolom. Tapi "A1"(atau bahkan a1) adalah jenis alias tabel yang hanya akan diimpikan oleh komputer. Akan jauh lebih baik menggunakan alias yang merupakan singkatan dari nama tabel, mungkin dalam kasus ini c. Bayangkan jika Anda bergabung dengan enam tabel - sekarang yang mana a3? Oh iya, itu ORDER_DETAILS. (Meskipun dalam kasus ini nama tabelnya sangat pendek sehingga tidak ada gunanya mengaliasinya.) Jadi,

SELECT "A1"."CPP" "CPP"
FROM   "C##ELLIE"."CPP" "A1"

akan jauh lebih baik sebagai adil

SELECT c.cpp
FROM   cpp c

(Saya juga akan menggunakan huruf kecil karena ini bukan tahun 1974 dan editor saya menyoroti kata kunci bahasa menggunakan warna dan tebal, tetapi kami akan membiarkannya.)

Nama skema pengkodean keras adalah praktik yang buruk karena paling tidak mubazir (objek ada dalam skema yang sudah Anda kerjakan sehingga tidak menambahkan apa-apa kecuali komplikasi yang tidak perlu) atau lebih buruk lagi, membatasi portabilitas (jika Anda pernah mengganti nama skema atau memindahkan kode Anda ' harus melalui itu membersihkan referensi hardcode).

Saya yakin ini adalah fitur pintar yang berarti baik, tetapi dalam hal ini bukan saran yang baik.

4 EdStevens Aug 21 2020 at 00:27

Berikut adalah demo tentang apa yang salah dengan menggunakan tanda kutip ganda di sekitar nama objek. Baca setiap perintah dengan cermat dan perhatikan sensitivitas huruf dari nama tabel, dikutip dan tidak dikutip.

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
1 CaiusJard Aug 21 2020 at 17:11

Saya mungkin akan merekomendasikan ini untuk kode Anda:

...
    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);
...

Kami hanya menggunakan satu tabel / tampilan, cppjadi aliasing tidak sepenuhnya diperlukan, tetapi akan membantu jika di masa mendatang tabel lain ditambahkan ke kueri ini.

Khususnya dengan 2+ kueri tabel, jika nama di SELECT tidak sepenuhnya memenuhi syarat (sebutkan nama tabel atau alias sebelum nama kolom) maka kueri bisa rusak jika kolom ditambahkan ke tabel, yang memiliki nama yang sama dengan kolom lain di kolom lain. meja:

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

Jika kita menambahkan kolom Status ke Address, query di atas gagal karena sekarang ambigu. Menambahkan kolom yang menyebabkan masalah semacam ini tidak akan membuat DB mengumumkan "Saya menambahkannya, tetapi omong-omong, semua kueri lain di seluruh skema dan sistem dependen Anda sekarang akan gagal" - Anda hanya perlu mencari kueri yang gagal dengan pengujian. Atau pelanggan mengeluh;)

Jika kami sepenuhnya memenuhi syarat:

SELECT 
  person.name, 
  person.status, 
  address.street 
FROM 
  person 
  INNER JOIN adress a ON person.addressid = address.id

Itu akan terus bekerja ..

Mengulangi nama tabel dengan kolom agak membosankan dan bertele-tele. Menggunakan nama yang lebih pendek tidak hanya meningkatkan keterbacaan ..

SELECT 
  p.name, 
  p.status, 
  a.street 
FROM 
  person p
  INNER JOIN address a ON p.addressid = a.id

..tapi secara psikologis mengingatkan kita bahwa kita dapat menggabungkan tabel dalam beberapa kali karena alasan yang berbeda:

 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

Secara keseluruhan, SQLDeveloper mencoba melakukan hal yang baik di sini karena bergerak menuju pengertian yang baik tentang:

  • Berikan tabel Anda alias yang masuk akal, dapat dibaca, dan relevan secara kontekstual
  • Selalu isi nama kolom Anda dengan alias

Dimana jatuhnya adalah:

  • Itu memilih nama alias omong kosong A1, yang tidak membantu Anda mengingat apa pun; Bukan kebetulan saya memilih porang dan aalamat, karena saya yakin Anda dapat menghargai. Jika ada Partai, dan Proyek untuk bergabung, saya mungkin menggunakan per, prodan par. Saya akan menghindari prkarena Person, Party, dan Project semuanya memiliki pdan rsebagai konsonan awal yang relevan dalam kata tersebut, jadi prjangan meneriakkan "ini adalah alias untuk Proyek" sejelas menggunakan tiga huruf (tapi saya pasti akan menerima Anda berdebat untuk pe, padan prjika Anda ingin menyimpan beberapa penekanan tombol :))
  • Ini membabi buta menabrak tanda kutip ganda di mana-mana, mungkin "untuk keamanan" tetapi juga karena itu adalah jalur yang paling tidak resistan - Jauh lebih mudah untuk membuat kode logika menambahkan tanda kutip secara membabi buta builder.addcolumn( '"' || alias_name || '"."' || col_name || '",')daripada memeriksa nama kolom dan melihat apakah itu mungkin perlu mengutip dan hanya menambahkannya jika diperlukan. Sayangnya, ini berarti kode berakhir dengan kekacauan yang tidak terbaca di "mana - mana ..
  • .. dan memulai dari itu "hanya kutipan membabi buta semuanya" adalah "dan kemudian membuat semua pengenal HURUF BESAR SEMUA, karena saat ini nama tabel / kolom tidak peka huruf besar-kecil. SELECT pErSon.NaME ...baik-baik saja; meskipun tabel.kolom hanya PERSON. NAMA bukan case sens .. Tetapi ketika kita menambahkan tanda kutip secara membabi buta, kita benar-benar harus meletakkan nama dalam huruf besar semua, karena menambahkan tanda kutip membuat mereka diperlakukan dengan cara yang peka huruf besar / kecil! Tidak SELECT "pErSon"."NaME"akan berhasil, jadi, pengenal huruf kecil Anda yang ditulis dengan cermat, dan huruf kecil * yang mudah dibaca hilang ..

SQLDeveloper benar-benar bisa masuk ke semua introspeksi dan logika untuk mencari tahu apa yang perlu dikutip, apakah itu karena karakter yang funky, spasi, case sens, dll. Tapi tidak - itu mengambil pendekatan kode yang aman dan sederhana seperti "just mengutipnya "," hanya huruf besar "dan" hanya membuat alias yang merupakan beberapa hal unik acak / tambahan "dan sayangnya itu adalah rekomendasi yang buruk, meskipun semangat dari beberapa dari apa yang dicoba adalah ide yang bagus

* sebagai anak-anak kita belajar huruf kecil sebelum huruf besar; kami selalu lebih cepat dalam membaca kalimat huruf kecil daripada huruf besar