internal table study ABAP study

*-------------------------------------
*CHAPTER 5. INTERNAL TABLE
*-------------------------------------

*-------------------------------------
* 1.OVER VIEW
*-------------------------------------

* 1-1) internal table 의 정의
* 프로그램 내에서 정의하여 사용할 수 있는 Local table.

* 1-2) structure(구조체) 비교
* 구조체 선언

TYPESBEGIN OF s_type,
         no(6)    TYPE c,
         name(10TYPE c,
         part(16TYPE c,
       END OF s_type.

DATA sawon TYPE s_type.

* 구조체는 사원 한명의 값만 할당하여 사용할 수 있지만, 사원 1명으로 이루어진 회사는 없다.

* 1-3) structure(구조체)배열과 Internal table
* ABAP에서의 인터널 테이블 선언

TYPESBEGIN OF s_type,
         no(6)    TYPE c,
         name(10TYPE c,
         part(16TYPE c,
       END OF s_type.

TYPESt_type TYPE STANDARD TABLE OF s_type INITIAL SIZE 100"DATA 테이블 명 TYPE 테이블 타입 INITIAL SIZE 건수
DATA sawon TYPE t_type.

* 값 할당
sawon-name 'kimsungjoon'.
APPEND sawon.
sawon-name 'kimminjae'.
APPEND sawon.

* 값 사용.
LOOP AT sawon.
  WRITE sawon-name.
ENDLOOP.


* 인터널 테이블은 INITIAL SIZE구문으로 테이블 크기만 선언할 뿐 메모리를 미리 할당하지 않는다.
* 할당과 추가가 동시에 해야만 해!! // sawon-name = '박종헌' 만 하고 APPEND를 안하면 추가 안됨.

* 1-4) internal table 생성

* internal table 생성에는 1) local table type을 이용한 생성 2) Global abap dictionary type을 이용한 생성  두가지가 있다.

*1) local table type을 이용한 생성
TYPESBEGIN OF s_type,        " local 구조체 타입 선언
         no(6)    TYPE c,
         name(10TYPE c,
         part(16TYPE c,
       END OF s_type.

* < STANDARD TABLe OF 구조체 타입 >을 이용해서 인터널 테이블 선언.
DATA gt_itab TYPE STANDARD TABLE OF s_type WITH NON-UNIQUE KEY no WITH HEADER LINE.    "  with NON-UNIQUE KEY no   왜 넣었을까?

gt_itab-no '0001'.
gt_itab-name 'EASY ABAP'.
gt_itab-part 'SAP Team'.      "////여기까지 추가
APPEND gt_itab.   "                 "테이블에 할당

LOOP AT gt_itab.
  WRITEgt_itab-nogt_itab-namegt_itab-part,     "테이블 값 읽어주기.
  endloop.

* 2) Global abap dictionary type을 이용한 생성

  DATAgt_itab TYPE SORTED TABLE OF scarr WITH UNIQUE KEY carrid.    "글로벌 테이블인 scarr을 이용한 인터널 테이블 선언.
  DATAgs_str LIKE LINE OF gt_itab.                                  "인터널 테이블의 필드를 이용하여 구조체 선언.

  SELECT *              "scarr을 테이블 gt_itab으로 읽어들여.
             INTO TABLE gt_itab
             FROM scarr.

  LOOP AT gt_itab INTO gs_str.     "gt_itab --> work area인 gs_str로 넣어서 WRITE출력하라.
    WRITE/gs_str-carridgs_strcarrname.
  ENDLOOP.



*---------------------------
* 2. 인터널 테이블과 헤더라인
*---------------------------

* 헤더라인이 있다면, 인터널테이블과 헤더라인의 이름이 같아서 생략된다.

* 인터널 테이블의 LOOP구문에서 1) 헤더라인이 없는 경우 2) 헤더라인이 있는 경우

* 1) 헤더라인이 없는 경우
LOOP AT itab INTO work_area.
  WRITE work_area-carrid.
ENDLOOP.

* 2) 헤더라인이 있는 겨우
LOOP AT itab.
  WRITE itab-carrid.
ENDLOOP.

* 인터널 테이블의 MODIFY 사용 시 1) 헤더라인 있는 경우 2) 없는 경우

*1) 있는 경우
MODIFY TABLE itab"(FROM itab)

*2) 없는 경우
MODIFY TABLE itab FROM work_area.

* READ 구문
*1) 있는 경우
READ TABLE itab...

*2) 없는 경우
READ TABLE itab INTO work_area.

* INSERT, COLLECT, READ, MODIFY, DELETE, LOOP, APPEND, 등등..

*헤더라인 있는 경우 예제.
TYPESBEGIN OF t_str,
         col1 TYPE i,
         col2 TYPE i,
       END OF t_str.

DATA gt_itab TYPE TABLE OF t_str WITH HEADER LINE.

DO TIMES.
  gt_itab-col1 sy-index.            "sy-index는 반복문 안에서 현재 실행되는 INDEX 값.
  gt_itab-col2 sy-index ** 2.     " ** 은 제곱.
  APPEND gt_itab.
ENDDO.

LOOP AT gt_itab.
  WRITE/ gt_itab-col1gt_itab-col2.
ENDLOOP.

* 헤더라인 없는 경우 예제

TYPESBEGIN OF t_str,              " local 구조체 type 선언
         col1 TYPE i,
         col2 TYPE i,
       END OF t_str.

DATA gt_itab TYPE TABLE OF t_str.       "구조체 type으로 인터널 테이블 선언.
DATA gs_wa LIKE  LINE OF gt_itab.        " 인터널 테이블로 work area선언.

DO TIMES.                                      " DO - ENDDO 3 번 반복
  gs_wa-col1 sy-index.
  gs_wa-col2 sy-index ** 2.
  APPEND gs_wa TO gt_itab.               "값을 넣어줄 때는 Work AREA에서 인터널 테이블로 작업을 해줌.
ENDDO.

LOOP AT gt_itab INTO gs_wa.            " 값을 출력하는 LOOP문에서는 인터널 테이블에서 Work Area로 작업을 해줌.
  WRITE/ gs_wa-col1gs_wa-col2.
ENDLOOP.

*---------------------------------------
* 3. 인터널 테이블 종류
*------------------------------------

* 인터널 테이블에는 1) STANDARD TABLE 2) SORTED TABLE 3) HASHED TABLE 세가지 종류가 있따.

* 3-1) STANDARD TABLE

* STANDARD TABLE이란 순차적인 INDEX를 가지는 테이블이다.
* INDEX는 단순히 인터널 테이블에서 데이터가 위치하는 라인 순번을 의미한다.
* STANDARD TABLE은 항상 WITH NON-UNIQUE로 선언해야 한다.

** 1.structure type 선언
TYPESBEGIN OF t_line,
         field1 TYPE LENGTH 5,
         field2 TYPE LENGTH 4,
         field3 TYPE i,
       END OF t_line.

**2. standard table type 선언
TYPESt_tab TYPE STANDARD TABLE OF t_line WITH NON-UNIQUE DEFAULT KEY"DEFAULT KEY는 CHAR타입으로 선언된 모든 칼럼들을 키 칼럼으로 정의하는 것.
" WITH KEY field1 와 같이 키 칼럼 선언해줄 수 있따.

**3. internal table 선언
DATA gt_itab TYPE t_tab WITH HEADER LINE.

gt_itab-field1 'Enjoy'.
gt_itab-field2 'ABAP'.
gt_itab-field3 1.
APPEND gt_itab.

READ TABLE gt_itab INDEX 1.

