쇼핑몰을 개발하는 중이라고 가정하자

고객이 배송율 현황을 만들어 달라고 했다.

헤더 행 당일배송 익일배송 총배송 당일배송률
데이터행...        
데이터행...        
데이터행...        
마지막 집계 행        

 

위와 같은 집계 그리드 중 마지막 집계 행에 당일배송율에 대한 주

의점을 알아보자

//DB에서 뽑힌 데이터 갯수 설정
const ROWNUM = 10;
//DB에서 뽑힌 데이터라 가정
var dbData = [];
for (let i = 0; i < ROWNUM; i++) {
    var val1 = Math.floor(Math.random() * 100)+1;
    var val2 = Math.floor(Math.random() * 50)+1;
    var sum = val1+val2;
    var per = Math.round((val1/sum*10000))/100;
    dbData.push({당일배송 : val1, 익일배송: val2 , 총배송 : sum, 당일배송률 : per});
}

console.log(dbData);

위와 같은 데이터에서 마지막 집계 행에 당일배송률에 대한 평균값을 구해야한다.

 

당일배송률 평균을 구하기 위해 "당일배송률 합계 / 전체행 수" 로 나눴다.

var count = 0;
var 잘못된당일배송률평균 = dbData.map(row=>{
    count++;
    return row.당일배송률;
}).reduce((a,b)=>a+b) /count;

console.log('잘못된당일배송률평균',Math.round(잘못된당일배송률평균*100)/100);

과연 올바른 값일까?

 

잘못된 값이다. 당일배송률은 이미 가공된 데이터이다.

그 가공된 데이터에 대한 평균값을 구한 것이지, 전체 모수로하는 당일배송률 평균이 아니다. 

 

올바른 값을 알아보자

 

var 총배송합계 = dbData.map(row=>{
    return row.총배송;
}).reduce((a,b)=>a+b);
console.log('총배송합계',총배송합계);


var 당일배송합계 = dbData.map(row=>{
    return row.당일배송;
}).reduce((a,b)=>a+b);
console.log('당일배송합계',당일배송합계);


var 익일배송합계 = dbData.map(row=>{
    return row.익일배송;
}).reduce((a,b)=>a+b);
console.log('익일배송합계',익일배송합계);

//전체 행 수
var count = 0;
var 잘못된당일배송률평균 = dbData.map(row=>{
    count++;
    return row.당일배송률;
}).reduce((a,b)=>a+b) /count;

console.log('잘못된당일배송률평균',Math.round(잘못된당일배송률평균*100)/100);

console.log('제대로된당일배송률평균',Math.round(당일배송합계/총배송합계 *10000)/100);

잘못된당일배송률평균은 당일배송율평균 간 평균값이 계산된 것이다.

반면에 제대로된당일배송률평균은 전체를 하나의 행으로 집계하고 그 결과를 가공해 평균값을 만들었다.

따라서 전체를 대표하는 평균값이 계산된 것이다.

평균구하기주의점.html
0.00MB

 

 

 

 

 

 

 

 

'개발 > 자바스크립트' 카테고리의 다른 글

구조 분해 할당  (0) 2023.08.21
배열은 객체?  (0) 2023.08.18
반올림 함수  (0) 2023.04.10
자바스크립트 중복제거 - 2  (0) 2022.12.15
자바스크립트 중복 제거  (0) 2022.12.12
SELECT (SELECT MAX(sal) FROM emp) AS MAX
      ,(SELECT MIN(sal) FROM emp) AS MIN
      ,(SELECT AVG(sal) FROM emp) AS AVG
      ,(SELECT SUM(sal) FROM emp) AS SUM
  FROM dual;
-- 위는 극단적인 대조를 위한 예시
SELECT DISTINCT  MAX(sal) OVER()  AS MAX   
     , MIN(sal) OVER()  AS MIN   
     , AVG(sal) OVER()  AS AVG   
     , SUM(sal) OVER()  AS SUM   
  FROM EMP;

결과는 같다. 다만 결과를 산출하는 방식에 차이가 있다.

윈도우 함수는 한 번 참조한 테이블을 버퍼로 활용한다.

 

스칼라 서브쿼리
윈도우 함수

SELECT DISTINCT DEPTNO 
     , MAX(sal) OVER(PARTITION BY DEPTNO)  AS MAX   
     , MIN(sal) OVER(PARTITION BY DEPTNO)  AS MIN   
     , AVG(sal) OVER(PARTITION BY DEPTNO)  AS AVG   
     , SUM(sal) OVER(PARTITION BY DEPTNO)  AS SUM   
  FROM EMP;
 
