SQL 개발자가 작동하는 프로 시저에 대해 다른 형식을 제안하는 이유는 무엇입니까?

Aug 20 2020

이것은 아름답게 작동하는 나의 원래 절차입니다.

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"은 무엇입니까?

답변

4 nbk Aug 20 2020 at 20:04

A1 테이블의 별칭입니다. "C##ELLIE"."CPP"

절차는 동일하지만 사용자와 오라클 은 테이블 cpp가 속한 스키마도 알고 있습니다.

또한 절차가 만드는 내용에 대한 설명도 추가해야합니다. 3 년 후에 돌아 오면 어떤 스키마를 사용했는지, 어떤 용도로 사용하는지 알기가 더 쉽습니다.

5 WilliamRobertson Aug 20 2020 at 21:49

코드가 이미 작동 할 때 다른 형식을 제안하는 이유에 대해서는 물론 제대로 작동하는 형식이 잘못된 코드가있을 수 있으므로 원칙적으로 레이아웃이나 리팩토링 개선을 고려하지 않아야 할 이유가 없습니다. 더 강력하고 효율적이거나 유지하기 쉬운 코드입니다.

그러나 큰 따옴표로 묶인 이름은 이름 지정 오류를 숨기고 대문자 / 소문자를 지정해야하며 결과가 원본보다 읽기 어렵 기 때문에 좋지 않습니다. 그것들은 이상한 테이블 이름 을 가진 써드 파티 어플리케이션과 함께 사용하기위한 이식성 기능입니다 . 코드 생성기는 각 경우에 실제로 필요한지 여부를 감지하는 것보다 쉽기 때문에 모든 것을 큰 따옴표로 묶는 경향이 있습니다. 방법이 없습니다

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 년이 아니기 때문에 소문자로하고 편집자가 색상과 굵은 체를 사용하여 언어 키워드를 강조하지만 우리는 그만두겠습니다.)

하드 코딩 스키마 이름은 중복되기 때문에 (객체가 이미 작업중인 스키마에 있으므로 불필요한 복잡함을 제외하고는 추가하지 않음) 이식성이 제한되기 때문에 좋지 않습니다 (스키마 이름을 바꾸거나 코드를 이동 한 경우). 하드 코딩 된 참조를 정리해야합니다).

이것이 의미있는 영리한 기능이라고 확신하지만이 경우에는 좋은 조언이 아닙니다.

4 EdStevens Aug 21 2020 at 00:27

다음은 개체 이름 주위에 큰 따옴표를 사용하는 데있어 문제점에 대한 데모입니다. 각 명령을주의 깊게 읽고 인용 및 인용되지 않은 테이블 이름의 대소 문자 구분에주의하십시오.

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

아마도 귀하의 코드에 대해 이것을 권장 할 것입니다.

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

하나의 테이블 / 뷰만 사용하고 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

Address에 Status 열을 추가하면 위의 쿼리는 이제 모호하기 때문에 실패합니다. 이런 종류의 문제를 일으키는 열을 추가한다고해서 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, propar. 나는 피할 것 pr사람, 파티 및 프로젝트 모두 가지고 있기 때문에 p그리고 r단어의 관련 초기 자음 정도로, pr(그러나 나는 확실히 당신이 주장 받아 들일 않는 세 글자를 사용하는 것과 분명히으로 "프로젝트가 별명이다"소리하지 않습니다 pe, pa그리고 pr당신은 몇 번의 키 입력을 :)) 저장하려는 경우
  • "안전을 위해"모든 곳에서 맹목적으로 큰 따옴표를 사용하지만 저항이 가장 적은 경로이기 때문이기도 builder.addcolumn( '"' || alias_name || '"."' || col_name || '",')합니다. 열 이름을 검사하고 필요한지 확인하는 것보다 따옴표를 맹목적으로 추가하는 논리를 코딩하는 것이 훨씬 쉽습니다. 인용하고 필요한 경우에만 추가하십시오. 이것은 불행히도 코드가 "모든 곳 에서 읽을 수없는 엉망이된다는 것을 의미합니다 ..
  • .. 그리고 그 "그냥 맹목적으로 모든 것을 인용한다"는 "그런 다음 모든 식별자를 모두 대문자로 만드십시오. 지금은 테이블 / 열 이름이 대소 문자를 구분 하지 않기 때문 입니다. SELECT pErSon.NaME ...table.column은 PERSON이지만 괜찮습니다. NAME 대소 문자를 구분하지 않습니다.하지만 맹목적으로 따옴표를 추가 한 경우에는 이름을 모두 대문자로 입력해야합니다. 따옴표를 추가하면 대소 문자를 구분하는 방식으로 처리 SELECT "pErSon"."NaME"되므로 작동하지 않습니다. 따라서 신중하게 작성하고 아름답게 읽을 수있는 * 소문자 식별자가 사라졌습니다.

SQLDeveloper는 펑키 한 문자, 공백, 대소 문자 구분 등으로 인해 인용되어야하는 모든 내용을 조사하고 논리를 파악할 수 있습니다.하지만 그렇지 않습니다. "그냥 인용 ","그냥 대문자로 ","무작위 / 증분 고유 한 별칭을 만드세요. "안타깝게도 좋지 않은 권장 사항이지만 시도중인 일부 정신은 좋은 생각입니다.

* 어릴 때 우리는 대문자보다 먼저 소문자를 배웁니다. 우리는 항상 대문자보다 소문자 문장을 읽는 것이 더 빠릅니다.