WRITE/ gt_itab-field1gt_itab field2gt_itab-field3.


*3-2) Sorted table
* standard table 과 sorted table은 INDEX table이다.
* sorted table은 key값으로 항상 정렬된 인터널 테이블 타입이다.
* soryed table은 unique와 non-unique 둘다 가능하기 때문에 반드시 명시해줘야 한다.

*1. structure type 선언
TYPESBEGIN OF t_line,
         col TYPE c,
         seq TYPE i,
       END OF t_line.

*2. standard table 타입 선언.
TYPESt_tab TYPE SORTED TABLE OF t_line WITH UNIQUE KEY col.

*3. Internal table 선언.
DATAgt_itab TYPE t_tab WITH HEADER LINE.

gt_itab-col 'B'.
gt_itab-seq '1'.
INSERT TABLE gt_itab.          " APPEND 와 INSERT의 차이점이 뭘까? 여기서는 APPEND쓰면 오류뜸.

gt_itab-col 'A'.
gt_itab-seq '2'.
INSERT TABLE gt_itab.

CLEAR gt_itab.
READ TABLE gt_itab INDEX 2.

WRITE/ gt_itab-colgt_itab-seq.


* 3-3) hashed table
* hashed table은 순차적인 index를 가지고 있지 않다.
* Hash값으로 계싼된 key값으로 탐색.
* hash값은 hash알고리즘으로 계산된것으로 메모리의 저장된 주소값으로 데이터를 찾는다.

* 1. structure type 선언
TYPESBEGIN OF t_line,
         col TYPE c,
         seq TYPE i,
       END OF t_line.

* 2. hashed table 타입 선언
TYPESt_tab TYPE HASHED TABLE OF t_line WITH UNIQUE KEY col"hashed table은 반드시 unique로 선언되어야 한다.

* 3. 인터널 테이블 선언
DATAgt_itab TYPE t_tab WITH HEADER LINE.

gt_itab-col 'B'.
gt_itab-seq '1'.
INSERT TABLE gt_itab.

gt_itab-col 'A'.
gt_itab-seq '2'.
INSERT TABLE gt_itab.

CLEAR gt_itab.
READ TABLE gt_itab WITH TABLE KEY col 'A'"index로 찾을 수 없고, key 값으로 찾아야 한다.

WRITE/ gt_itab-colgt_itab-seq.


*----------------------------------------------------------
* 5. 인터널 테이블 명령어
*----------------------------------------------------------

* 5-1) 인터널 테이블 값 할당.

* LINE TYPE이 다르면 다음 구문을 이용하여 순서와 관계없이 같은 칼럼 명에만 값을 할당 할 수 있다.
MOVE-CORRESPONDING itab1 TO itab2.

TYPESBEGIN OF t_line,
         col1 TYPE i,
         col2 TYPE i,
       END OF t_line.

DATAgt_itab1 TYPE STANDARD TABLE OF t_line WITH HEADER LINE,
      gt_itab2 TYPE STANDARD TABLE OF t_line,
      gs_wa    LIKE LINE OF gt_itab2.

DO TIMES.
  gt_itab1-col1 sy-index.                   "gt_itab1은 헤더라인이 있기 떄문에 바로 넣어줘.
  gt_itab1-col2 sy-index 2.
  INSERT TABLE gt_itab1.
ENDDO.

MOVE gt_itab1[] TO gt_itab2.        "body를 move해줘야 하기때문에 헤더라인 있는경우는 []를 꼭 넣어줘야 함.

LOOP AT gt_itab2 INTO gs_wa.           "gt_itab2는 헤더라인이 없기 때문에 work area를 통해서 출력
  WRITE/ gs_wa-col1gs_wa-col2.
ENDLOOP.

* 5-2) 인터널 테이블 초기화

*1) 헤더라인이 없는 인터널 테이블
* refresh구문을 사용하면 테이블의 내용만 삭제 메모리는 그대로 clear,  free를 사용하면 테이블 내용 + 메모리까지 삭제.

*2) 헤더라인이 있는 인터널 테이블
*clear는 헤더라인만 삭제, refresh는 테이블 body의 내용만 삭제 메모리는 그대로, free는 테이블 내용+메모리까지 삭제.

DATABEGIN OF gs_line,
        col1 TYPE i,
        col2 TYPE c,
      END OF gs_line.

DATAgt_itab LIKE STANDARD TABLE OF gs_line.  "뒤에 DATA가 오면 like, type이 오면 TYPE.

gs_line-col1 1.
gs_line-col2 'A'.
INSERT gs_line INTO TABLE gt_itab.

REFRESH gt_itab.
* FREE itab.
* CLEAR itab.

IF gt_itab IS INITIAL.                          "초기화 되었다면,
  WRITE'Internal table has no data.'.    " REFRESH로 초기화 되었기 떄문에 실행하면  '   ' 이 출력된다.
  FREE gt_itab.                                        "데이터만 초기화 되었고 메모리는 그대로 있어서 FREE로 메모리도 반환해줌.
ENDIF.

* HEADERLINE 있을 경우도 실습.

* 5-3) 인터널 테이블 정렬

* 5-3-1) SORT
* STANDARD 또는 HASHED type의 인터널 테이블을 sort로 정렬할 수 있다.
* sorted type의 인터널 테이블은 이미 정렬되어 있기때문에 sort구문을 쓰면 오류남.

SORT itab [ascending/descending].
* 테이블 키가 선언되지 않은 경우는 문자 타입(char)의 칼럼들을 구성하여 KEY값으로 만듬.

* 5-3-2) SORT 칼럼 지정

*정렬이 필요한 칼럼을 임의로 지정하고 싶을때
SORT itab BY <field명> [ASCENDING / DESCENDING].

* 5-3-3) Stable SORT

DATABEGIN OF gs_line,
        col1 TYPE c,
        col2 TYPE i,
      END OF gs_line.

DATA gt_itab LIKE STANDARD TABLE OF gs_line WITH NON-UNIQUE KEY col1.

gs_line-col1 'B'.      "work area --> gt_itab? gt_itab은 헤더라인이 없으니까
gs_line-col2 3.
APPEND gs_line TO gt_itab.

gs_line-col1 'C'.
gs_line-col2 4.
APPEND gs_line TO gt_itab.

gs_line-col1 'A'.
gs_line-col2 2.
APPEND gs_line TO gt_itab.

gs_line-col1 'A'.
gs_line-col2 1.
APPEND gs_line TO gt_itab.

SORT gt_itab.                          "col1만 기준으로 ascending
PERFORM wirte_data.

SORT gt_itab BY col1 col2.     "col1기준으로 ascending 후 col2 기준으로 ascending
PERFORM wirte_data.

SORT gt_itab BY col1 DESCENDING col2 ASCENDING.
PERFORM write_data.

FORM wirte_data.                                  " FORM - ENDFORM 한번에 선언해두고, 위에서 PERFORM 나올떄마다 실행.
  LOOP AT gt_itab INTO gs_line.
    WRITE/ gs_line-col1gs_line-col2.
  ENDLOOP.
  ULINE.
ENDFORM.

*------------------------------------------
* 6. 인터널 테이블 데이터 추가
*------------------------------------------

* 6-1) INSERT 구문

* 6-1-1) Table key를 이용해 한 라인 추가.

* 6-1-2) Table Key를 이용해 여러 라인 추가.


DATABEGIN OF gs_line,
        col1 TYPE c,
        col2 TYPE i,
      END OF gs_line.