SELECT DEPTNO
      ,MAX(SAL) AS MAX
      ,MIN(SAL) AS MIN
      ,AVG(SAL) AS AVG
      ,SUM(SAL) AS SUM
  FROM EMP
 GROUP BY DEPTNO;

GROUP BY 사용 시 해당 절에 열거된 컬럼만 사용이 가능하다. 

이런 제약에서 자유롭기 때문에 좀 더 유연하게 결과를 도출할 수 있다.

 

 

'개발 > 오라클 SQL' 카테고리의 다른 글

지정 요일 주차 구하기  (1) 2023.02.01
집계 함수 사용 시 주의사항  (0) 2023.01.15
컬럼 <=> 행 변환  (0) 2023.01.13
숫자 함수 응용  (0) 2023.01.10
자주 쓰는 함수 모음  (1) 2023.01.07
SELECT NUM
     , VALUE
FROM (
      SELECT TRUNC(DBMS_RANDOM.VALUE(1,1000)) NUM 
           , DECODE(MOD(TRUNC(DBMS_RANDOM.VALUE(1,1000)) ,2),0,NULL 
                   ,TRUNC(DBMS_RANDOM.VALUE(1,1000))) VALUE  --짝수면 NULL
        FROM DUAL
      CONNECT BY LEVEL <=10
     );

짝수면 NULL이 나오게 했다.

SELECT 
     DISTINCT AVG(VALUE) OVER() AVG1  --NULL포함 안함
     , AVG(NVL(VALUE,0)) OVER() AVG2  -- NULL포함
     , SUM(VALUE) OVER() / COUNT(VALUE) OVER() AVG3 --NULL포함 안함
     , SUM(VALUE) OVER() / COUNT(*) OVER()     AVG4 --카운트만 NULL포함
     , SUM(VALUE) OVER() / COUNT(NVL(VALUE,0)) OVER() AVG5 -- 카윤트만 NULL 포함
     , COUNT(VALUE) OVER() CN1
     , COUNT(1) OVER() CN2
FROM (
      SELECT TRUNC(DBMS_RANDOM.VALUE(1,1000)) NUM 
           , DECODE(MOD(TRUNC(DBMS_RANDOM.VALUE(1,1000)) ,2),0,NULL 
                   ,TRUNC(DBMS_RANDOM.VALUE(1,1000))) VALUE  --짝수면 NULL
        FROM DUAL
      CONNECT BY LEVEL <=10
     );

기본적으로 집계함수는 NULL 값을 제외한다. 따라서 AVG함수나, COUNT함수는 주의해서 사용해야 한다.

NULL인 값을 포함해서 계산을 하고 싶은 경우도 많기 때문이다.

 

추가로 집계함수의 NULL 처리 방식을 이해하면 아래 중 무엇이 잘못된 사용 방식인지 판별할 수 있다.

SELECT SUM(NVL(123,0)) FROM DUAL;
SELECT NVL(SUM(123), 0) FROM DUAL;

1번 째의 경우 나름 생각한다고 NULL처리를 했지만 DB에 불필요한 부하를 주게 된다.

내부적으로 NULL을 처리하는데 개발자가 NVL을 또 주었으니 불필요한 연산이 들어가게 된다.

이게 행이 많고, 집계함수를 몇 십개 쓴다고 생각해보자. 

 

'개발 > 오라클 SQL' 카테고리의 다른 글

지정 요일 주차 구하기  (1) 2023.02.01
WINDOW함수와 DISTINCT조합  (0) 2023.01.19
컬럼 <=> 행 변환  (0) 2023.01.13
숫자 함수 응용  (0) 2023.01.10
자주 쓰는 함수 모음  (1) 2023.01.07

WITH TMP AS
(
SELECT WORD
       ,SUBSTR(WORD, ROWNUM, 1) COL_TO_ROWS
FROM(
    SELECT 'ADSFGWEQWE' WORD FROM DUAL
    )
CONNECT BY LEVEL <= LENGTH(WORD)
)
, TMP2 AS
(
SELECT DECODE(ROWNUM,1,COL_TO_ROWS) "1"
      ,DECODE(ROWNUM,2,COL_TO_ROWS) "2"
      ,DECODE(ROWNUM,3,COL_TO_ROWS) "3"
      ,DECODE(ROWNUM,4,COL_TO_ROWS) "4"
      ,DECODE(ROWNUM,5,COL_TO_ROWS) "5"
      ,DECODE(ROWNUM,6,COL_TO_ROWS) "6"
      ,DECODE(ROWNUM,7,COL_TO_ROWS) "7"
      ,DECODE(ROWNUM,8,COL_TO_ROWS) "8"
      ,DECODE(ROWNUM,9,COL_TO_ROWS) "9"
      ,DECODE(ROWNUM,10,COL_TO_ROWS) "10"
  FROM TMP
)
--SELECT * FROM TMP2;
SELECT MAX("1")||MAX("2")||MAX("3")||MAX("4")||MAX("5")||
       MAX("6")||MAX("7")||MAX("8")||MAX("9")||MAX("10") ROWS_TO_COL
