< 이전 | 다음 >

학습 5: 테이블 결합을 사용하여 더욱 복잡한 데이터 검색

지금까지는 각 데이터 액세스 함수가 오직 한 테이블에서만 행을 검색했습니다. 이 학습에서는 EGL과 SQL 테이블 결합을 사용하여 한 번에 여러 테이블에 대한 작업을 수행하는 방법을 설명합니다.

SQL 테이블 결합에 대한 전체 설명은 이 학습서의 범위를 벗어납니다. 쉽게 말해서, 테이블 결합은 둘 이상의 관련된 테이블로부터 결과 세트를 조합합니다.
예를 들어, 데이터베이스의 CUSTOMERS 테이블은 고객의 성 및 이름과, 1차 키로서 ID 번호를 포함합니다(기타 여러 콜론 포함).
표 1. CUSTOMER 테이블의 샘플 데이터
CUSTOMER_ID FIRST_NAME LAST_NAME
1 Fred Filibuster
2 Andy Lundquist
3 Billie Kingman
ORDERS 테이블에는 1차 키로서 주문 ID 번호와 주문 양을 포함합니다. 테이블에는 주문을 한 고객의 ID 번호도 포함되며 해당 열은 외부 키가 됩니다.
표 2. ORDERS 테이블의 샘플 데이터
ORDER_ID CUSTOMER_ID ORDER_AMOUNT
1 1 111.11
2 1 222.22
3 1 333.33
이 경우, CUSTOMER_ID 열이 두 테이블 사이의 관계를 작성하므로 이 열은 테이블 결합에 사용할 좋은 후보입니다. 이 학습에서는 이 두 테이블을 사용자 정의된 SQLRecord 파트와 결합하여 고객의 주문과 해당 고객을 일치시키는 결과 세트를 생성합니다.