DATAgt_itab1 LIKE STANDARD TABLE OF gs_line WITH NON-UNIQUE KEY col1.
DATAgt_itab2 LIKE SORTED TABLE OF gs_line WITH NON-UNIQUE KEY col1.


gs_line-col1 'B'.
gs_line-col2 1.
INSERT gs_line INTO TABLE gt_itab1.

gs_line-col1 'A'.
gs_line-col2 2.
INSERT gs_line INTO TABLE gt_itab1.

gs_line-col1 'C'.
gs_line-col2 3.
INSERT gs_line INTO TABLE gt_itab1.

INSERT LINES OF gt_itab1 INTO TABLE gt_itab2.     "SORTED TABLE에 넣으면 KEY값을 기준으로 정렬됨.
"여기서는 char type인 A B C순으로 정렬되어 출력됨.

*INSERT LINES OF gt_itab2 FROM 1 TO 2 INTO TABLE gt_itab2.      "실행이 안되는데??????

LOOP AT gt_itab2 INTO gs_line.
  WRITE/ gs_line-col1gs_line-col2.
ENDLOOP.


* 6-1-3) index를 이용해서 한 라인 or 여러 라인 추가.

INSERT line INTO itab [INDEX idx].

or

insert lines of itab2 into itab [index idx].



* 6-1-4, 6-2) 인터널 테이블 타입에 따른 INSERT, APPEND구문을 통한 Table Line추가.

INSERT 구문은 key와 index를 이용해 인터널 테이블을 추가할 수 있다--> 3가지 종류의 테이블에 모두 사용 가능.
APPEND 구문은 index만 이용할 수 있다.  ---> hashed 테이블에 사용 불가.

insert를 이용하면sorted 테이블은 col1이 정렬되어서 출력.
append를 이용하면넣어주는 테이블이 정렬이 안되어있어서 오류가 뜸...

* 6-3) COLLECT 구문
* COLLECT 구문을 이용하여 인터널 테이블의 숫자 타입 칼럼을 합산하는 기능 수행.

* 기준!!

* 선언할 때 KEY값을 제외한 칼럼들은 Numeric Type(f, i, p)로 선언되어야 한다. 왜냐하면 KEY값이 기준이기 떄문에.
* 같은 KEY 값이 있을 때는 숫자 타입의 칼럼을 합산하고, 업을 떄는 APPEND 기능을 수행한다.
* KEY값이 없는 테이블은 CHAR 타입 칼럼들을 기준으로 같은 작업을 수행한다.

DATABEGIN OF gs_line,
        col1(3TYPE c,
        col2(2type m,
        col3    TYPE i,
      ENd OF gs_line.

DATAgt_itab LIKE STANDARD TABLE OF gs_line WITh NON-UNIQUE KEY col1 col2.

gs_line-col1 'AA'.
gs_line-col2 '17'.
gs_line-col3 660.
COLLECT gs_line INTO gt_itab.         "처음에는 아무 데이터가 없으므로 APPEND 기능을 함.

gs_line-col1 'AL'.
gs_line-col2 '34'.
gs_line-col3 220.
COLLECT gs_line INTO gt_itab.        " 일치하는 KEY값이 없으므로 APPEND기능을 함.

gs_line-col1 'AA'.
gs_line-col2 '17'.
gs_line-col3 280.
COLLECT gs_line INTO gt_itab.       "첫번째 index 데이터와 KEY값이 일치하므로, COLLECT실행됨.

LOOP AT gt_itab INTO gs_line.
  WRITE/ gs_line-col1gs_line-col2gs_line-col3.
ENdloop.




* 데이터베이스 테이블에서 데이터를 가져와 COLLECT를 하는 경우.

DATABEGIN OF gs_line,
        carrid     TYPE sflight-carrid,
        connid     TYPE sflight-connid,
        paymentsum TYPE sflight-paymentsum,
      END OF gs_line.

DATAgt_itab LIKE STANDARD TABLE OF gs_line WITH NON-UNIQUE KEY carrid connid WITH HEADER LINE.
DATAgt_sum LIKE STANDARD TABLE OF gs_line WITH NON-UNIQUE KEY carrid connid WITH HEADER LINE.

SELECT carrid connid paymentsum
  INTO CORRESPONDING FIELDS OF gt_itab from sflight.

  LOOP AT gt_itab.
    COLLECT gt_itab INTO gt_sum.
  ENDLOOP.

  LOOP AT gt_sum.
    WRITE/ gt_sum-carridgt_sum-connidgt_sum-paymentsum.
  ENDLOOP.

*----------------------------
*
* 7. 인터널 테이블 데이터 변경
*----------------------------


* 인터널 테이블의 한 라인을 변경하려면 MODIFY구문을 사용


* 7-1) TABLE KEY를 이용해 한 라인 변경.
* MODIFY TABLE <itab> FROM <wa> [TRANSPORTING f1 f2]
* 헤더라인이 있는 경우 from wa를 생략.
* TRANSPROTING 구문을 이용하여 해당 칼럼만 변경

DATABEGIN OF gs_line,
        col1(2TYPE c,                     "type c는 문자든 숫자든 문자열로 인식..
        col2    TYPE i,                           "type i는 숫자로 인식.
        col3    TYPE sy-datum,
      END OF gs_line.

DATAgt_itab LIKE STANDARD TABLE OF gs_line WITH NON-UNIQUE KEY col1 col2"WITH NON-UNIQUE KEY col1 col2. 이렇게 되면 안됨.     " KEY 필드를 선언해줌.   col1 col2

gs_line-col1 'AA'.
gs_line-col2 50.
INSERT gs_line INTO TABLE gt_itab.             "위 지정 값들을 wa(gs_line)에서 인터널테이블(gt_itab)으로 넣어줌.

gs_line-col1 'AA'.
gs_line-col2 26.
INSERT gs_line INTO TABLE gt_itab.          "위 지정 값들을 wa(gs_line)에서 인터널테이블(gt_itab)으로 넣어줌.

gs_line-col1 'AA'.
gs_line-col2 50.
gs_line-col3 '20201029'.

MODIFY TABLE gt_itab FROM gs_line.        ""중복된 값이 존재할 때 MODIFY는 변경 시킴." NON-UNIQUE KEY를 설정해 줘야 KEY 값을 기준으로 테이블 라인을 변경한ㄴ다.

LOOP AT gt_itab INTO gs_line.
  WRITE/ gs_line-col1gs_line-col2gs_line-col3.
ENDLOOP.


* 7-2) WHERE 조건을 이용해 여러 라인 변경.
* 하나 이상의 라인을 변경하고자 할 때 WHERE 구문을 사용한다.
* MODIFY <itab> FROM <wa> TRANSPORTING f1 f2 ... WHERE cond.

DATABEGIN OF gs_line,
        carrid   TYPE sflight-carrid,
        carrname TYPE scarr-carrname,
        fldate   TYPE sflight-fldate,

      END OF gs_line.

DATAgt_itab LIKE TABLE OF gs_line.

SELECT carrid
        INTO CORRESPONDING FIELDS OF TABLE gt_itab
        FROM sflight.

LOOP AT gt_itab INTO gs_line.     " carrid connid가 인터널 테이블에서 wa로 보내짐.

  AT NEW carrid.    "AT NEW F1: 필드 F1에 새로운 값이 들어올 때 수행된다.

    SELECT SINGLE carrname        "FROM에서 WHERE조건을 만족하는 SINGLE carrname을 INTO로 보냄.
      INTO gs_line-carrname
      FROM scarr
      WHERE carrid gs_line-carrid.    "WHERE처음의 carrid는 scarr의 carrid
                                                            "그럼 여기까지 gs_line-carrname에 carrname이 넣어짐.

    MODIFY gt_itab FROM gs_line TRANSPORTING carrname         "" gs_line에서 gt_itab으로 MODIFY시켜.
    WHERE carrid gs_line-carrid.                                                " where의 carrid는 어디 carrid?? SELECT문의 WHERE조건과 똑같이 해석.

  ENDAT.

  WRITE/ gs_line-carridgs_line-carrname.


ENDLOOP.

* --> sflight의 carrid를 gt_itab에 넣고, 그 carrid와 scarr의 carrid가 일치하는 조건들의 carrname을 gt_itab에 추가하여 변경 시킴.


* 7-3) INDEX를 이용해 한 라인 변경.