FROM TMP2;

 

TMP2 결과

TMP2 합친 결과

 

컬럼을 행으로 변환할 때는 행을 반복적으로 실행시켜 나눌 수 있지만 본문 "COL_TO_ROWS"

반대로 합칠 때는 수동으로 입력하는 수 밖에 없다. 본문 "ROWS_TO_COL"

WITH R10 AS --미리 만들어둔 반복용 테이블이라 가정
(
SELECT 1 AS NUM FROM DUAL UNION ALL
SELECT 2 AS NUM FROM DUAL UNION ALL
SELECT 3 AS NUM FROM DUAL UNION ALL
SELECT 4 AS NUM FROM DUAL UNION ALL
SELECT 5 AS NUM FROM DUAL UNION ALL
SELECT 6 AS NUM FROM DUAL UNION ALL
SELECT 7 AS NUM FROM DUAL UNION ALL
SELECT 8 AS NUM FROM DUAL UNION ALL
SELECT 9 AS NUM FROM DUAL UNION ALL
SELECT 10 AS NUM FROM DUAL
)
, TMP AS
(
SELECT WORD
       ,SUBSTR(WORD, ROWNUM, 1) COL_TO_ROWS
FROM(
    SELECT 'ADSFGWEQWE' WORD FROM DUAL
    )
    , R10 --데카르트 곱으로 활용
 WHERE R10.NUM <= LENGTH(WORD)  
--CONNECT BY LEVEL <= LENGTH(WORD)

)
, TMP2 AS
(
SELECT DECODE(ROWNUM,1,COL_TO_ROWS) "1"
      ,DECODE(ROWNUM,2,COL_TO_ROWS) "2"
      ,DECODE(ROWNUM,3,COL_TO_ROWS) "3"
      ,DECODE(ROWNUM,4,COL_TO_ROWS) "4"
      ,DECODE(ROWNUM,5,COL_TO_ROWS) "5"
      ,DECODE(ROWNUM,6,COL_TO_ROWS) "6"
      ,DECODE(ROWNUM,7,COL_TO_ROWS) "7"
      ,DECODE(ROWNUM,8,COL_TO_ROWS) "8"
      ,DECODE(ROWNUM,9,COL_TO_ROWS) "9"
      ,DECODE(ROWNUM,10,COL_TO_ROWS) "10"
  FROM TMP
)
--SELECT * FROM TMP2;
SELECT MAX("1")||MAX("2")||MAX("3")||MAX("4")||MAX("5")||
       MAX("6")||MAX("7")||MAX("8")||MAX("9")||MAX("10") ROWS_TO_COL
FROM TMP2;

CONNECT BY 를 꼭 안쓰더라도 위 처럼 사용하는 경우도 많다.

'개발 > 오라클 SQL' 카테고리의 다른 글

WINDOW함수와 DISTINCT조합  (0) 2023.01.19
집계 함수 사용 시 주의사항  (0) 2023.01.15
숫자 함수 응용  (0) 2023.01.10
자주 쓰는 함수 모음  (1) 2023.01.07
SELECT 문으로 SQL문 만들기  (0) 2023.01.05
	SELECT 
	       MONTH 
	     , EXTRACT (MONTH FROM MONTH) /3 M1
	     , CEIL(EXTRACT (MONTH FROM MONTH) /3) M2
	     , MOD(EXTRACT (MONTH FROM MONTH) ,3) M3
	 FROM(
		SELECT ADD_MONTHS(TRUNC(SYSDATE ,'YYYY'), LEVEL-1) MONTH  
		 FROM DUAL
		CONNECT BY LEVEL <= 12
	     )

리포트나 통계를 낼 때 그룹핑을 위한 값을 생성할 때 숫자함수가 유용하다.

 