테이블 결합은 복잡한 데이터베이스 오퍼레이션이므로 데이터베이스의 동작에 대해 잘 이해하고 있어야 하며 출력을 주의하여 테스트해야 합니다. 이 학습에서 표시되는 바와 같이 예상 데이터를 항상 얻지는 못합니다.

  1. 다음과 같이 새 SQLRecord 파트를 보유할 새 EGL 소스 파일을 작성하십시오.
    1. 프로젝트 탐색기 보기에서 EGLSQL 프로젝트를 마우스 오른쪽 단추로 클릭한 다음 새로 작성 > EGL 소스 파일을 클릭하십시오.
    2. 새 EGL 소스 파일 창에서 패키지 필드에 data라는 이름을 입력하십시오.
    3. EGL 소스 파일 이름 필드에 records를 입력하십시오.
    4. 완료를 클릭하십시오.
    새 EGL 소스 파일이 작성되어 편집기에서 열립니다.
  2. 새 파일에서 package 문 아래 새 SQLRecord의 이름을 입력하여 CUSTOMER와 ORDERS 테이블을 결합하십시오.
    record OrderCustomerJoin type SQLRecord
      {tableNames = [["EGL.CUSTOMER", "C"], ["EGL.ORDERS", "O"]]}
    end
    이 레코드의 첫 번째 행은 기타 SQLRecord 파트와 동일합니다. 레코드의 이름과 SQLRecord 스테레오타입을 지정합니다. 두 번째 행은 이 레코드가 연관될 테이블을 tableNames 특성 값으로 지정합니다. 이전 학습에서 작업한 단일 테이블 레코드는 이 특성에서 한 테이블만 나열합니다(예: Orders 레코드의 ORDERS 테이블).
    record Orders type sqlRecord { 
      tablenames=[["EGL.ORDERS"]]
    ...
    작성 중인 OrderCustomerJoin 레코드는 두 테이블 모두에서 데이터를 검색하도록 tableNames 특성에 두 테이블을 나열해야 합니다. 구분을 쉽게 하기 위해 레코드는 각 테이블 이름의 별명을 포함합니다(ORDERS의 경우 "O" 및 CUSTOMERS의 경우 "C"). 이러한 별명을 통해 레코드에서 테이블 이름을 보다 쉽게 참조할 수 있습니다.

    이제, 레코드 파트의 기본 정보를 지정했으므로 EGL이 나머지 파트를 채울 수 있습니다. 그러나, 우선 EGL이 연결 정보를 검색할 데이터베이스를 지정해야 합니다.

  3. 다음과 같이 EGL의 기본 SQL 데이터베이스로 Derby 데이터베이스를 설정하십시오.
    1. > 환경 설정을 클릭하십시오.
    2. 환경 설정 창에서 EGL을 펼치고 SQL 데이터베이스 연결을 클릭하십시오.
    3. 연결 목록에서 EGLDerbyR7 또는 EGLDerbyR71이라는 데이터베이스 연결을 선택하십시오.
    4. 확인을 클릭하십시오.
  4. 다시 records.egl 파일에서 커서를 레코드의 이름에 두십시오.
  5. OrderCustomerJoin 레코드의 이름에 커서를 둔 상태로 마우스 오른쪽 단추를 클릭한 다음 SQL 레코드 > SQL 검색을 클릭하십시오. EGL SQL 검색 기능
  6. 암호 프롬프트에서 사용자 이름 및 암호의 기본값을 그대로 두십시오. 샘플 데이터베이스에는 특정 사용자 이름이나 암호가 필요하지 않습니다. EGL SQL 검색 기능이 keyItems 특성과 테이블의 행 필드를 포함하여 나머지 SQLRecord 파트를 작성합니다.
    record OrderCustomerJoin type SQLRecord
      {tableNames = [["EGL.CUSTOMER", "C"], ["EGL.ORDERS", "O"]], 
      keyItems=[CUSTOMER_ID, ORDER_ID]}
    
      CUSTOMER_ID int
        {column="C.CUSTOMER_ID", isReadOnly=yes};
      FIRST_NAME string
        {column="C.FIRST_NAME", isReadOnly=yes, 
          isSqlNullable=yes, sqlVariableLen=yes, maxLen=30};
      LAST_NAME string
        {column="C.LAST_NAME", isReadOnly=yes, 
          isSqlNullable=yes, sqlVariableLen=yes, maxLen=30};
    ...
      ORDER_ID int
        {column="O.ORDER_ID", isReadOnly=yes};
      orders_CUSTOMER_ID int
        {column="O.CUSTOMER_ID", isReadOnly=yes, 
          isSqlNullable=yes};
      ORDER_AMOUNT decimal(8,2)
        {column="O.ORDER_AMOUNT", isReadOnly=yes, 
          isSqlNullable=yes};
      ORDER_DETAILS string
        {column="O.ORDER_DETAILS", isReadOnly=yes, 
          isSqlNullable=yes, sqlVariableLen=yes, maxLen=111};
    end
    각 필드의 특성 값은 tableNames 특성에 지정된 대로 테이블의 별명으로 시작됩니다. 이 별명을 사용하여 특정 필드가 연관되는 테이블을 추적할 수 있습니다.
  7. records.egl 파일을 저장하되 닫지는 마십시오.
  8. printCustomerOrders라는 프로그램 패키지에서 새 프로그램 파트를 작성하십시오.
  9. 새 프로그램에서 기본 코드를 제거하십시오.
  10. 프로그램의 main 함수에서 사용자가 방금 작성한 OrderCustomerJoin 레코드를 기반으로 배열 변수를 작성하십시오.
    allCustomerOrders OrderCustomerJoin[0];
    Ctrl+Space를 눌러 레코드 파트 유형을 삽입하도록 컨텐츠 지원을 사용하십시오. 컨텐츠 지원을 사용하지 않는 경우 import 문을 파일의 맨 위 package문 바로 아래에 수동으로 추가해야 합니다.
    import data.OrderCustomerJoin;
  11. openforEach 문을 사용하여 데이터베이스에서 행을 검색하고 콘솔에 값을 인쇄하십시오.
    tempRec OrderCustomerJoin;
    open resultSet for tempRec;
    forEach (tempRec)
      SysLib.writeStdout(tempRec.CUSTOMER_ID :: " " :: 
        tempRec.LAST_NAME :: " " :: tempRec.ORDER_ID);
    end
  12. 프로그램을 저장하고 생성하여 실행하십시오. 사용자가 테이블 결합의 함정을 잘 이해하고 있다면, 이 테이블 결합의 오류와 출력이 그리 유용하지 않다는 것을 알아챘을 것입니다.
    1 Filibuster 1
    1 Filibuster 2
    1 Filibuster 3
    ...
    1 Filibuster 22
    1 Filibuster 23
    2 Lundquist 1
    2 Lundquist 2
    2 Lundquist 3
    2 Lundquist 4
    ...
    2 Lundquist 22
    2 Lundquist 23
    3 Kingman 1
    3 Kingman 2
    ...
    데이터베이스가 테이블 사이의 논리적 교차 참조를 작성하지 않았습니다. 그 대신, 가능한 모든 조합으로 CUSTOMERS 테이블의 각 행을 ORDERS 테이블의 각 행과 쌍으로 연결합니다. 이 결과에서 각 고객은 모두를 주문한 것으로 기록되며, 이 기록은 올바르지 않습니다. open 문 뒤에서 SQL 코드를 명시적으로 표시되게 만들면 SQL이 WHERE절을 사용하지 않고 두 테이블 모두에서 모든 행을 선택하는 것을 확인할 수 있습니다.
    open resultSet for tempRec with
      #sql{
        select
          C.CUSTOMER_ID, C.FIRST_NAME, C.LAST_NAME, C.PASSWORD, 
          C.PHONE, C.EMAIL_ADDRESS, C.STREET, C.APARTMENT, 
          C.CITY, C.STATE, C.POSTALCODE, C.DIRECTIONS, 
          O.ORDER_ID, O.CUSTOMER_ID, O.ORDER_AMOUNT, 
          O.ORDER_DETAILS, O.ORDER_DATE, O.ORDER_STATUS
        from EGL.CUSTOMER C, EGL.ORDERS O
        order by
          C.CUSTOMER_ID, O.ORDER_ID asc
      };

    테이블을 효과적으로 결합하려면 테이블 유니온을 리턴하지 않고 테이블을 논리적으로 병합하는 방법을 데이터베이스에 알려야 합니다. 명시적 SQL 코드를 편집하여 이 작업을 수행할 수 있지만, 이 경우 레코드를 사용할 때마다 작업을 수행하거나 정확하지 않은 데이터를 검색할 수도 있다는 위험이 있습니다. 대신, 내재적 SQL 코드가 항상 효과적인 테이블 결합을 수행하도록 이 레코드의 기본 선택 조건을 설정합니다.

  13. open 문 뒤에서 SQL 코드를 명시적으로 만든 경우 레코드 이름에 커서를 두고 마우스 오른쪽 단추로 클릭한 다음 SQL 문 > 제거를 클릭하여 다시 내재적으로 만드십시오.
  14. records.egl 파일의 레코드 파트 정의로 되돌아가십시오.
  15. 다음과 같이 레코드 파트 정의에 defaultSelectCondition 특성을 추가하십시오.
    record OrderCustomerJoin type SQLRecord
      {tableNames = [["EGL.CUSTOMER", "C"], ["EGL.ORDERS", "O"]], 
      keyItems=[CUSTOMER_ID, ORDER_ID],
      defaultSelectCondition = #sqlCondition{ condition }}
    defaultSelectCondition 특성은 이 레코드와 get 또는 open을 사용할 때 내재적 SQL 코드와 기본 명시적 SQL 코드에 WHERE절을 지정합니다.
  16. #sqlCondition{} 블록에서 기본 "condition" 텍스트를 바꾸고 이 두 테이블 사이의 SQL 테이블 결합에 올바른 WHERE절을 입력하여 전체 테이블 이름이 아니라 테이블 별명을 사용하도록 하십시오.
    defaultSelectCondition = #sqlCondition{ O.CUSTOMER_ID = C.CUSTOMER_ID }}
    키워드 WHERE를 추가할 필요가 없습니다. 이 경우에는 EGL이 WHERE를 SQL 코드에 자동으로 삽입합니다.
  17. 파일을 저장하십시오. 이제, open 문 뒤에서 SQL 코드를 명시적으로 만든 경우 다음과 같이 표시됩니다.
    open resultSet for tempRec with
      #sql{
        select
          C.CUSTOMER_ID, C.FIRST_NAME, C.LAST_NAME, C.PASSWORD, 
          C.PHONE, C.EMAIL_ADDRESS, C.STREET, C.APARTMENT, 
          C.CITY, C.STATE, C.POSTALCODE, C.DIRECTIONS, 
          O.ORDER_ID, O.CUSTOMER_ID, O.ORDER_AMOUNT, 
          O.ORDER_DETAILS, O.ORDER_DATE, O.ORDER_STATUS
        from EGL.CUSTOMER C, EGL.ORDERS O
        where
          O.CUSTOMER_ID = C.CUSTOMER_ID
        order by
          C.CUSTOMER_ID, O.ORDER_ID asc
      };
    이제, SQL 코드는 리턴된 행을 CUSTOMER 및 ORDERS 테이블 모두에 같은 고객 번호가 있는 행으로만 제한하는 WHERE절을 포함합니다.
  18. 프로그램을 저장하고 생성하여 실행하십시오.
효과적으로 테이블을 결합하면 이 프로그램의 결과는 각각의 주문을 한 고객을 표시합니다.
1 Filibuster 1
1 Filibuster 2
1 Filibuster 3
...
1 Filibuster 11
1 Filibuster 18
2 Lundquist 7
2 Lundquist 8
2 Lundquist 12
2 Lundquist 15
2 Lundquist 20
3 Kingman 13
4 Liebowitz 14
6 Springsteen 22
7 St. Louis 16
8 Sharov 17
9 Hudak 23

이 학습에서 사용하는 두 파일의 전체 코드를 살펴보십시오. 파일에 빨간색 X 기호로 표시된 오류가 나타나면 사용자의 코드가 학습 5에서 완성된 printCustomerOrders.egl 및 records.egl 파일의 코드와 일치하는지 확인하십시오.

< 이전 | 다음 >