* INDEX를 이용하여 해당 라인의 값을 변경할 수 있다.
* MODIFY it_itab FROM wa [INDEX idx] TANSPORTING f1 f2].

DATABEGIN OF gs_line,
        carrid   TYPE sflight-carrid,
        carrname TYPE scarr-carrname,
        fldate   TYPE sflight-fldate,
      END OF gs_line.

DATAgt_itab LIKE TABLE OF gs_line.

SELECT carrid fldate
    INTO CORRESPONDING FIELDS OF TABLE gt_itab
   FROM sflight.

LOOP AT gt_itab INTO gs_line.

  SELECT SINGLE carrname
          INTO gs_line-carrname
          FROM scarr
    WHERE carrid gs_line-carrid.

  MODIFY gt_itab FROM gs_line INDEX sy-tabix.     "INDEX sy-tabix를 이용해서 한 라인의 값을 변경. LOOP는 제일 위에서부터 wa로 하나씩 보내줌.
  "sy-tabix 순서대로 변경해줌.

  WRITE/ gs_line-carridgs_line-carrname.

ENDLOOP.

*-----------------------------------

* 8. 인터널 테이블 데이터 삭제.

* ----------------------------------

* 인터널 테이블 데이터 변경은 MODIFY를 사용했다.
* 데이터 삭제는 DELETE 구문을 사용한다.
* 마찬가지로 KEY와 WHERE조건,  INDEX조건으로 찾아서 삭제할 수 있다.

* 8-1) Table KEY를 이용해 한 라인 삭제.

* DELETE TABLE itab WITH TABLE KEY k1 = <f1> k2 = <f2>.  " 키가 이미 선언되어 있는 테이블에서 제거하고 싶은  기준 키를 WITH TABLE KEY로 선언해줌.

* 8-2) WHERE 조건을 이용해 여러 라인 삭제
* DELETE itab WHERE condition.

DATABEGIN OF gs_line,
        carrid TYPE sflight-carrid,
        connid TYPE sflight-connid,
      END OF gs_line.

DATAgt_itab LIKE TABLE OF gs_line WITH NON-UNIQUE KEY carrid.  "key carrid 설정.

SELECT carrid connid fldate
  INTO CORRESPONDING FIELDS OF TABLE gt_itab
  FROM sflight.                 "gt_itab에 sflight에 있는 carrid connid 정보를 다 넣음.

DELETE gt_itab WHERE carrid 'AA' AND connid '0017'.   "gt_itab에서 WHERE조건을 만족하는 것들 다 삭제.

LOOP AT gt_itab INTO gs_line.   "출력"
  WRITE/ gs_line-carridgs_line-connid.
ENDLOOP.

* 8-3) INDEX를 이용해 삭제
* DELETE itab <index idx].

* 다음 구문을 이용해서 한번에 여러 라인을 삭제할 수 있다.
* DELETE itab FROM n1 TO n2.    " n1 ~ n2 까지 다 삭제
* DELETE itab FROM n1. "n1부터 끝까지 다삭제
* DELETE itab TO n2.  "처음부터 n2까지 다 삭제.

DATABEGIN OF gs_line,
    col1 type i,
    col2 type i,
  END OF gs_line.

  DATAgt_itab LIKE TABLE OF gs_line.

  DO TIMES.
    gs_line-col1 sy-index.
    gs_line-col2 sy-index 2.
    APPEND gs_line TO gt_itab.
    ENDDO.

    DELETE gt_itab INDEX 2.

    LOOP AT gt_itab INTO gs_line.
      WRITE/ gs_line-col1gs_line-col2.
      ENDLOOP.

* 8-4 ADJACENT DUPLICATE 구문을 이용해 중복라인 삭제.
* ADJACENT DUPLICATE를 사용해서 중복 라인을 삭제할 수 있다.
* ADJACENT DUPLICATE를 사용하기 전에 항상 SORT구문을 이용해서 정렬을 해줘야 한다.

*DELETE ADJACENT DUPLICATE ENTRIES FROM ITAB [COMPARING f1 f2].
* COMPARING을 이용해서 중복라인을 정하는 기준을 정해줄 수 있다.      .
* COMPARING을 사용하지 않는다면 TABLE KEY값이 중복된 데이터를 삭제한다.
* KEY값을 정해주지 않았을 때는 문자열의 선행 필드들이 Default KEY로 구분된다.

DATABEGIN OF gs_line,
  carrid TYPE sflight-carrid,
  connid TYPE sflight-connid,
  END OF gs_line.

  DATAgt_itab LIKE TABLE OF gs_line WITH HEADER LINE.

      SELECT carrid connid
        INTO CORRESPONDING FIELDS OF TABLE gt_itab
        FROM sflight.

       DELETE ADJACENT DUPLICATES FROM gt_itab.

       LOOP AT gt_itab .
         WRITE/ gt_itab-carridgt_itab-connid.
         ENDLOOP.

* --------------------------------
* 9. 인터널 테이블 읽기
* --------------------------------

* 인터널 테이블에서 원하는 데이터를 읽으려면 READ구문을 사용한다.

* 9-1) TABLE KEY 이용.
* KEY값을 이용하여 값을 찾을 수 있다.
* 헤더라인이 있으면 바로 복사, 없으면 wa에 복사.
* 성공하면 sy-subrc = 0. 실패하면 sy-subrc = 4.

* READ TABLE itab FROM wa INTO result.
* READ TABLE itab WITH TABLE KEY k1 = f1, kn = fn INTO result.

DATABEGIN OF gs_line,
        carrid   TYPE scarr-carrid,
        carrname TYPE scarr-carrname,
      END OF gs_line.

DATAgt_itab LIKE TABLE OF gs_line WITH NON-UNIQUE KEY carrid.

SELECT carrid carrname
  INTO CORRESPONDING FIELDS OF TABLE gt_itab
  FROM scarr.

gs_line-carrid 'AA'"인터널 테이블의 값을 읽어주기 위해서 wa를 이용함.
READ TABLE gt_itab FROM gs_line INTO gs_line.   "FROM wa 를 이용해서 인터널 테이블을 읽어주고 출력하기 위해서 INTO wa를 사용함.
WRITE/ gs_line-carridgs_line-carrname.
CLEAR gs_line.

READ TABLE gt_itab WITH KEY carrid 'AB' INTO gs_line.   "KEY 값을 이용해서 인터널 테이블을 읽어주고 출력하기 위해 INTO wa를 사용함.
WRITE/ gs_line-carridgs_line-carrname.


* 8-2) work area 할당
* READ구문의 수행결과를 wa로 할당하는 구문
* READ TABLE itab WITH KEY k1 = f1 INTO wa [COMPARING f1 f2 ] [TRANSPORTING f1 f2]