SELECT M2
	  ,M3
	  ,DECODE(M3, 1, M2||'분기') M4
	  ,MONTH
 FROM(
	SELECT 
	       MONTH 
	     , EXTRACT (MONTH FROM MONTH) /3 M1
	     , CEIL(EXTRACT (MONTH FROM MONTH) /3) M2
	     , MOD(EXTRACT (MONTH FROM MONTH) ,3) M3
	 FROM(
		SELECT ADD_MONTHS(TRUNC(SYSDATE ,'YYYY'), LEVEL-1) MONTH  
		 FROM DUAL
		CONNECT BY LEVEL <= 12
	     )
     )
;

 

 

 

 

 

 

 

'개발 > 오라클 SQL' 카테고리의 다른 글

집계 함수 사용 시 주의사항  (0) 2023.01.15
컬럼 <=> 행 변환  (0) 2023.01.13
자주 쓰는 함수 모음  (1) 2023.01.07
SELECT 문으로 SQL문 만들기  (0) 2023.01.05
중복 데이터 삭제  (0) 2023.01.03
--올림, 내림, 반올림
SELECT 
    CEIL(10.3) C -- 정수만 가능
    ,FLOOR(10.7) F  -- 정수만 가능
    ,ROUND(10.77, 1) R  -- 유일하게 소수점 가능
    ,ROUND(10.77, -2) R -- 유일하게 소수점 가능
    ,ROUND(10.34,1) R
FROM DUAL;
-- SIGN 부호  -1, 0, 1 만 표시  DECODE는 동등비교만 된다
-- SIGN과 같이 사용 시 크기 비교가 가능해진다.
SELECT 
    SIGN(-10)
    ,SIGN(0)
    ,SIGN(20)
FROM DUAL;
SELECT 
    SIGN(-10)
    ,SIGN(0)
    ,SIGN(20)
FROM DUAL;

-- 0으로 만든다.
SELECT TRUNC(123.934, -2) 
    ,TRUNC(SYSDATE)
    ,ROUND(SYSDATE)
    ,ROUND(TO_DATE('20220109 11:59:59', 'YYYYMMDD HH24:MI:SS')) R1
    ,ROUND(TO_DATE('20220109 12:59:59', 'YYYYMMDD HH24:MI:SS')) R2 -- 정오 기준 다음날 아님 오늘
    ,TRUNC(TO_DATE('20220109 11:59:59', 'YYYYMMDD HH24:MI:SS')) T1  --무조건 자른다
FROM DUAL;

-- 월 다루기 -도 가능
SELECT 
    ADD_MONTHS(SYSDATE, 3)
    ,ADD_MONTHS(SYSDATE, -3)
FROM DUAL;

-- TO_DATE
-- DB 기준 DB가 가진 현재 시간을 리턴
SELECT 
    CURRENT_DATE
    ,SYSDATE 
FROM DUAL;

-- 그리드에서 정렬이 오른쪽이면 숫자, 왼쪽이면 문자열
SELECT EXTRACT(YEAR FROM SYSDATE)A 
     , EXTRACT(MONTH FROM SYSDATE)B
     , EXTRACT(DAY FROM SYSDATE)C -- 리턴 타입이 숫자
     , TO_CHAR(SYSDATE,'YYYY')D --리턴 타입이 문자
FROM DUAL;

--해당 달의 마지막 날 반환
SELECT LAST_DAY(SYSDATE) D1
     , ADD_MONTHS(TRUNC(SYSDATE, 'MM'),1)-1  D2
FROM DUAL;

SELECT NEXT_DAY(SYSDATE,6) --인덱스로 따짐 단 1부터 일요일 돌아오는 날짜
FROM DUAL;



SELECT 
    ABS(-5) COL1 -- 부등호 제외한 
    ,ABS(5) COL2 -- 절대값
    ,FLOOR(10.5) COL3 -- 내림
    ,CEIL(10.5) COL4 -- 올림
    ,POWER(2,5) COL5 -- 제곱
    ,SQRT(2) COL6 --루트
    ,ROUND(10.4) COL7 -- 반올림인데 소수점 가능
    ,ROUND(10.55,1) COL8 -- 2번 째 인자는 소수점 몇번째를 기준으로 할지
    ,TRUNC(10.4) COL9 -- 버림
    ,TRUNC(10.5) COL10 --무조건 버림
    ,TRUNC(11.5, -1) COL11 -- 정수 1의자리 버림
    ,ADD_MONTHS(TO_DATE('20180101','YYYYMMDD'),3) COL12 -- 날짜로 이후 3달 더하기
    ,CURRENT_DATE COL13 -- DB기준 현재시간
    ,EXTRACT(YEAR FROM SYSDATE) COL14 -- 년도 추출
    ,EXTRACT(MONTH FROM SYSDATE) COL15 -- 월 추출
    ,EXTRACT(DAY FROM SYSDATE) COL16 -- 일 추출
    ,NEXT_DAY('20180206',2) COL18 -- 1부터 일요일 돌아오는 그 요일의 날짜 반환
    ,NEXT_DAY('20180206','월') COL19 -- 월 화 수 목 금 토 일 가능
    ,SYSDATE COL20 -- DB기준 현재시간
FROM DUAL;

'개발 > 오라클 SQL' 카테고리의 다른 글

컬럼 <=> 행 변환  (0) 2023.01.13
숫자 함수 응용  (0) 2023.01.10
SELECT 문으로 SQL문 만들기  (0) 2023.01.05
중복 데이터 삭제  (0) 2023.01.03
NOT IN 에서 NULL 사용 시 주의사항  (0) 2023.01.01

일반화와 특수화

범주의 계층

18세기 자연에 대한 관심 증가로 매년 수천 종의 생물들이 새롭게 발견

끝임없이 쏟아져 보편적 분류 체계가 필요하다 느낌

1735 카를로스 린네 자연의 체계를 발표

계문강목과속종

 

린네의 분류 체계는 범주 간의 계층적인 구조를 가짐

모든 포유류는 척추가 있고 새끼를 낳아 젖을 먹여 기른다는 특징을 공유

따라서 얼룩고양이도 척추가 있고 새끼를 낳아 기르며 젖을 먹여 새끼를 기를 것이라는 사실을 쉽게 있다.

 

린네의 계층 구조는 세부적인 범주가 계층의 하위에 위치하고 일반적인 범주가 계층의 상위에 위치한다.

계층 상위에 위치한 범주를 계층 하위에 위치한 범주의 일반화

계층의 하위에 위치한 범주는 계층의 상위에 위치한 범주의 특수화라고 한다.

 

서브타입

객체지향의 세게에서 범주는 개념, 개념은 타입

따라서 일반화와 특수화는 계층 구조 안에서 존재하는 타입 간의 관계를 의미한다.

어떤 타입이 다른 타입보다 일반적이라면 슈퍼 타입(supertype)

어떤 타입이 다른 타입보다 특수하다면 서브타입(subtype)이라고 한다.

슈퍼타입은 서브타입의 일반화

서브타입은 슈퍼타입의 특수화

 

일반화와 특수화 계층 구조에서 서브타입은 슈퍼타입이 가진 본질적인 속성과 함께 자신만의 추가적인 속성을 가진다.

 

크레이그 라만은 어떤 타입이 다른 타입의 서브타입이 되기 위해서는 100% 규칙과 Is-a 규칙을 준수해야한다고 했다.

100% 규칙은 내연 관련

Is-a 규칙은 외연 관련 규칙이다.

  • 100%규칙
    슈퍼타입의 정의가 서브타입에 100% 적용되어야 한다
    서브타입은 속성과 연관관계 면에서 슈퍼타입과 100% 일치해야 한다.
  • Is-a 규칙(is-a-kind-of)
    서브타입의 모든 인스턴스는 슈퍼타입 집합에 포함돼야 한다.
    "서브타입은 슈퍼타입이다" 라는 말에 대입해서 맞다면 적용되는 것으로 본다.
    인간은 동물이다. (일치) / 컴퓨터는 동물이다(불일치)
    서브타입이 슈퍼타입의 부분집합인 것을 알 수 있다.

 

상속

일반화 특수화 관계를 구현하는 일반적인 방법은 클래스 상속을 사용하는

반드시 모든 상속 관계가 일반화 관계인 것은 아니다.

 

일반화의 원칙은 타입이 다른 타입의 서브타입이 되기 위해서는 슈퍼타입에 순응(conformance)해야 한다는

순응은 구조적인 순응(structural conformance) 행위적인 순응(behavioral conformance) 가지 종류가 있다.

가지 모두 특정 기대 집합에 대해 서브타입의 슈퍼타입에 대한 대체 가능성 의미한다.

  • 구조적인 순응의 경우 기대 집합은 속성과 연관관계에 관한 것
  • 행위적인 순응의 경우 기대 집합은 행위가 동일한 계약을 기반으로 하느냐

 

구조적인 순응은 타입의 내연과 관련된 100% 규칙을 의미(속성)

Person 클래스에 name 속성이 있다고 가정, Person 서브타입인 Employee 역시 name 속성을 가져야 한다.

Employee 클래스는 구조적으로 Person클래스를 대체할 있다.

 

행위적 순응은 흔히 리스코프 치환 원칙(Liskov Substitution Principle,LSP)이라고 한다.