* 8-2-1) READ구문의 COMPARING 옵션
* comparing구문 다음에 오는 field들이 wa 값과 itab의 값이 같으면 sy-subrc = 0을 반환, 같지 않으면 sy-subrc = 2를 반환.

DATABEGIN OF gs_line,
        col1 TYPE c,
        col2 TYPE i,
      END OF gs_line.

DATAgt_itab LIKE SORTED TABLE OF gs_line WITH UNIQUE KEY col1.

gs_line-col1 'A'.
gs_line-col2 1.
INSERT gs_line INTO TABLE gt_itab.

CLEAR gs_line.

gs_line-col1 'B'.
gs_line-col2 2.
INSERT gs_line INTO TABLE gt_itab.

CLEAR gs_line.

gs_line-col1 'A'.

READ TABLE gt_itab FROM gs_line INTO gs_line COMPARING col2.    "COMPARING 뒤에오는 필드인 col2를 wa값과 비교했을 떄
"현재 col2 값은 없으므로 sy-subrc = 2를 반환.

WRITE' sy-subrc = 'sy-subrc.
WRITE'RESULT IS = 'gs_line-col1gs_line-col2.

* 8-2-2) READ구문의 TRANSPORTING 옵션
* TRANSPORTING은 READ한 결과를 해당 칼럼만 Target에 저장하는 기능을 수행.

DATABEGIN OF gs_line,
        col1    TYPE c,
        col2(7TYPE c,
      END OF gs_line.

DATA gt_itab LIKE SORTED TABLE OF gs_line WITH UNIQUE KEY col1"WITH UNIQUE KEY와 WITH NON-UNIQUE KEY의 차이점?
DATAgs_wa LIKE LINE OF gt_itab.

gs_line-col1 'A'.
gs_line-col2 'First'.
INSERT gs_line INTO TABLE gt_itab.

CLEAR gs_line.
gs_line-col1 'B'.
gs_line-col2 'Second'.
INSERT gs_line INTO TABLE gt_itab.

CLEAR gs_line.

gs_line-col1 'A'.

READ TABLE gt_itab WITH TABLE KEY col1 'A' INTO gs_wa TRANSPORTING col2.  " TABLE KEY값에 맞는 값을 읽어서 gs_wa로 보내주지만, TRANSPORTING뒤에 오는 필드인 col2만 보내준다.

WRITE'COL1 is : 'gs_wa-col1'Col2 is: 'gs_wa-col2.


* 8-3) INDEX를 이용해 READ 구문 수행.
* INDEX를 이용하여 해당라인의 값을 읽을 수 있다.
* 성공하면 sy-subrc = 0을 반환, 실패시 sy-subrc = 4를 반환.
* READ TABLE itab INDEX idx INTO wa.

DATABEGIN OF gs_line,
        col1    TYPE c,
        col2(7TYPE c,
      END OF gs_line.

DATAgt_itab LIKE SORTED TABLE OF gs_line WITH UNIQUE KEY col1"SORTED를 해야지 UNIQUE KEY가 먹힘.

gs_line-col1 "A'.
gs_line-col2 'First'.
INSERT gs_line INTO TABLE gt_itab.

CLEAR gs_line.
gs_line-col1 'B'.
gs_line-col2 'Second'.
INSERT gs_line INTO TABLE gt_itab.

CLEAR gs_line.

READ TABLE gt_itab INTO gs_line INDEX 1.   " INSERT한 순서대로 INDEX 순번이 저장된다.
wirte'Col1 is :'gs_line-col1'Col2 is : 'gs_line-col2.

* 8-4) READ BINARY SEARCH
* 아직.

OPEN SQL study ABAP study

*SELECT - ENDSELECT 구문을 활용 vs SELECT - LOOP - ENDLOOP활용 비교
*
*SELECT - ENDSELECT 구문

DATAgt_itab TYPE STANDARD TABLE OF sflight,    "이거 없어도 되지 않음?
      gs_wa   TYPE sflight.

SELECT *                          " *은 테이블의 모든 칼럼을 읽는다.
  INTO gs_wa                      " gs_wa(테이블 변수)로 보내라
  FROM sflight                      "sflight로부터
WHERE carrid 'AA'.           "carrid = ''AA'와 일치하는 조건을 가진
  WRITE/ gs_wa-carridgs_wa-connid.   "gs_wa-carrid, gs_wa-connid를 출력하라.
ENDSELECT.


 SELECT LOOP ENDLOOP 구문 활용

DATAgt_itab TYPE STANDARD TABLE OF sflight,    ""sflight 테이블 형태를 갖는 인터널 테이블 gt_itab선언
      gs_wa   TYPE sflight.                                         "sflight 테이블 형태를 갖는 work area gs_wa선언

SELECT *                                                                   "*은 테이블의 모든 칼럼을 읽는다.
  INTO TABLE gt_itab                                                     " 인터널 테이블 gt_itab으로 보내라
  FROM sflight WHERE carrid EQ 'AA'.                         "  테이블 sflight에서 carrid = 'AA'의 조건을 만족하는 칼럼들을

LOOP AT gt_itab INTO gs_wa.                                       " 인터널 테이블 gt_itab에서 work area gs_wa로 보내서 WRITE를 출력해라/.
  WRITE/ gs_wa-carridgs_wa-connid.
ENDLOOP.




DATAgt_itab TYPE STANDARD TABLE OF sflight,      "standard table 형태의 sflight typㄷ인 인터널 테이블 gt_itab선언
      gs_wa   LIKE LINE OF gt_itab.                              "인터널 테이블 gt_itab 타입의 work area gs_wa선언

DATAgs_line(72TYPE c,                                          "gs_line 선언 ??????

      gt_list     LIKE TABLE OF gs_line(72).                    " ------------아직 이해 못함
      gs_line 'CARRID CONNID'.

SELECT DISTINCT (gs_lineINTO TABLE gt_itab
  FROM sflight.
IF sy-subrc 0.
  LOOP AT gt_itab INTO gs_wa.
    WRITE/ gs_wa-carridgs_wa-connid.
  ENDLOOP.
ENDIF.


*---------------------------
*2. INTO 구문
*---------------------------
*
* 2-1) work area
* select * 은 개별 필드를 select하는 것보다 비효율 적임.
* corresponding fields of <wa>를 사용하여 효율 적으로 결과를 반환한다.
* 예를 들어,
* SELECT connid cannid FROM <인터널 테이블> INTO CORRESPONDING OF <work area>
*
* 2-2) internal table


DATAgs_wa   TYPE sflight,          "sflight의 필드 이름을 가진 구조체 형태의 work area 선언.
      gt_itab TYPE TABLE OF sflight.   "sflight 테이블 그대로 형태의 인터널 테이블 선언.

SELECT carrid connid
  FROM spfli
  INTO CORRESPONDING FIELDS OF TABLE gt_itab "spfli와 gt_itab은 다른 구조로 되어 있기 떄문에 CORRESponding을 사용함.
  PACKAGE SIZE 5.         "spfli로부터 gt_itab과 일치하는 carrid와 connid를 5개 가져와  //// 5개의 값을 여러번 불러와 LOOP를 실행한다.
                                        "PACKAGE SIZE를 정해주었을 때는 ENDSELECT를 꼭 써쭤야 한다.
  LOOP AT gt_itab INTO gs_wa.     " LOOP문 실행
    WRITE/ gs_wa-carridgs_wa-connid.
  ENDLOOP.
ENDSELECT.