Person.getAge() 나이를 반환한다면 Employee.getAge()역시 나이를 반환해야 한다.

Employee Person 대해 행위적으로 순응하기 때문에 대체 가능하다.

 

상속의 또다른 용도는 코드 중복을 방지 공통 코드를 재사용하기 위한 언어적 메커니즘을 제공하는

 

 

상속은 서브타이핑(subtyping) 서브클래싱(subclassing) 가지 용도로 사용될 있다.

  • 서브 클래스가 슈퍼클래스를 대체할 수 있는 경우 이를 서브타이핑이라고 한다.
  • 서브 클래스가 슈퍼클래스를 대체할 수 없는 경우 서브클래싱이라고 한다.

 

서브타이핑은 설계의 유연성이 목표

서브클래싱은 코드의 중복 제거와 재사용이 목적

 

서브타이핑은 인터페이스 상속(interface inheritance)

서브클래싱을 구현 상속(implementation inheritance)이라고 한다.

 

클래스가 다른 클래스를 상속받았다는 사실만으로 클래스 간의 관계가 서브타이핑인지, 서브클래싱인지 여부를 결정할 없다.

서브타이핑의 전제 조건은 대체 가능성이기 때문에 클라이언트 관점에서 실제로 어떻게 사용되고 있는지를 확인해야 한다.

 

가능한 모든 상속관계가 서브타이핑의 대체 가능성을 준수하도록 하는 것이 좋다

 

여러 클래스로 구성된 상속 계층에서 수신된 메시지를 이해하는 기본적인 방법은 클래스 위임(delegation) 사용하는  

 

 

집합과 분해

계층적인 복잡성

복잡성은 계층의 형태를 띈다.

단순한 형태로부터 복잡한 형태로 진화하는데 걸리는 시간은 그 사이에 존재하는 안정적인 형태의 수와 분포에 의존한다

 

시계는 중간 부품들을 조립해서 만들어진다.

중간 부품은 작은 부품들을 조립해서 만들어진다.

결국 시계는 전체적으로 연쇄적인 계층 구조 구성된다.

같이 안정적인 형태의 부분으로부터 전체를 구축하는 행위를 집합이라고 한다.

반대로 전체를 부분으로 분할하는 행위를 분해라고 한다.

 

집합의 가치는 많은 수의 사물들의 형상을 하나의 단위 다룸으로써 복잡성을 줄일 있다는 있다.

 

집합은 불필요한 세부 사항을 배제하고 그림에서 대상을 다룰 있게 한다. (추상화, 캡슐화)

그러나 필요한 시점에는 전체를 분해함으로써 안에 포함된 부분들을 새로운 전체 다룰 있다.

 

합성 관계

상품 주문을 생각해보자.

상품 주문은 여러 상품을 번에 주문할 있다.

이때 상품을 주문했는지를 가리켜 주문 항목이라고 한다.

주문 항목은 주문과 독립적으로 존재할 없다. 반드시 어느 주문에 주문항목이 일부로 생성되기 때문이다.

객체와 객체 사이의 전체-부분 관계를 구현하기 위해서는 합성 관계를 사용한다.

 

합성관계는 부분을 전체 안에 캡슐화함으로써 단순화한다.

, 주문과 상품만이 존재하는 것처럼 모델을 다룰 있다.

필요시 주문 내부의 세부적인 주문항목을 보는

 

주문항목은 주문과 전체와 부분을 나타내는 합성관계다.

주문항목과 상품 간에도 선이 연결되어 있는데 이를 연관 관계라 한다.

 

일반적으로 합성관계로 연결된 객체는 포함하는 객체가 제거되면 같이 제거된다.

주문이 제거되면 주문항목이 존재할 없으니 같이 제거

 

연관 관계는 주문 제거되더라도 상품은 계속 판매될 것이다.

 

 

패키지

합성 관계를 통해 단순화 하더라도 결국 클래스 수가 많아지면 복잡해진다.

 

서로 관련성이 높은 클래스 집합을 논리적인 단위로 통합

 

관련된 클래스 집합을 하나의 논리적인 단위로 묶는 구성 요소를 패키지(package)또는 모듈(module)이라한다.

 

합성 관계가 내부에 포함된 객체들의 존재를 감춤으로써 내부 구조를 추상화하는 처럼 패키지는 내부에 포함된 클래스들을 감춤으로써 시스템의 구조를 추상화한다.

 

 

SELECT 'INSERT INTO EMP VALUES('||DEPTNO||','''||DNAME||''','''||LOC||''')' FROM DEPT;

 

실제로 이렇게 쓰는 경우가 간혹있다.

 

'개발 > 오라클 SQL' 카테고리의 다른 글

숫자 함수 응용  (0) 2023.01.10
자주 쓰는 함수 모음  (1) 2023.01.07
중복 데이터 삭제  (0) 2023.01.03
NOT IN 에서 NULL 사용 시 주의사항  (0) 2023.01.01
집합 연산자 사용 시 주의사항  (0) 2022.12.30

추상화 기법

추상화는 도메인의 복잡성을 단순화하고 직관적인 멘탈 모델을 만드는 사용할 있는 기본적인 인지 수단이다

동일한 특성을 공유하는 객체들을 타입으로 분류하는 것이 추상화 기법의 예다.

 

추상화 기법은 결국 복잡성을 낮추기,세부사항 감추기

 

  • 분류와 인스턴스화 
    분류는 객체의 구체적인 세부 사항을 숨김, 인스턴스 간 공유하는 공통적인 특성을 기반으로 범주화
    인스턴스화는 범주로부터 객체를 생성하는 것
  • 일반화와 특수화
    범주 사이의 차이를 숨기고 번주 간에 공유하는 공통적인 특성을 강조
    이 반대가 특수화
  • 집홥과 분해
    부분과 관련된 세부 사항을 숨기고 부분을 사용해서 전체를 형성하는 과정을 가리킴
    집합의 반대 과정은 전체를 부분으로 분리하는 분해

 

 

분류와 인스턴스화

개념과 범주

 

개념이란 속성과 행위가 유사한 객체에 공통적으로 적용되는 관념이나 아이디어다 -Martin

객체를 분류하고 범주로 묶는 것은 객체들의 특정 집합에 공통의 개념을 적용하는 것을 의미한다.

 

나무라는 범주에는 '푸른 잎과 갈색의 줄기를 가진 다년생 식물'이라는 개념을 적용할 있다.

객체들을 공통적인 특성을 기반으로 범주로 묶고, 개념을 적용하는 것은 범주라는 정신적인 렌즈를 통해 세상을 바라보는 것과 유사하다.

자동차라는 렌즈를 통해 바라본 세상은 자동차 범주에 속한 객체만 보일

 

세상에 존재하는 객체에 개념을 적용하는 과정을 분류라고 한다. -Martin

분류는 객체를 특정한 개념을 가타내는 집합의 구성 요소로 포함시킨다.

 

세상에 존재하는 서로 다른 상태를 가진 무수히 많은 자동차와 나무를 개별적으로 다루기는 불가능하다. 그래서 범주로 묶어 세상이 가진 복잡성을 낮춘다.

사람들은 분류를 통해 개별 현상을 하나의 개념으로 다룬다.

이때 '수많은 개별적인 현상들' 객체라하고, '하나의 개념' 타입이라고 한다.

분류는 객체를 타입과 연관시키는 것이다.

 

분류의 역은 타입에 해당하는 객체를 생성하는 과정으로 인스턴스화 또는 예시라고 한다.

 

객체지향 세계에서 개념을 가리키는 표준 용어는 타입이다. -Martin

객체를 타입의 인스턴스라고 한다.

 

분류는 객체와 타입 간의 관계를 나타낸 것이다.

어떤 객체가 타입의 정의에 부합할 경우 객체는 해당 타입으로 분류되며 자동으로 타입의 인스턴스가 된다.

 

타입

타입을 객체의 분류 장치로서 적용할 수 있으려면 다음과 같은 세 가지 관점에서의 정의가 필요하다 - Martin
  • 심볼
    타입을 가리키는 간단략 명칭
  • 내연
    타입의 완전한 정의
  • 외연
    타입에 속하는 모든 객체들의 집합

 

 

외연과 집합

타입의 외연은 타입에 속하는 객체들의 집합으로 표현

집합 = 외연

객체들은 동시에 서로 다른 집합에 포함 수도 있다.

 

객체가 하나의 타입에 속하는 경우 단일 분류(single classification)

여러 타입에 속하는 경우 다중 분류(multiple classification) 한다.

 

대부분의 객체지향 프로그래밍 언어들은 단일 분류만을 지원한다.

대부분의 언어에서 객체는 오직 클래스의 인스턴스여야만 하며 동시에 개의 클래스의 인스턴스일 수는 없다. 관점에서 다중 분류를 다중 상속과 혼동해서는 안된다.

다중 상속은 하나의 타입이 다수의 슈퍼타입을 가질 있도록 허용하지만 타입 정의를 생략할 수는 없다. 반면 다중 분류는 특정한 타입을 정의하지 않고도 하나의 객체가 서로 다른 타입의 인스턴스가 되도록 허용한다.

 

객체를 특정한 타입으로 분류하면 해당 객체는 타입의 집합에 포함된다.

객체가 집합에서 다른 집합의 원소로 자신이 속하는 타입을 변경할 있는 경우 이를 동적 분류(dynamic classification)이라고 한다.

객체가 자신의 타입을 변경할 없는 경우 이를 정적 분류(static classification) 한다.

 

하나의 컴퓨터가 시간의 흐름에 따라 교육용 컴퓨터에서 사무용 컴퓨터로, 다시 사무용에서 교육용 컴퓨터로 분류가 바뀌는 과정은 컴퓨터가 여러 집합에 속할 있다는

 

다중 분류와 동적 분류는 서로 배타적인 개념이 아니다. 함께 적용하는 것이 실세계의 복잡성을 모델링하는데 유용하다.

 

클래스 기반의 객체지향에서 타입은 클래스로 구현된다.

대부분의 언어는 일단 클래스로부터 인스턴스를 생성한 클래스를 변경할 있는 방법을 제공하지 않는다. , 객체의 타입을 변경할 없다. 따라서 우리가 사용하는 대부분의 언어는 정적 분류만 허용하며 동적 분류를 구현할 있는 방법을 제공하지 않는다.

 

이처럼 언어의 제약으로 인해 다중 분류와 동적 분류를 구현으로 옮기기 쉽지 않다.

절충안으로 도메인 모델의 초안을 다중 분류와 동적 분류로 만들고, 실제 구현에 적합하도록 단일 분류와 정적 분류 방식으로 객체들의 범주를 재조정하는 것이 좋다.

 

디자인 템플릿은 유연성이라는 측면에서 필요한 경우에만 사용

단순함을 위해서는 단일 분류와 정적 분류를 선택

 

 

클래스

타입을 구현하는 가장 보편적인 방법

클래스는 타입 구현 용도 외에 코드 재사용 용도로 사용할 있다.

추상 클래스, 인터페이스도 타입 구현 가능

 

현재 객체지향 패러다임은 아리스토텔레스 분류법의 근간을 형성하는 아이디어를 근간으로 한다

 

아리스토 텔레스는 객체의 특성을 본질적인 속성과 우연적인 속성으로 분류했다.

본질(essence)이란 사물의 가장 핵심적이고 필수불가결한 솓성

본질적인 속성 속성을 우연적(accidental)속성이라고 한다.

예컨대 사람이 취직을 해서 회사원이 되어도 사람은 여전히 사람이다. 회사원이 사람의 본질을 바꾸지는 못한다.

 

클래스는 객체가 공유하는 본질적인 속성을 정의한다. 대부분의 객체지향 언어에는 우연적인 속성은 추가할 없다.

안타깝지만 분류 수준과 결과는 누가 분류를 하는가와 무엇을 기반으로 분류하는가에 따라 크게 달라진다. 실제로 사람들은 동일한 사물을 다양한 방식으로 인식하며 다양한 방식으로 분류한다.

 

자바스크립트처럼 클래스가 존재하지 않는 프로토타입 기반의 언어는 아리스토텔레스의 객관적인 분류 체계가 존재한다는 사상 대한 철학적 의문에 뿌리를 두고 있다. 클래스가 없는 프로토타입 언어에서 분류와 인스턴스화는 프로토타입이라는 객체의 복사를 통해 이뤄진다.

 

DELETE FROM DEPT
 WHERE DEPTNO NOT IN ( SELECT MIN(DEPTNO)/*KEY값*/
                         FROM DEPT
                        GROUP BY LOC/*중복제거 컬럼*/);

기본키는 유일하기 때문에 키값을 기준으로 잡고 중복을 제거하고 싶은 컬럼을 선정한다.

그리고 집계함수를 사용하면 반드시 1개의 값만 리턴하게 된다.

 

위 예제는 편의상 DEPT 테이블의 DEPTNO을 사용했지만, 원래는 지워도 되는 행인지 명확히 판별해야 한다.

'개발 > 오라클 SQL' 카테고리의 다른 글

자주 쓰는 함수 모음  (1) 2023.01.07
SELECT 문으로 SQL문 만들기  (0) 2023.01.05
NOT IN 에서 NULL 사용 시 주의사항  (0) 2023.01.01
집합 연산자 사용 시 주의사항  (0) 2022.12.30
UNION ALL, UNION  (0) 2022.12.28

+ Recent posts