* -------------------------------------
* 3. FROM 구문
*---------------------------------------
*FROM 구문은 SELECT할 대상 테이블을 지정한다.
*FROM 구문에는 하나의 테이블을 지정하거나 여러 개의 테이블을 JOIN할 수 있다.(여러개의 테이블로부터 SELECT하기위해)
*Alias를 사용하여 테이블 명에 별명을 붙일 수 있다. = 쉽게 쓰기 위해서
*
*
* 3-1) 정적인 Table 선택
* SELECT ______   FROM 한개의 테이블 AS 테이블 별명 <option>
*
*3-2) 동적인 Table 선택
* 사용자가 원하는 테이블 이름을 직접 입력 받아서 데이터를 출력(PARAMETERS)

PARAMETERS p_tname TYPE char10.   "사용자가 원하는 테이블 명을 직접 입력 받음
DATA gs_wa TYPE sflight.                      "work area 선언

SELECT SINGLE *                                  "* = 전체를 탐색하고, single = 하나만 찾음.
            INTO gs_wa                               "입력받은 (p_tname)에서 carrid = 'AA'인 조건을 만족하는 부분을 gs_wa로 전달.
            FROM (p_tname)
            WHERE carrid 'AA'.

  WRITE/ gs_wa-carridgs_wa-connidgs_wa-fldate.

* 3-3) JOIN 구문
* 여러 개의 테이블 값을 동시에 읽어오고 싶은 경우 JOIN구문을 사용한다.
* ON 구문과 WHERE 이 같이 있다면, WHERE조건이 먼저 수행되고, 이 데이터를 기준으로 ON 조건에서 JOIN하게 된다.

TYPESBEGIN OF t_str,                         "t_str이라는 구조체  타입 선언.
    carrid TYPE sflight-carrid,
    carrname TYPE scarr-carrname,
 END OF t_str.

 DATAgs_str type t_str.        " 선언한 구조체 타입으로 구조체 선언.

 SELECT SINGLE a~carrid b~carrname
   INTO CORRESPONDING FIELDS OF gs_str       "where, on 조건을 만족하는 FROM, JOIN으로부터 a~carrid, b~carrname을 gs_str에 넣어라.
   FROM sflight as a
   JOIN scarr as b                                              "JOIN은 기본적으로 INNER JOIN으로 설정된다. // a, b 별명을 설정해주지 않으면 변수명을 다 써줘야 된다.
   on a~carrid b~carrid                                  "ON과 WHERE이 같이 있을 경우, WHERE조건이 만족 후 그 데이터에서 ON조건을 만족하는 field를 찾는다.
   WHERE a~carrid 'AZ'.

   WRITEgs_str-carridgs_str-carrname.

* 3-4) INNER JOIN과 OUTER JOIN
* INNER JOIN은 교집합.  OUTER JOIN은 합집합.
* OUTER JOIN은 LEFT OUTER JOIN이 기준이다!!!

TYPESBEGIN OF t_str,                        "t_str이라는 구조체 타입 선언
    carrid TYPE sflight-carrid,
    carrname TYPE scarr-carrname,
  END OF t_str.

  DATAgs_str TYPE t_str.        "선언한 구조체 타입을 가지는 구조체 선언

  SELECT SINGLE a~carrid b~carrname              "(FROM) sflight 에서 그리고 scarr에서
        INTO CORRESPONDING FIELDS OF gs_str
        FROM sflight as a
        LEFT OUTER JOIN SCARR as b
  ON a~carrid b~carrid                         " 교집합 조건. 둘다 포함하는 조건
    WHERE a~carrid 'AZ'.                       " a~carrid = 'AZ' 조건을 만족하는 데이터에서 a~carrid = b~carrid인 데이터를 gs_str에 넣어라.

    WRITEgs_str-carridgs_str-carrname.

* 3-5) line 수 제한
* 최대 적중수를 제한하지 않으면 모든 데이터를 읽기 때문에 서버에 부하를 주게 된다.

*-------------------------------------------------
*4. WHERE 구문
*-------------------------------------------------
*where 조건은 사용자가 원하는 데이터를 정확하게 선택할 수 있도록 하는 조건
*index에서 사용될 때 빠른 성능
*연산자
*
* 4-1) interval 조건
* 조건에 범위 값을 사용할 떄 사용
* WHERE col1 BETWEEN 1 and 10          "COL1 칼럼이 1~10까지 인 경우
*
* 4-2) string 조건
* 문자열을 비교할 때 사용
* WHERE COL2 LIKE 'ABC%'. "ABC로 시작하는 조건.
* WHERE COL2 LIKE 'ABC_'. "ABC로 시작하는 4자리 조건.
*
* 4-3, 4-4) LIST VALUE, SELECTION TABLE
* 여러 조건에 속한 경우  --> WHERE 거주지 IN ('서울', '수원')
* SELECTION TABLE, RANGE 변수에 존재하는 값들을 조회 --> WHERE <s> IN <TABLE>
*
* 4-5, 4-6은 넘어감
*
*--------------------------------------------------
*5. GROUPING 구문
*--------------------------------------------------
*Aggregate 함수(평균, 개수, 최대값, 최소값, 표준편차, 합계, 분산)등을 사용하려면 GROUP BYr구문을 사용해야 한다.

DATAgv_carrid     TYPE sflight-carrid,
      gv_connid     TYPE sflight-connid,
      gv_paymentsum TYPE i.

SELECT carrid connid AVGpaymentsum )         "carrid connid AVG를 INTO ____________에 넣자.
  INTO (gv_carridgv_connidgv_paymentsum)
  FROM sflight GROUP BY carrid connid.              "sflight 에서 / carrid connid 그룹해서 AVG 하자. 
  WRITE/ gv_carridgv_connidgv_paymentsum.
ENDSELECT.

* ----------------------------------------------
* 7. SORT 구문
*-----------------------------------------------
*SELECT 결과로 조회된 데이터가 ORDER BY에 기술된 칼럼 기준으로 정렬된다.
*ORDER BY를 사용하지 않으면 임의로 정렬된 결과
* 1) ORDER BY PRIMARY KEY
* 2) ORDER BY < 필드명 > ascending / descending 

c# study : 클래스 c# study


//this 키워드
//객체 내부에서(클래스 내부에서) 객체가 자신의 필드나 메소드에 접근할 때 this키워드를 사용
//
namespace This
{
    class Employee
    {
        private string Name;
        private string Position;
    
        public void SetName(string Name) // SetName 메소드는 Employee 클래스의 변수인 Name(this.Name)에  
                                         // 입력받은 매개변수 Name을 저장하는 기능. 
        {
            this.Name = Name;  
        }

        public string GetName()  // GetName 메소드는 Name을 반환.
        {
            return Name;
        }

        public void SetPosition(string Position) // SetPosition 메소드는 Employee 클래스의 변수인 Position(this.Position)에
        {                                        // 입력받은 매개변수 Position을 저장하는 기능.
            this.Position = Position;
        }

        public string GetPosition() // GetPosition 메소드는 Position을 반환.
        {
            return this.Position;
        }
    }
    class MainApp
    {
        static void Main(string[] args)
        {
            Employee pooh = new Employee();  // Employee클래스의 pooh라는 인스턴스 생성
            pooh.SetName("Pooh");            // SetName에 매개변수 Pooh 저장
            pooh.SetPosition("Waiter");      // SetPosition에 매개변수 Waiter 저장

            Console.WriteLine($"{pooh.GetName()} {pooh.GetPosition()}"); // 반환

            Employee tigger = new Employee(); // 위 내용과 같음.
            tigger.SetName("Tigger");
            tigger.SetPosition("Cleaner");
            Console.WriteLine($"{tigger.GetName()} {tigger.GetPosition()}");
        }
    }
}




// 접근 한정자로 공개 수준 결정하기
// 은닉성 - 클래스의 사용자(프로그래머 or 코더)에게 필요한 최소의 기능만을 노출하고 내부는 감춤
// 필드, 메소드, 프로퍼티 등 모든 요소에 사용
// public, protected, private, internal...
// 접근 한정자로 수식하지 않은 클래스의 멤버는 private로 접근 수준이 자동으로 지정

namespace AccessModifier
{
    class WaterHeater
    {
        protected int temperature;  // temperature 변수의 접근 범위가 protected - 파생클래스에서만 접근 가능

        public void SetTemperature(int temperature)
        {
            if (temperature < -5 || temperature > 42)
            {
                throw new Exception("Out of temperature range"); // if 범위에서 throw 예외던지기
            }

            this.temperature = temperature;
        }

        internal void TurnOnWater() // internal - 같은 어셈블리 코드에서만 public으로 접근 가능
        {
            Console.WriteLine($"Turn on water : {temperature}");
        }
    }

    class MainApp
    {
        static void Main(string[] args)
        {
            try // 실행하고자 하는 코드
            {
                WaterHeater heater = new WaterHeater(); // 클래스 WaterHeater의 인스턴스 생성
                heater.SetTemperature(20);
                heater.TurnOnWater();

                heater.SetTemperature(-2);
                heater.TurnOnWater();

                heater.SetTemperature(50); // 예외가 발생하여 catch블록으로 실행위치가 이동함
                heater.TurnOnWater();
            }

            catch(Exception e) // 예외가 발생했을 때 코드
            {
                Console.WriteLine(e.Message);
            }
        }
    }
}


// 상속으로 코드 재활용하기
// 파생클래스, 기반클래스
// 기반클래스의 멤버에 접근하기 위해서 base 키워드 사용. this키워드 처럼 사용.
// 파생클래스의 생성자에서 기반클래스의 생성자에게 매개변수를 넘겨주는 방법.
// base() - 기반클래스 생성자 이용.
// 어려움 아직 해석 못함!

namespace Inheritance
{
    class Base
    {
        protected string Name;
        public Base(string Name)
        {
            this.Name = Name;
            Console.WriteLine($"{this.Name}.Base()");
        }

        ~Base()
        {
            Console.WriteLine($"{this.Name}.~Base()");
        }

        public void BaseMethod()
        {
            Console.WriteLine($"{Name}.BaseMethod()");
        }
    }

    class Derived : Base
    {
        public Derived(string Name) : base(Name)
        {
            Console.WriteLine($"{this.Name}.Derived()");
        }

        ~Derived()
        {
            Console.WriteLine($"{this.Name}.~Derived()");
        }

        public void DerivedMethod()
        {
            Console.WriteLine($"{Name}.DerivedMethod()");
        }
    }

    class MainApp
    {
        static void Main(string[] args)
        {
            Base a = new Base("a");
            a.BaseMethod();

            Derived b = new Derived("b");
            b.BaseMethod();
            b.DerivedMethod();
        }
    }
}

// 기반 클래스와 파생 클래스 사이의 형식 변환, 그리고 is와 as
// Mammal - 기반클래스, Dog, Cat - 파생클래스
// (Dog)mammal, (Cat)mammal 로 형식 변환
// 형변환을 위한 연산자 is와 as
// is - 객체가 해당 형식에 해당하는 지를 검사하여 결과를 bool값으로 반환
// ex) if (mammal is Dog)
// as - 형식변환 연산자와 같은 역할. cast강제 변환보다는 as를 사용하는게 좋음. 변환에 실패할 경우 null로 만듬.
// ex) (Dog)mammal -> mammal as Dog
// 즉, is로 형식 확인 후 as로 형 변환.

namespace TypeCasting
{
    class Mammal
    {
        public void Nurse()
        {
            Console.WriteLine("Nurse()");
        }
    }

    class Dog : Mammal // Mammal 기반 클래스.
    {
        public void Bark()
        {
            Console.WriteLine("Bark()");
        }
    }

    class Cat : Mammal // Mammal 기반 클래스.
    {
        public void Meow()
        {
            Console.WriteLine("Meow()");
        }
    }

    class MainApp
    {
        static void Main(string[] args)
        {
            Mammal mammal = new Dog(); // 기반클래스 Mammal는 파생클래스 Dog()가 생성자로 인스턴스 생성
            Dog dog;

            if (mammal is Dog)
            {
                dog = (Dog)mammal; // dog를 Dog에서 mammal로 변환
                dog.Bark();
            }

            Mammal mammal2 = new Cat();

            Cat cat = mammal2 as Cat; // cat을 Cat에서 mammal2로 변환
            if (cat != null)
                cat.Meow();

            Cat cat2 = mammal as Cat; // cat2을 Cat에서 mammal로 변환
            if (cat2 != null) // cat2가 Cat에서 mammal로 변환되었다면, cat2.Meow()반환
                cat2.Meow();
            else
                Console.WriteLine("cat2 is not a Cat"); // cat2가 Cat에서 mammal로 변환되지 못했다면 cat2는 Cat이 아님.
        }
    }
}


c# study : 클래스 c# study

//객체 지향 프로그래밍 --> 모든 것을 객체로 표현
//객체 ( 속성(변수) + 기능(메소드))
//int a = 30; --> int = 클래스, a = 객체
// 클래스(변수 + 메소드) ==> 객체를 만들기 위한 청사진
    
//클래스의 선언과 객체의 생성
//클래스 --> 청사진 / 객체(인스턴스) --> 

namespace BasicClass
{
    class Cat
    {
        public string Name;
        public string Color;
        //변수 --> 속성

        public void Meow()
        {
            Console.WriteLine($"{Name} : 야옹");
        }
        //메소드 --> 기능
    }

    class MainApp
    {
        static void Main(string[] args)
        {
            Cat kitty = new Cat(); // 객체(인스턴스) 생성
            kitty.Name = "키티";
            kitty.Color = "하얀색";
            kitty.Meow();
            Console.WriteLine($"{kitty.Name} : {kitty.Color}");

            Cat nero = new Cat(); // 객체(인스턴스) 생성
            nero.Name = "네로";
            nero.Color = "검정색";
            nero.Meow();
            Console.WriteLine($"{nero.Name} : {nero.Color}");

        }
    }
}

//객체의 삶과 죽음에 대하여 : 생성자와 종료자
//생성자는 일부러 구현하지 않아도 컴파일러가 만들어준다. 
//하지만 생성자를 일부러 구현해주는 이유는 객체의 필드를 원하는 값으로 초기화 시켜주고 싶을 때 사용한다.
//종료자는 CLR이 자동으로 불러줌. 가급적 사용하지 않는다.

namespace Constructor
{
    class Cat
    {
        public Cat() // 생성자 생성(매개변수 없는)
        {
            Name = "";
            Color = "";
        }

        public Cat(string _Name, string _Color) // 생성자 생성(매개변수 있는)
        {
            Name = _Name;
            Color = _Color;
        }

        ~Cat() //종료자 생성
        {
            Console.WriteLine($"{Name} : 잘가 ");
        }

        public string Name; // 속성(변수)
        public string Color;

    
        public void Meow() // 기능(메소드)
        {
            Console.WriteLine($"{Name} : 야옹");
        }
    }

    class MainApp
    {
        static void Main(string[] args)
        {
            Cat kitty = new Cat("키티", "하얀색");
            kitty.Meow();
            Console.WriteLine($"{kitty.Name} : {kitty.Color}");

            Cat nero = new Cat("네로", "검정색");
            nero.Meow();
            Console.WriteLine($"{nero.Name} : {nero.Color}");

            Cat jame = new Cat();
            jame.Name = "자메";
            jame.Color = "갈색";
            jame.Meow();
            Console.WriteLine($"{jame.Name} : {jame.Color}");

            Console.ReadKey();

        }
    }
}

//정적 필드와 메소드
//먼저, 클래스 = 청사진, 인스턴스 = 구현된 것.
//정적 필드를 생성하는 이유는 어떤 필드가 그 클래스에 소속된다는 것 = 프로그램 전체에 유일하다는 것.
//정적 필드 = 클래스를 통해서 바로 호출 / 인스턴스 필드 = 인스턴스 생성 후 호출

class Global
{
    public static int Count = 0; // 정적 필드 생성
}

class ClassA
{
    public ClassA()
    {
        Global.Count++; // 클래스를 통해서 정적 필드에 직접 접근
    }
}

class ClassB
{
    public ClassB()
    {
        Global.Count++; // 클래스를 통해서 정적 필드에 직접 접근
    }
}

class MainApp
{
    static void Main()
    {
        Console.WriteLine($"Global.Count : {Global.Count}");

        new ClassA();
        new ClassA();
        new ClassB();
        new ClassB();

        Console.WriteLine($"Global.Count : {Global.Count}");
    }
}

//클래스(필드 + 메소드)
//정적 메소드도 정적 필드와 같음
//클래스를 통해서 직접 접근



//객체 복사하기 : 얕은 복사와 깊은 복사
//클래스는 참조형식이라서 깊은 복사 불가
//깊은 복사를 하려면 수행하는 코드를 만들어 줘야 함

namespace DeepCopy
{
    class MyClass
    {
        public int MyField1;
        public int MyField2;

        public MyClass DeepCopy()
        {
            MyClass newCopy = new MyClass();
            newCopy.MyField1 = this.MyField1;
            newCopy.MyField2 = this.MyField2;

            return newCopy;
        }
    }

    class MainApp
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Shallow Copy");
            {                                                //왜 묵어준 거?
                MyClass source = new MyClass();
                source.MyField1 = 10;
                source.MyField2 = 20;

                MyClass target = source;
                target.MyField2 = 30;

                Console.WriteLine($"{source.MyField1}    {source.MyField2}");
                Console.WriteLine($"{target.MyField1}    {target.MyField2}");
            }

            Console.WriteLine("Deep Copy");
            {
                MyClass source = new MyClass();
                source.MyField1 = 10;
                source.MyField2 = 20;

                MyClass target = source.DeepCopy();
                target.MyField2 = 30;
                Console.WriteLine($"{source.MyField1}    {source.MyField2}");
                Console.WriteLine($"{target.MyField1}    {target.MyField2}");
            }
           
        }
    }
}

c# study : 매개 변수 c# study

// 출력 전용 매개 변수
// 메소드의 결과가 두 개 이상일 때 출력 전용 매개 변수를 사용한다. 
// 메소드 선언 시 out키워드를 이용한다. 
/* ref 키워드는 메소드가 해당 매개 변수에 결과를 저장하지 않으면 컴파일러가 에러 메세지를 출력 X
out 키워드는 에러 메세지 출력 O. 안전 장치. */

namespace UsingOut
{
    class MainApp
    {
        static void Divide(int a, int b, out int quotient, out int remainder)
        {
            quotient = a / b;
            remainder = a % b;
        }

        static void Main(string[] args)
        {
            int a = 20;
            int b = 3;
            // int c 
            // int d 
            // 변수 c, d를 미리 선언하지 않고 메소드 호출 시 즉석으로 선언.

            Divide(a, b, out int c, out int d);

            Console.WriteLine($"a: {a}, b: {b}, a/b: {c}, a%b: {d}");
        }
    }
}

//메소드 오버로딩
//하나의 메소드 이름에 여러 개의 구현을 올리는 것.
//다양한 형식을 지원하는 동일 메소드를 만들기 위해서 사용.

namespace Overloading
{
    class MainApp
    {
        static int Plus(int a, int b)
        {
            Console.WriteLine("Calling int Plus(int, int)...");
            return a + b;
        }

        static int Plus(int a, int b, int c)
        {
            Console.WriteLine("Calling int Plus(int, int, int)...");
            return a + b + c;
        }

        static double Plus(double a, double b)
        {
            Console.WriteLine("Calling double Plus(double, double)...");
            return a + b;
        }

        static double Plus(int a, double b)
        {
            Console.WriteLine("Calling double Plus(int, double)...");
            return a + b;
        }

        static void Main(string[] args)
        {
            Console.WriteLine(Plus(1, 2));
            Console.WriteLine(Plus(1, 2, 3));
            Console.WriteLine(Plus(1.2, 2.6));
            Console.WriteLine(Plus(1, 2.6));
        }
    }
}

//가변길이 매개 변수
//매개변수의 '수'가 달라서 메소드를 오버로딩 할 때 사용.
//params 키워드와 배열을 이용하여 선언.
namespace UsingParams
{
    class MainApp
    {
        static int Sum(params int[] args)
        {
            Console.Write("Summing...");

            int sum = 0;

            for(int i=0; i<args.Length; i++)
            {
                if (i > 0)
                    Console.Write(", ");

                Console.Write(args[i]);

                sum += args[i];
            }

            Console.WriteLine();

            return sum;
        }

        static void Main(string[] args)
        {
            int sum = Sum(3, 4, 5, 6, 7, 8, 9, 10);

            Console.WriteLine($"Sum : {sum}");
        }
    }
}


//명명된 매개 변수
//일반적인 매개 변수는 순서에 따라 할당.
/*예를 들어, Sum(int a, int b, int c)를 선언, Sum(1, 2, 3) 호출. a=1, b=2, c=3이 각각 할당 된다.*/
//순서가 아닌 이름에 근거해서 데이터를 할당
//메소드 호출 시 매개 변수의 이름 뒤에 콜론(:)을 붙여서 할당.

namespace NamedParameter
{
    class MainApp
    {
        static void PrintProfile(string name, string phone)
        {
            Console.WriteLine($"Name:{name}, Phone:{phone}");
        }

        static void Main(string[] args)
        {
            PrintProfile(name: "박찬호", phone: "010-1234-4567");
            PrintProfile(phone: "010-123-9877", name: "박지성");
            PrintProfile("박세리", "010-4567-4567");
            PrintProfile("박상현", phone: "010-987-45632");
        }
    }
}


//선택적 매개 변수
//매개변수에 기본값을 할당해주어 메소드 호출 시 매개변수  할당을 생략할 수 있음.
//모호함을 불러옴.
//오버로딩 + 선택적 매개 변수 사용. --> 모호함. 0점짜리 코드

namespace OptionalParameter
{
    class MainApp
    {
        static void PrintProfile(string name, string phone = "")
        {
            Console.WriteLine($"Name: {name}, Phone: {phone}");
        }

        static void Main(string[] args)
        {
            PrintProfile("태연"); // phone에 기본값 할당. 호출 시 생략
            PrintProfile("윤아", "010-1234-4567");
            PrintProfile(name: "유리");
            PrintProfile(name: "서현", phone: "010-4567-7845");
        }
    }
}

//로컬 함수
//메소드 안에서 선언되고, 선언된 메소드 안에서만 사용되는 함수
//메소드 밖에서는 다시 쓸 일 없는 반복적인 작업을 설정.

1