<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>mong-head.log</title>
        <link>https://velog.io/</link>
        <description>안녕하세요</description>
        <lastBuildDate>Sun, 13 Mar 2022 05:43:11 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>mong-head.log</title>
            <url>https://images.velog.io/images/mong-head/profile/af961397-28b4-438c-849c-7e7c88d770bb/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. mong-head.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/mong-head" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[SQLD] 시험 전반적인 개념]]></title>
            <link>https://velog.io/@mong-head/SQLD-%EC%8B%9C%ED%97%98-%EC%A0%84%EB%B0%98%EC%A0%81%EC%9D%B8-%EA%B0%9C%EB%85%90</link>
            <guid>https://velog.io/@mong-head/SQLD-%EC%8B%9C%ED%97%98-%EC%A0%84%EB%B0%98%EC%A0%81%EC%9D%B8-%EA%B0%9C%EB%85%90</guid>
            <pubDate>Sun, 13 Mar 2022 05:43:11 GMT</pubDate>
            <description><![CDATA[<p><strong>기출 및 노랭이 풀면서 시험에 필요한 개념위주로 정리했습니다.</strong>
<strong>모든 개념을 담지 않았습니다. 대강 이런게 나오는구나하고 참고해주시면 감사합니다.</strong></p>
<blockquote>
<p>💡 1과목 공부 꼭 해야하는 것</p>
</blockquote>
<ul>
<li>일반적으로 1과목 내용은 그냥 다 알아야함, 그럼에도 꼭 공부해야하는 것을 꼽자면 밑의 세가지가 있음</li>
</ul>
<ol>
<li>엔티티</li>
<li>속성 - 종류관련</li>
<li>식별자 - 종류관련</li>
</ol>
<blockquote>
<p>💡 2과목 공부 꼭 해야하는 것 - SQL 문은 대부분 Oracle 기준으로 씀(Oracle 이나 SQL Server 기준으로 쿼리 알면 됨)</p>
</blockquote>
<ul>
<li>DML, DDL, DCL, TCL</li>
<li>ROLLBACK, SAVEPOINT - 문제 및 예제를 보기</li>
<li>null 처리관련 연산자, 함수<ol>
<li>연산자 <ul>
<li>IN , NOTIN 의 null 처리관련</li>
</ul>
</li>
<li>함수<ul>
<li>null처리함수(NVL, ISNULL, NULLIF, COALESCE)</li>
<li>집계함수(SUM,AVG,COUNT 등)이 null에 대해 어떻게 처리하는지</li>
</ul>
</li>
</ol>
</li>
<li>윈도우함수(Window Function) - 윈도우함수로 될 수 있는 것 및 BETWEEN 절에 들어갈 수 있는 것 등등 전반적으로 공부</li>
<li>그룹함수 (ROLLUP, CUBE, GROUPING SETS)</li>
<li>조건관련 (CASE, DECODE)</li>
<li>JOIN - 조인종류(natural join, inner join, cross join, ...)에 따른 특징</li>
<li>서브쿼리 - 서브쿼리 관련해서는 SQL 오류 관련으로 많이 나옴 (해당 서브쿼리를 썼을때 오류가 나지 않는지)</li>
<li>계층형 쿼리 - 무조건 많은 문제 및 예시를 보는게 답</li>
<li>ORDER BY - order by 절에 올 수 있는 것들이 무엇이 있는지</li>
<li><code>TOP()</code>, <code>ROWNUM</code></li>
<li>Nested Loop Join, Sort Merge Join, Hash Join - 차이 및 개념정도</li>
</ul>
<h1 id="1과목-데이터-모델의-이해">1과목. 데이터 모델의 이해</h1>
<h2 id="1-1-데이터-모델링-이해">1-1. 데이터 모델링 이해</h2>
<h3 id="모델링">모델링</h3>
<p>모델링 : 시스템 구현+ 업무,업무형상화 목적</p>
<ul>
<li>특징<ul>
<li>추상화, 단순화, 정확화(명확화)</li>
</ul>
</li>
<li>주의<ul>
<li>중복<ul>
<li>여러 장소에 같은 정보 저장 X</li>
</ul>
</li>
<li>비유연성<ul>
<li>데이터 정의와 사용프로세스를 분리해야함</li>
<li>유지보수성관련</li>
</ul>
</li>
<li>비일관성<ul>
<li>데이터간에 상호 연관 관계 설명 명확히 해야함</li>
</ul>
</li>
</ul>
</li>
<li>데이터 모델링의 3가지 요소<ul>
<li>Thing(저장이 되어 관리가 필요한 어떤 것), Attributes(속성), Relationship(관계)</li>
</ul>
</li>
<li>DB 스키마 구조<ul>
<li>개념적 데이터 모델링 : 통합 관점, 포괄적</li>
<li>논리적 데이터 모델링 : 관계 명확히<ul>
<li>논리 모델링의 외래키는 반드시 구현되지는 않음</li>
</ul>
</li>
<li>물리적 데이터 모델링 : 이식, 성능, 저장등 고려 실제 물리적 고민</li>
</ul>
</li>
</ul>
<h3 id="엔터티">엔터티</h3>
<ul>
<li><p>이름짓기</p>
<ul>
<li>현업에서 사용하는 용어 사용</li>
<li>약어 X</li>
<li>단수 명사, 고유한 이름 사용</li>
</ul>
</li>
<li><p>특징</p>
<ul>
<li><p>2개 이상의 인스턴스 집합</p>
<p>  인스턴스 : 엔터티 구현된거? (환자1,환자2)</p>
</li>
<li><p>2개 이상의 속성 집합</p>
</li>
<li><p>하나의 속성은 하나의 속성값만 가짐</p>
</li>
</ul>
</li>
<li><p>종류</p>
<ul>
<li>유무형에 따른 분류<ul>
<li>유형 엔터티 : 물리적 엔터티 (사원, 물품, 강사)</li>
<li>개념 엔터티 : 개념적 정보, 물리적인 형태가 아님 (보험상품, 조직)</li>
<li>사건 엔터티 : 업무 수행시 발생, 통계자료 이용 (주문, 청구, 미납)</li>
</ul>
</li>
<li>발생시점에 따른 분류<ul>
<li>기본 엔터티 : 부모가 되는 엔터티, 주식별자를 상속받지 않고, 자신의 고유한 식별자를 가짐<ul>
<li>행위의 주체이자 제일 처음 고려대상</li>
<li>예시 : 사원, 자재, 부서, 고객, 상품</li>
</ul>
</li>
<li>중심 엔터티 : 기본엔터티로부터 발생되고, 업무에 있어서 중심적인 역할함<ul>
<li>데이터 양 많음, 많은 행위 엔터티 발생시킴</li>
<li>예시 : 매출, 계약, 주문</li>
</ul>
</li>
<li>행위 엔터티 : 2개 이상의 부모 엔터티로부터 발생됨, 내용자주 바뀜<ul>
<li>예시 : 장비점검목록(점검번호, 날짜), 주문번호, 사원변경이력</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="관계-엔터티간의">관계 (엔터티간의)</h3>
<ul>
<li>사용하는 개념<ul>
<li>관계명</li>
<li>관계차수 (1:1, 1:M)</li>
<li>관계 선택사양 : 필수관계, 선택관계</li>
</ul>
</li>
<li>관계간에 중요한 것은 명사가 아닌 ‘동사’</li>
<li>데이터 모델링 vs. UML<ul>
<li>데이터 모델링 : 존재간 관계, 행위간 관계를 구분 안함<ul>
<li>존재에 의힌 관계 : 소속된다</li>
<li>행위에 의한 관계 : 주문한다</li>
</ul>
</li>
<li>UML : 연관관계(실선), 의존관계(점선) 구분함<ul>
<li>연관관계 : 존재적 관계</li>
<li>의존관계 : 상대방 행위에 의한 관계</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="속성">속성</h3>
<ul>
<li>정의<ul>
<li>의미상 더이상 분리되지 않는 최소의 데이터 단위</li>
</ul>
</li>
<li>⭐ 도메인 : 속성이 가질 수 있는 값 범위</li>
<li>특징<ul>
<li>하나의 속성값만 가져야함</li>
<li>속성의 명칭 : 전체 데이터 모델에서 유일성을 확보해야함 → 반정규화,통합등 작업시 혼란 방지할 수 있도록 ‘복합 명사&#39; 사용해서 엔터티마다 비슷한 값을 가지더라도 명칭을 다 다르게 해야함<ul>
<li>1 엔터티의 name, 2 엔터티의 name : X (1_name, 2_name O)</li>
</ul>
</li>
</ul>
</li>
<li>종류<ul>
<li>기본속성</li>
<li>파생속성 : 빠른성능 위함. 본래 속성값 계산해서 저장가능하게 만든 속성</li>
<li>설계속성 : 업무를 규칙화하기 위해 새로만들거나 변형하거나 정의하는 속성 (ex : 일련번호)</li>
</ul>
</li>
</ul>
<h3 id="식별자">식별자</h3>
<ul>
<li>종류<ul>
<li>대표성<ul>
<li>주식별자<ul>
<li>유일성, 최소성, 불변성, 존재성</li>
</ul>
</li>
<li>보조식별자</li>
</ul>
</li>
<li>엔터티 내에서 스스로 생겼는가<ul>
<li>내부식별자</li>
<li>외부식별자 : 타 엔터티의 관계로 인해 타 엔터티에서 받아온 속성</li>
</ul>
</li>
<li>단일 속성으로 식별이 되는가<ul>
<li>단일식별자</li>
<li>복합식별자 : 2개 이상의 속성으로 식별자 구성</li>
</ul>
</li>
<li>업무적으로 의미있는 식별자 대체한 식별자인가<ul>
<li>본질식별자</li>
<li>인조식별자 : 본래 업무적으로 의미가 있던 식별자 속성 대체한 일련번호처럼 인위적으로 새롭게 만든 식별자<ul>
<li>시스템적으로 부여된 식별자</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>식별자관계, 비식별자 관계<ul>
<li>식별자 관계 : 강한 연결관계 표현, 엔티티간 실선표현, 자식의 주식별자에 반드시 포함(종속관계있음)</li>
<li>비식별자 관계 : 약한 연결관계 표현, 엔티티간 점선표현, 자식의 일반 속성에 포함됨<ul>
<li>복합식별자가 많은 경우 부모와 자식간의 조인시에 sql 문이 복잡해질 수 있음. 해당 부분은 비식별자로 할건지 고민 중 가장 최하위 우선순위를 가짐(가장 마지막에 고려한다는 것, 식별자관계여야하는데 단순 sql 문이 복잡해진다고 비식별자로 하면 안 됨)</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="1-2-데이터-모델과-성능">1-2. 데이터 모델과 성능</h2>
<h3 id="정규화">정규화</h3>
<ol>
<li>1차 정규형<ul>
<li>하나의 속성은 하나의 속성값만 가져야 함<ul>
<li>같은 속성을 가지는 속성값들은 동일 형식이어야 함(정수면 정수만)</li>
<li>속성은 유일한 이름을 가져야함</li>
</ul>
</li>
</ul>
</li>
<li>2차 정규형<ul>
<li>식별자가 아닌 속성들은 식별자에 완전 종속되어야 함<ul>
<li>= PK 아닌 속성들은 PK에 종속되는 속성이어야 함</li>
</ul>
</li>
</ul>
</li>
<li>3차 정규형<ul>
<li>식별자가 아닌 속성끼리는 종속관계가 있으면 안됨</li>
</ul>
</li>
</ol>
<h3 id="반정규화">반정규화</h3>
<ul>
<li>반정규화 대상<ul>
<li>조인으로 인한 성능저하</li>
<li>디스크 I/O량이 많아 성능저하</li>
<li>칼럼 계산량이 많아 성능 저하 → 계산된 칼럼을 새로 추가</li>
<li>통계성 정보가 따로 필요할 때, 통계 테이블 만드는 것을 고려함</li>
</ul>
</li>
<li>반정규화 대상이 아닌 것<ul>
<li>Sorting, Order by가 많은 경우</li>
</ul>
</li>
<li>반정규화 전에 고려해야하는 것<ul>
<li>VIEW : 조인이 너무 많이 걸려있는 경우 조인을 한 View를 만들어서 활용</li>
<li>인덱스 조정 / 클러스터링 적용 : 대량의 데이터처리에 의해 성능 저하되는 경우</li>
</ul>
</li>
</ul>
<h3 id="대량-데이터-성능">대량 데이터 성능</h3>
<ul>
<li>많은 컬럼으로 인한 성능 저하<ul>
<li>Row Chaining (신규 데이터 입력시 발생)<ul>
<li>row 길이가 길어서 하나의 블록에 저장되지 못하고, 두 개 이상의 블록에 하나의 row가 저장되는 현상</li>
<li>chaining ? c++에서 포인터로 데이터 가리키듯이 너무 긴 수정데이터를 포인터 형식으로 가리켜서 그런 이름인 듯?</li>
</ul>
</li>
<li>Row Migration (데이터 수정시 발생)<ul>
<li>데이터 블록에서 수정할 때, 수정된 데이터를 해당 블록에서 찾지 못하고 다른 블록의 빈 공간에서 찾아서 저장하는 방식</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="분산-db">분산 DB</h3>
<ul>
<li>정의<ul>
<li>DB가 물리적으로 여러곳에 분산되어 있음 하지만 하나의 논리적으로 동일한 가상 시스템</li>
</ul>
</li>
<li>투명성<ul>
<li>위치 투명성 : 저장 장소 명시가 불필요</li>
<li>지역 사상 투명성 : 지역 DBMS - 물리 DB 간의 맵핑 보장, 각 지역 시스템과 무관한 이름 사용 가능</li>
<li>중복 투명성 : DB 객체가 여러 장소에 중복되어 있는지 알 필요 없는 성질</li>
<li>장애 투명성 : 구성요소의 장애에 무관한 트랜잭션 원자성 유지</li>
<li>병행 투명성 : 다수 트랜잭션 동시 수행시에 결과의 일관성 유지</li>
</ul>
</li>
</ul>
<h1 id="2-sql-기본-및-활용">2. SQL 기본 및 활용</h1>
<h3 id="rdbms">RDBMS</h3>
<ul>
<li><p>DML(데이터 조작어)</p>
<ul>
<li><p>SELECT</p>
</li>
<li><p>INSERT, DELETE, UPDATE</p>
<pre><code class="language-sql">INSERT INTO 테이블명 (칼럼리스트) VALUES (칼럼 값);
UPDATE 테이블명 SET 수정되어야할 칼럼명 = 값; DELETE FROM 테이블명;
SELECT 칼럼리스트 FROM 테이블명;</code></pre>
</li>
</ul>
</li>
<li><p>DDL(데이터 정의어)</p>
<ul>
<li><p>DROP, CREATE, ALTER, RENAME, TRUNCATE</p>
<pre><code class="language-sql">ALTER TABLE DEPT ALTER COLUMN VARCHAR(30) NOT NULL;

ALTER TABLE 테이블명 ADD 칼럼명 데이터 유형; - 여러개 컬럼 동시수정 불가(SQL Server)
ALTER TABLE 테이블명 DROP COLUMN 칼럼명;
ALTER TABLE 테이블명 MODIFY (칼럼명 데이터유형 DEFAULT식 NOT NULL); - 칼럼 데이터 유형, 조건 등 변경 / Oracle
ALTER TABLE 테이블명 ALTER (칼럼명 데이터유형 DEFAULT식 NOT NULL); / SQL Server
ALTER TABLE 테이블명 RENAME COLUMN 변경전칼 럼명 TO 뉴칼럼명; Ora
ALTER TABLE 테이블명 DROP CONSTRAINT 조건명; 제약조건 삭제
ALTER TABLE 테이블명 ADD CONSTRAINT 조건명 조건 (칼럼명); 조건 추가
RENAME 변경전테이블명 TO 변경후테이블명; Ora 
sp_rename ‘db0.TEAM’,‘TEAM_BACKUP’; SQL
sp_rename 변경전칼럼명, 뉴칼럼명, ‘COLUMN’; SQ
DROP TABLE 테이블명 [CASCADE CONSTRAINT] CASCADE CONSTRAINT : 참조되는 제약조건 삭제
TRUNCATE TABLE 테이블명; 행 제거, 저장공간 재 사용</code></pre>
</li>
</ul>
</li>
<li><p>DCL(데이터 제의어) - 유저생성 및 권한 제어</p>
<ul>
<li>GRANT - 권한 부여</li>
<li>REVOKE - 권한 회수</li>
</ul>
</li>
<li><p>TCL(트랜잭션 제의어)</p>
<ul>
<li>COMMIT, ROLLBACK, SAVEPOINT</li>
<li>DCL 로 표현하기도 함</li>
</ul>
</li>
</ul>
<h3 id="transaction-tcl관련">Transaction (TCL관련)</h3>
<ul>
<li><p>Transaction 속성</p>
<ul>
<li>원자성 : 트랜잭션에 정의된 속성은 모두 성공이던지 모두 실패던지 둘 중에 하나여야함</li>
<li>일관성 : 트랜잭션이 실행되기 전 결과가 잘못되지 않았다면, 후에도 잘못되면 안됨</li>
<li>지속성 : 트랜잭션이 성공적이면 그 결과는 영구적으로 저장됨</li>
<li>고립성 : 다른 트랜잭션에 영향받아 현재 트랜잭션의 결과가 이상하게 되면 안됨</li>
</ul>
</li>
<li><p>Auto Commit</p>
<ul>
<li><p>DDL이 일어나면 암묵적으로 commit 됨</p>
<pre><code class="language-sql">  - 01 : CREATE TABLE TAB1 (N1 NUMBER, N2 NUMBER);
  - 02 : INSERT INTO TAB1 VALUES (1,1);
  - 03 : INSERT INTO TAB1 VALUES (2,2);
  - 04 : CREATE TABLE TAB2 (V1 VARCHAR2(10), V2 VARCHAR2(10));
  - 05 : ROLLBACK;
  - 06 : SELECT COUNT(*) FROM TAB1; // 2</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="권한-dcl관련">권한 (DCL관련)</h3>
<ul>
<li><p>ROLE : 권한 부여 쉽게 관리 가능한 권한 집합</p>
</li>
<li><p>권한 부여</p>
<ul>
<li>DBA 권한, 시스템 권한 (SYS, SYSTEM) 가진 사람들이 권한 부여 가능</li>
</ul>
</li>
<li><p>참고</p>
<p>  <a href="https://devdhjo.github.io/sqld/2019/11/28/database-sqld-024.html">https://devdhjo.github.io/sqld/2019/11/28/database-sqld-024.html</a></p>
</li>
</ul>
<h3 id="sql-실행순서">SQL 실행순서</h3>
<pre><code class="language-sql">SELECT DEPTNO, COUNT(EMPNO) 
FROM SCOTT.EMP
WHERE SAL &gt;= 500
GROUP BY DEPTNO
HAVING COUNT(EMPNO) &gt; 2 
ORDER BY DEPTNO;</code></pre>
<ul>
<li><p>FROM -&gt; WHERE -&gt; GROUP BY -&gt; HAVING -&gt; SELECT -&gt; ORDER BY</p>
</li>
<li><p>최대한 앞에서 거를 수 있으면 거르는게 좋음</p>
<ul>
<li>WHERE에서 처리할 수 있는 일을 HAVING에서 처리하지 않기!</li>
<li>참고 : <a href="https://myjamong.tistory.com/172">https://myjamong.tistory.com/172</a></li>
</ul>
</li>
<li><p>각 절 상세 설명</p>
<ol>
<li><p>FROM과 JOIN</p>
<p> JOIN이 먼저 실행되어 데이터가 SET으로 모아지게 됌.여기에는 서브쿼리도 함께 포함되어 임시적인 테이블을 만들 수 있게 도와줌.</p>
</li>
<li><p>WHERE</p>
<p> 데이터셋을 형성하게 되면 WHERE의 조건이 개별 행에 적용이 된다. </p>
<p> 이 WHERE절의 제약 조건은 FROM절로 가져온 테이블에 적용이 될 수 있다.</p>
</li>
<li><p>GROUP BY</p>
<p> WHERE의 조건 적용 후 나머지 행은 GROUP BY절에 지정된 열의 공통 값을 기준으로 그룹화된다. </p>
<p> 쿼리에 집계 기능이 있는 경우에만 이 기능을 사용해야 한다.</p>
</li>
<li><p>HAVING</p>
<p> GROUP BY 절이 쿼리에 있을 경우 HAVING 절의 제약조건이 그룹화된 행에 적용됌.</p>
</li>
<li><p>SELECT</p>
<p> SELECT에 표현된 식이 마지막으로 적용됌.</p>
</li>
<li><p>DISTINCT</p>
<p> 표현된 행에서 중복된 행은 삭제됌</p>
</li>
<li><p>ORDER BY</p>
<p> 지정된 데이터를 기준으로 오름차순, 내림차순을 지정</p>
</li>
<li><p>LIMIT / OFFSET</p>
<p> LIMIT와 OFFSET에서 벗어나는 행들이 제외되어서 출력됨</p>
</li>
</ol>
</li>
</ul>
<h3 id="데이터-유형">데이터 유형</h3>
<ul>
<li>문자<ul>
<li>CHAR<ul>
<li>고정된 길이</li>
<li>비교 : 길이가 다른 경우 스페이스(공백) 하나 추가해서 비교<ul>
<li>예를들어, CHAR(8)이고 ‘AA’ 가 저장된 경우, ‘AA’에 공백 6자리 붙인 ‘AA      ‘로 타 문자와 비교</li>
</ul>
</li>
</ul>
</li>
<li>VARCHAR<ul>
<li>가변길이</li>
<li>비교 : 공백또한 한 문자로 취급해서 비교, 길이 짧은거 끝나면 그대로 비교 종료함</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="insert">INSERT</h3>
<ul>
<li>Identity<ul>
<li>SQL SERVER : IDENTITY [ ( seed , increment ) ]<ul>
<li>seed : 시작</li>
<li>increment : 증가값</li>
</ul>
</li>
<li>insert 문에 indentity인 컬럼에 값 넣으면 ERROR</li>
</ul>
</li>
<li>check<ul>
<li>check 조건 만족못하면 ERROR, NULL은 무시</li>
</ul>
</li>
</ul>
<h3 id="join">JOIN</h3>
<ul>
<li><p>JOIN 종류</p>
<ul>
<li><p>Natural Join</p>
<ul>
<li><p>두 테이블간 동일한 이름과 형식의 컬럼이 하나 있는 경우 사용가능</p>
</li>
<li><p>식별자 가질 수 없음 ( <code>EMP.DEPTNO</code> 같은 owner 명 기재 불가)</p>
<pre><code class="language-sql">  SELECT EMP.DEPTNO, EMPNO, ENAME, DNAME FROM EMP NATURAL JOIN DEPT; // ERROR</code></pre>
</li>
</ul>
</li>
<li><p>Using</p>
<ul>
<li><p>두 테이블간 동일한 이름과 형식의 컬럼이 둘 이상인 경우 natural join 사용 불가. 이때 using 사용</p>
<pre><code class="language-sql">SELECT *
FROM DEPT JOIN DEMPT_TEMP
USING (DEPTNO);</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="sub-query">Sub Query</h3>
<blockquote>
</blockquote>
<p><strong>SELECT col1, (SELECT ...)     -- 스칼라 서브쿼리(Scalar Sub Query): 하나의 컬럼처럼 사용 (표현 용도)</strong>
<strong>FROM (SELECT ...)             -- 인라인 뷰(Inline View): 하나의 테이블처럼 사용 (테이블 대체 용도)</strong>
<strong>WHERE col = (SELECT ...)    -- 일반 서브쿼리: 하나의 변수(상수)처럼 사용 (서브쿼리의 결과에 따라 달라지는 조건절)</strong></p>
<ul>
<li>Inline View<ul>
<li>from 절 내에서 쓰이는 서브쿼리</li>
<li>select 절을 마치 테이블처럼 쓰고 싶을 때 사용</li>
<li>메인쿼리에서 서브쿼리 컬럼 사용 가능</li>
</ul>
</li>
</ul>
<h3 id="여러-함수">여러 함수</h3>
<ul>
<li><p>NULL 처리 함수</p>
<ul>
<li><p>⭐ <code>NVL(v1,v2)</code> : Null 이 컬럼에 포함된 경우 어떠한 값으로 치환하는 함수</p>
<ul>
<li><p>v1 에 null 이 있다면 v2 로 치환 보통 문자면 ‘X’, 숫자면 0 으로 치환함</p>
<pre><code class="language-sql">SELECT COL1, COL2
FROM TAB1
WHERE NVL(COL1, &#39;X&#39;) &lt;&gt; &#39;A01&#39;;</code></pre>
</li>
<li><p>COL1이 NULL 인 경우 ‘X’ 로 치환, 그 후 COL1값이 ‘A01’이 아니면 출력 → 보통 Null 행도 출력하기 위해 사용함(해당 함수를 사용하지 않는다면 Null인 행은 자동으로 배제되고 출력됨)</p>
</li>
<li><p>실행결과</p>
<pre><code class="language-sql">  &lt;TAB1 테이블 구조&gt;
  COL1 COL2
  A01 10
  A02 20
  A03 30 
  NULL 40 
  NULL 50

  &lt;실행 결과&gt;
  CO1 CO2 
  A02 20 
  A03 30 
  NULL 40 
  NULL 50</code></pre>
</li>
</ul>
</li>
<li><p><code>ISNULL(v1,v2)</code> : NVL과 동일</p>
</li>
<li><p><code>COALESCE(v1,v2,...,vn)</code> : 모든 v들이 null이면 null 반환하지만, 하나라도 아닌 경우 null이 아닌 최초의 표현식을 반환</p>
</li>
<li><p><code>NULLIF(v1,v2)</code> : 특정값을 NULL로 대치하기 위한 함수</p>
<ul>
<li>v1이 v2이라면 NULL로 치환</li>
</ul>
</li>
</ul>
</li>
<li><p>문자열 관련 함수</p>
<ul>
<li>문자열 이어붙이기 : <code>+</code>, <code>||</code>(연산자), <code>CONCAT</code>,</li>
<li>공백제거 : <code>trim</code></li>
</ul>
</li>
<li><p>length(), len()</p>
<ul>
<li>length() : ORACLE</li>
<li>len() : SQL SERVER</li>
</ul>
</li>
<li><p>집계함수</p>
<ul>
<li><p><code>AVG</code></p>
<ul>
<li>해당 칼럼값이 NULL 인 것 제외해서 결과 반환</li>
</ul>
</li>
<li><p><code>SUM</code></p>
<ul>
<li>해당 칼럼값이 NULL 인 것 제외해서 결과 반환</li>
</ul>
</li>
<li><p><code>COUNT</code></p>
<ul>
<li><p>아무 결과도 반환안하면 0을 반환함</p>
<ul>
<li><p>이외의 다른 집계함수는 아무 결과가 없다면 NULL → <code>NVL</code>함수 필요</p>
<pre><code class="language-sql">SELECT nvl(count(*), 9999) from table where 1=2 // 0</code></pre>
</li>
</ul>
</li>
<li><p><code>COUNT(*)</code> : NULL 포함해서 결과 반환</p>
</li>
<li><p><code>COUNT(column)</code> : 해당 컬럼값이 NULL 인것 제외해서 결과 반환</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>SQL의 IF-ELSE</p>
<ul>
<li><code>DECODE(칼럼,조건1,결과1,조건2,결과2,...)</code><ul>
<li>칼럼 == 조건1 → 결과1 반환</li>
<li>해당 조건이 없는경우 <code>NULL</code> 반환</li>
</ul>
</li>
<li><code>CASE</code> : 최근 권장<ul>
<li><code>ELSE</code> 없고 해당값이 아니면 <code>NULL</code> 반환</li>
</ul>
</li>
</ul>
</li>
<li><p>WINDOW FUNCTION</p>
<ul>
<li><p>윈도우 함수 개념 정리</p>
<ul>
<li><a href="https://velog.io/@yewon-july/Window-Function">https://velog.io/@yewon-july/Window-Function</a></li>
</ul>
<pre><code class="language-sql">SELECT WINDOW_FUNCTION(ARGUMENTS)
OVER (PARTITION BY 칼럼
          ORDER BY WINDOWING절
          RANGE BETWEEN start_point AND end_point)
FROM 테이블명;</code></pre>
</li>
<li><p>WINDOW_FUNCTION 가능한 것</p>
<ul>
<li>집계함수 ( COUNT, AVG, ... )</li>
<li>순위함수<ul>
<li>RANK() : 4,5,5,5,8 (동일 순위에 대해 하나의 등수로 매기지만, 그 다음 등수는 중복값 개수 쳐서 진행)</li>
<li>RANK_DENSE() : 4,5,5,5,6 (동일 등수에 대해 하나의 등수로 매기고, 그 다음 등수는 해당 등수 다음)</li>
<li>ROW_NUMBER() : 4,5,6,7,8 (동일 등수에 대해서도 순위 매김)</li>
<li>PERCENT_RANK() : 값이 아닌 백분율로 순위 매김 (0~1 사이값 반환)</li>
</ul>
</li>
</ul>
</li>
<li><p><code>PARTITION_BY</code> : group by 과 비슷</p>
</li>
<li><p><code>RANGE BETWEEN start_point AND end_point</code> : 누적 평균 낼 수 있음</p>
<ul>
<li><p>default : <code>RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW</code> : 누적평균</p>
</li>
<li><p><code>UNBOUNDED PRECEDING</code> : start_point만 들어갈 수 있으며, 파티션의 first row</p>
</li>
<li><p><code>UNBOUNDED FOLLOWING</code> : end_point만 들어갈 수 있으며, 파티션의 last row</p>
</li>
<li><p><code>CURRENT ROW</code> : start, end_point 둘다 가능. 윈도우는 CUREENT ROW에서 start하거나 end 함</p>
</li>
<li><p>누적평균 예제</p>
<pre><code class="language-sql">  SELECT COL1, COL2,
  ROUND ( AVG (COL3) 
      OVER( PARTITION BY COL1 ORDER BY COL3
                  RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
      ) , 0)
      AS 누적평균
  FROM TAB1 
  ORDER BY COL1, COL3;
</code></pre>
<ul>
<li>COL1 로 파티션되어서 파티션 내의 누적평균</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p>그룹 함수</p>
<ul>
<li><p>ROLLUP</p>
<ul>
<li>인수 순서 상관O<ul>
<li>1번째 인수 중심</li>
</ul>
</li>
</ul>
</li>
<li><p>CUBE</p>
<ul>
<li>인수 순서 상관X<ul>
<li>인수에 따라 나올 수 있는 모든 경우의 수 출력해줌</li>
</ul>
</li>
</ul>
</li>
<li><p>GROUPING SETS</p>
<p><a href="https://velog.io/@dongchyeon/%EC%98%A4%EB%9D%BC%ED%81%B4Oracle-%EA%B7%B8%EB%A3%B9-%ED%95%A8%EC%88%98-ROLLUP-CUBE-GROUPING-%EB%93%B1">https://velog.io/@dongchyeon/오라클Oracle-그룹-함수-ROLLUP-CUBE-GROUPING-등</a></p>
</li>
</ul>
</li>
</ul>
<h3 id="연산자">연산자</h3>
<ul>
<li><p><code>IN</code></p>
<ul>
<li><code>COL1 IN(NULL, &#39;A&#39;)</code> : COL1 = Null or COL1 = ‘A’ 로 치환됨. 결과는 null인 행은 출력안함</li>
<li><code>COL1 NOT IN(NULL, &#39;A&#39;)</code> : NOT IN의 조건절에 <code>NULL</code> 이 하나라도 포함되면 아무행도 출력안함</li>
<li>IN, ANY, ALL<ul>
<li>IN(10,20,30) : 10,20,30 값 중 하나</li>
<li>ANY(10,20,30) : 10,20,30 어떤 값보다 - 비교연산자 사용</li>
<li>ALL(10,20,30) : 10,20,30 모두보다 - 비교연산자 사용</li>
</ul>
</li>
<li>IN, EXISTS<ul>
<li>IN : 컬럼 값 비교할 때 좋음, 서브쿼리는 안넣는게 좋음<ul>
<li>일치하지 않더라도 서브쿼리를 모두 수행하기 때문에 별로 안좋음</li>
<li><code>SELECT * FROM A WHERE A.v1 IN (SELECT B.v1 FROM B)</code> : not good</li>
</ul>
</li>
<li>EXISTS : 서브쿼리 넣어서 비교할 때 좋음(성능상)<ul>
<li>한 건이라도 만족하면 <code>true</code></li>
<li>일치하지 않다면 더이상 서브쿼리를 실행하지 않는다. - 뭔말인지 이해안감</li>
<li><code>SELECT * FROM A WHERE EXISTS (SELECT &#39;X&#39; FROM B WHERE A.v1 = B.v1)</code> : good<ul>
<li>서브쿼리절의 컬럼은 불필요함 - 의미없는 값(’X’) 넣음</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p><code>=</code></p>
<ul>
<li><code>COL1=NULL</code> : NULL 을 비교시 항상 False를 함. 따라서 실제 Null인 행이 있어도 출력 암것도 안함</li>
</ul>
</li>
<li><p><code>IS</code>, <code>IS NOT</code></p>
<ul>
<li>유일하게 NULL 을 잡아낼 수 있는 연산자</li>
</ul>
</li>
<li><p><code>SUM</code></p>
<ul>
<li><code>SUM(NULL, 1)</code> : 1</li>
</ul>
</li>
<li><p>SET 연산자</p>
<ul>
<li><p><code>INTERSECT</code></p>
</li>
<li><p><code>UNION</code></p>
<ul>
<li><p><code>UNION ALL</code> : 중복 제거하기 위한 정렬 안함</p>
<ul>
<li><p>문제</p>
<pre><code class="language-sql">  [데이터]
  TABLE A 
  COL1 COL2 
  -----------
     1    2
     1    2
     1    3
  TABLE B 
  COL1 COL2 
  -----------
     1    2 
     1    4 
     1    5
  [SQL]
  SELECT DISTINCT COL1, COL2 FROM TAB_A 
  UNION ALL
  SELECT COL1, COL2 FROM TAB_B;

  // 결과 : 5</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="having">Having</h3>
<ul>
<li><p><code>HAVING COUNT(*)</code></p>
<pre><code class="language-sql">  SELECT 주문일자, 고객명, COUNT(*) 
  FROM TAB1
  GROUP BY 주문일자,고객명
  HAVING COUNT(*) &gt;= 2;</code></pre>
<ul>
<li>2건 이상 주문하는 고객리스트</li>
</ul>
</li>
</ul>
<h3 id="order-by">Order by</h3>
<ul>
<li>order by 절에는 숫자 가능<ul>
<li>0 : 해당 column 을 가장 위에 오게 함 (CASE 와 함께 쓰임 <code>order by case ROWNUM when 3 then 0</code>)</li>
<li>1,2,3,... : <code>select a,b,c</code> 일때 a 가 1, b가 2, c가 3, 만약 여기서 <code>order by 4</code> 하면 오류남(4에 해당하는 칼럼이 없으므로)</li>
</ul>
</li>
<li>group by 가 있는 경우 order by 에 집계함수 사용 가능<ul>
<li><code>group by col1 order by count(*)</code> : col1에 따라 개수 셈</li>
</ul>
</li>
<li>select 절에서 alias 로 명명지은 이름 사용가능<ul>
<li><code>select user_name as name from dept order by name</code></li>
<li>SQL 실행순서와 관련있음 (select 이후에 order by를 행하므로 select 시에 alias 로 지은 이름을 사용할 수 있는 것)</li>
<li>비교 : <code>group by</code> 절 내에서는 alias 로 명명지은 이름 사용 불가 (group by 는 select 이전에 실행되기 때문)</li>
</ul>
</li>
</ul>
<h3 id="sql-server-↔-oracle">SQL Server ↔ Oracle</h3>
<ul>
<li><p><code>TOP</code>(SQL Server), <code>ROWNUM</code> : Oracle</p>
<ul>
<li><p>oracle</p>
<pre><code class="language-sql">  SELECT ENAME, SAL
  FROM (SELECT ENAME, SAL
              FROM SCOTT.EMP
              ORDER BY SAL DESC) 
  WHERE ROWNUM &lt; 4 ;</code></pre>
</li>
<li><p>SQL server</p>
<pre><code class="language-sql">  SELECT TOP(3) ENAME,SAL 
  FROM SCOTT.EMP
  ORDER BY SAL DESC</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="ansi-sql-표준">ANSI SQL 표준</h3>
<ul>
<li><p>모든 DBMS에 통하는 SQL문</p>
</li>
<li><p>Inner Join 표준</p>
<ul>
<li><p>오라클</p>
<pre><code class="language-sql">  SELECT *
  FROM SCOTT.EMP A,
  SCOTT.DEPT B
  WHERE A.DEPTNO = B.DEPTNO AND B.DNAME = &#39;SALES&#39;</code></pre>
</li>
<li><p>ANSI 표준</p>
<pre><code class="language-sql">  SELECT *
  FROM SCOTT.EMP A INNER JOIN SCOTT.DEPT B
  ON A.DEPTNO = B.DEPTNO 
  WHERE 1=1
  AND B.DNAME =&#39;SALES&#39;;</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="view뷰">VIEW(뷰)</h3>
<ul>
<li><p>개념</p>
<ul>
<li><p>사용자에게 제한적으로 자료를 보여주기 위한 가상 테이블</p>
<ul>
<li>필요한 데이터만 뷰로 정의 가능</li>
</ul>
</li>
<li><p>물리적으로 존재X, 임시작업(데이터 보정, 처리과정)위한 용도</p>
</li>
<li><p>뷰정의 변경 불가(ALTER VIEW 안됨)</p>
<ul>
<li>변경이 필요하다면 삭제후에 정의 다시해야함</li>
</ul>
</li>
<li><p>뷰로 구성된 내용삽입,제거,연산,갱신 제약O</p>
</li>
<li><p>예제</p>
<ul>
<li><p>정의문</p>
<pre><code class="language-sql">  --문법--
  CREATE VIEW 뷰이름[(속성이름[,속성이름])]AS SELECT문;

  --고객 테이블에서 주소가 서울시인 고객들의 성명과 전화번호를 서울고객이라는 뷰로 만들어라--
  CREATE VIEW 서울고객(성명, 전화번호)
  AS SELECT 성명 전화번호
  FROM 고객
  WHERE 주소 = &#39;서울시&#39;;</code></pre>
</li>
<li><p>삭제문</p>
<pre><code class="language-sql">  --문법--
  DROP VIEW 뷰이름 RESTRICT or CASCADE

  --서울고객이라는 뷰를 삭제해라--
  DROP VIEW 서울고객 RESTRICT;</code></pre>
<p>  RESTRICT : 뷰를 다른곳에서 참조하고 있으면 삭제가 취소된다.
  CASCADE : 뷰를 참조하는 다른 뷰나 제약 조건까지 모두 삭제된다.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="계층형-질의-계층형-sql">계층형 질의 (계층형 SQL)</h3>
<ul>
<li><p>쉽게 설명</p>
<p>  <a href="https://mjn5027.tistory.com/55">https://mjn5027.tistory.com/55</a></p>
</li>
<li><p>계층형 쿼리 관련</p>
<p>  <a href="https://devdhjo.github.io/sqld/2019/11/26/database-sqld-020.html">https://devdhjo.github.io/sqld/2019/11/26/database-sqld-020.html</a></p>
</li>
<li><p>MAX(LEVEL) : 계층형 쿼리에서 최대 계층 수 구함</p>
<pre><code class="language-sql">  SELECT MAX(LEVEL)
  FROM SCOTT.EMP
  START WITH MGR IS NULL
  CONNECT BY PRIOR EMPNO = MGR;</code></pre>
<ul>
<li>매니저~사원까지 결제 단계가 가장 많은 레벨을 구함</li>
</ul>
</li>
</ul>
<h3 id="trigger">Trigger</h3>
<ul>
<li>특정 테이블에서 DML(select,insert,update,delete)이 일어나게 된다면 자동적으로 데이터베이스에서 수행되도록 만들어진 프로그램<ul>
<li>결국 해당 DML과는 트랜잭션 관계</li>
<li>begin,end 절 내에서는 TCL(COMMIT, ROLLBACK) 사용 불가</li>
</ul>
</li>
<li><code>:OLD</code> : 기존 데이터</li>
<li><code>:NEW</code> : 변경될 데이터</li>
</ul>
<h3 id="최적화">최적화</h3>
<ul>
<li><p>Optimizer (옵티마이저)</p>
<ul>
<li>비용 기반 옵티마이저 : 쿼리 수행시 소요되는 시간 및 일량 기준으로 최적화 수행</li>
</ul>
</li>
<li><p>실행계획</p>
</li>
<li><p>INDEX(인덱스)</p>
<ul>
<li><p>효율적으로 숫자 인덱스를 사용하는 방법?</p>
<ul>
<li><p>= 으로 찾기 (WHERE COL1 = 10)</p>
</li>
<li><p>비효율적인 방법</p>
<p>  WHERE COL1 LIKE &#39;2%&#39; : LIKE - 문자로 변환해서 인덱스 사용 못함
  WHERE COL1 IS NOT NULL : 인덱스 풀 조회하지만, 효율 떨어짐
  WHERE COL1 &lt;&gt; 10 : 부정형 비교(<code>&lt;&gt;</code>, <code>!=</code>, <code>^=</code>, <code>NOT</code>)는 인덱스 사용 불가</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>JOIN</p>
<ul>
<li>⭐Nested Loop Join, Sort Merge Join, <strong>Hash Join</strong><ul>
<li>Nested Loop Join<ul>
<li>C++의 중첩된 반복문처럼 조인 수행</li>
<li>INDEX 사용</li>
<li>데이터 읽는 방식 : 랜덤 액세스<ul>
<li>ex ) Index scan</li>
</ul>
</li>
<li>대량의 데이터에 적합 X</li>
<li>빨리 조인 결과를 보여줘야 하는 경우 굳</li>
</ul>
</li>
<li>Sort Merge Join<ul>
<li>먼저 조인할 두 테이블의 SORT 부터 수행 후 merge 해서 join<ul>
<li>sort 로 인해 disk 를 사용할 수 있어 성능이 그렇게 좋지 않음(느리다)</li>
</ul>
</li>
<li>INDEX 사용 안함</li>
<li>Non Equal Join 가능</li>
<li>대량의 데이터는 성능상 Hash Join 이 유리함</li>
</ul>
</li>
<li>Hash Join<ul>
<li>NL Join(랜덤 액세스), Sort Merge Join(선 sort로 인한 느림) 문제점 해결</li>
<li>INDEX 사용 안함</li>
<li>Non Equal Join 불가능</li>
<li>대량의 데이터 처리시 굳! (CPU 작업 위주로 처리하기 때문)</li>
</ul>
</li>
<li><a href="https://hoon93.tistory.com/46">https://hoon93.tistory.com/46</a></li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[mistake][python] 이중 리스트 초기화 시 복사관련 문제]]></title>
            <link>https://velog.io/@mong-head/mistakepython-%EC%9D%B4%EC%A4%91-%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EC%B4%88%EA%B8%B0%ED%99%94-%EC%8B%9C-%EB%B3%B5%EC%82%AC%EA%B4%80%EB%A0%A8-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@mong-head/mistakepython-%EC%9D%B4%EC%A4%91-%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EC%B4%88%EA%B8%B0%ED%99%94-%EC%8B%9C-%EB%B3%B5%EC%82%AC%EA%B4%80%EB%A0%A8-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Mon, 17 Jan 2022 21:42:29 GMT</pubDate>
            <description><![CDATA[<p>탐색 문제를 풀다가 보면 그래프를 방문했는지 하지 않았는지 체크하는 <code>visited</code> 이중 배열을 만드는 경우가 많다.</p>
<p>이 <code>visited</code>를 초기화할 때 밑과 같은 방법으로 했더니 잘 동작하지 않았다.</p>
<pre><code class="language-py">visited = [[False]*3]*4

visited[1][2] = True</code></pre>
<p>이때, <code>visited</code>를 출력해보면, 밑과 같다.</p>
<pre><code class="language-py">[[False, False, True], 
[False, False, True], 
[False, False, True], 
[False, False, True]]</code></pre>
<p>바꾸려고 했던 (1,2)의 값만 바뀌지 않고, 모두 바뀌는 것이었다. </p>
<p>제대로 동작하도록 수정해보면 다음과 같다.</p>
<pre><code class="language-py">visited_ = [ [False]*3 for l in range(4) ]

visited_[1][2] = True
print(visited_)</code></pre>
<p>이때, <code>visited_</code>를 출력해보면 원하는 대로 (1,2)만 수정된 것을 볼 수 있다.</p>
<pre><code class="language-py">[[False, False, False], 
[False, False, True], 
[False, False, False], 
[False, False, False]]</code></pre>
<h2 id="결론">결론</h2>
<p>리스트를 포함하는 리스트에 곱하기 연산자를 사용하면, 얕은 복사가 되어, 값 하나를 변경시 모두 변경된다. 따라서 초기화할 때에는 반드시 밑처럼 사용하자.</p>
<pre><code class="language-py">visited = [ [False]*3 for _ in range(4) ]</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Mistake](JS) 어떠한 값 중에 하나인지 비교]]></title>
            <link>https://velog.io/@mong-head/%EC%8B%A4%EC%88%98JS-%EC%96%B4%EB%96%A0%ED%95%9C-%EA%B0%92-%EC%A4%91%EC%97%90-%ED%95%98%EB%82%98%EC%9D%B8%EC%A7%80-%EB%B9%84%EA%B5%90</link>
            <guid>https://velog.io/@mong-head/%EC%8B%A4%EC%88%98JS-%EC%96%B4%EB%96%A0%ED%95%9C-%EA%B0%92-%EC%A4%91%EC%97%90-%ED%95%98%EB%82%98%EC%9D%B8%EC%A7%80-%EB%B9%84%EA%B5%90</guid>
            <pubDate>Sat, 15 Jan 2022 00:53:11 GMT</pubDate>
            <description><![CDATA[<h2 id="어떠한-값-중-하나인지-비교방법">어떠한 값 중 하나인지 비교방법</h2>
<ul>
<li><code>includes</code> 사용<pre><code class="language-js">currentLocation = &#39;local&#39;;
[&#39;local&#39;,&#39;dev&#39;].includes(currentLocation)</code></pre>
</li>
</ul>
<h2 id="실수">실수</h2>
<h3 id="실수-코드">실수 코드</h3>
<ul>
<li><code>||</code> 사용해서 해결하려고 함<pre><code class="language-js">currentLocation = &#39;local&#39;;
curretLocation === (&#39;local&#39; || &#39;dev&#39;)</code></pre>
</li>
</ul>
<h3 id="실수-상황">실수 상황</h3>
<p>현재 빌드한 상황이 로컬인지 개발기인지 운영기인지 비교하기 위해서 해당 코드를 작성했다. 저 코드를 작성하고 로컬에서 잘 돌아가네 싶어서 올렸는데 개발기에서 동작하지 않는 것이었다.. </p>
<p>다시 살펴보니 <code>||</code> 연산자는 값을 리턴하는 &#39;연산자&#39;였던 것이었다.. <code>&#39;local&#39; || &#39;dev&#39;</code> 하면 당연히 해당 연산에서는 local을 값으로 리턴한다. 어쩌다 이렇게 바보같은 코드를 짜고 돌아간다고 생각한건지 모르겠다. </p>
<p>여하튼 어떠한 값이 여러개 값 중 하나인지 검사할 때에는 <code>includes</code>를 쓰자!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[intellij] 기존 프로젝트 dependency 관련]]></title>
            <link>https://velog.io/@mong-head/intellij-%EA%B8%B0%EC%A1%B4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-dependency-%EA%B4%80%EB%A0%A8-x8031hdz</link>
            <guid>https://velog.io/@mong-head/intellij-%EA%B8%B0%EC%A1%B4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-dependency-%EA%B4%80%EB%A0%A8-x8031hdz</guid>
            <pubDate>Mon, 27 Dec 2021 06:33:13 GMT</pubDate>
            <description><![CDATA[<p>pom.xml에 없는 module의 경우 lib에 저장이 되어있다.
그 lib를 <code>Add as Library</code> 설정</p>
<p><img src="https://images.velog.io/images/mong-head/post/21b2eb56-6334-4e4d-83e3-c16833abc35f/addAsLib.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Error] [React] [Redux-Saga] saga 무한히 실행]]></title>
            <link>https://velog.io/@mong-head/Error-React-Redux-Saga-saga-%EB%AC%B4%ED%95%9C%ED%9E%88-%EC%8B%A4%ED%96%89</link>
            <guid>https://velog.io/@mong-head/Error-React-Redux-Saga-saga-%EB%AC%B4%ED%95%9C%ED%9E%88-%EC%8B%A4%ED%96%89</guid>
            <pubDate>Tue, 21 Dec 2021 01:16:37 GMT</pubDate>
            <description><![CDATA[<h2 id="error">Error</h2>
<p><img src="https://github.com/mong-head/error/blob/master/images/saga_infinite_loop_problem.PNG?raw=true" alt="https://github.com/mong-head/error/blob/master/images/saga_infinite_loop_problem.PNG?raw=true"></p>
<ul>
<li><p>문제</p>
<ul>
<li>상황 : mount하는 시점에 dispatch실행</li>
<li>mount, action은 한번씩만 불렸지만, reducer과 saga는 여러번 호출됨</li>
</ul>
</li>
<li><p>관련 코드</p>
<ul>
<li><p>Component (Layout.js)</p>
<pre><code class="language-jsx">  import React, {Component} from &#39;react&#39;;
  import { connect } from &#39;react-redux&#39;;
  import &#39;../assets/css/Contacts.css&#39;;
  import {selectedContactAction} from &#39;../Store/Actions/selectedContactAction&#39;
  import {setContacts} from &#39;../Store/Sagas/contactsSaga&#39;;

  class Layout extends Component {

      async componentDidMount() {
          this.props.setContacts();
      }

      render() {

          return (
              &lt;div className={&#39;contacts&#39;}&gt;
                    {
                                      this.props.contacts
                              }  
              &lt;/div&gt;
          );
      }
  }

  const mapStateToProps = (state) =&gt; ({
      contacts : state.contacts
  });

  const mapDispatchToProps = (Dispatch) =&gt; {
      return {
          setContacts : () =&gt; Dispatch(contactsSetAction())
      }
  }

  export default connect(mapStateToProps,mapDispatchToProps)(Layout);</code></pre>
</li>
<li><p>Action Types (types.js)</p>
<pre><code class="language-jsx">  export const contactsType = {
      CONTACTS_SET : &#39;CONTACTS_SET&#39;
  }</code></pre>
</li>
<li><p>Action (contactsAction.js)</p>
<pre><code class="language-jsx">  export const contactsSetAction = () =&gt; {
      return { type: contactsType.CONTACTS_SET }
  };</code></pre>
</li>
<li><p>Saga (contactsSaga.js)</p>
<pre><code class="language-jsx">  export function* setContacts(){
      try{
          const response = yield call(fetchApi().getAll);
          yield put({type: contactsType.CONTACTS_SET, contacts : response.map(symbolizeObjectId)});
      } catch (error) {
          yield put({type: contactsType.CONTACTS_SET, contacts : {}})
      } finally {
      }
  }

  const saga = [
      takeLatest(contactsType.CONTACTS_SET, contactsSaga.setContacts),
  ]
  export default saga;</code></pre>
</li>
<li><p>Reducer (contactReducer.js)</p>
<pre><code class="language-jsx">  import { contactsType } from &#39;../Actions/types&#39;;

  const contactsReducer = (state = [], action) =&gt; {
      switch (action.type) {
          case contactsType.CONTACTS_SET:
              return action.contacts ? action.contacts : state;
          default:
              return state;
      }
  };

  export default contactsReducer;</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="solve">Solve</h2>
<p><img src="https://github.com/mong-head/error/blob/master/images/saga_infinite_loop_problem_solved.PNG?raw=true" alt="https://github.com/mong-head/error/blob/master/images/saga_infinite_loop_problem_solved.PNG?raw=true"></p>
<ul>
<li><p>Action, Saga 용 type과 reducer용 type을 나누기</p>
<ul>
<li>Action, Saga 용 : <code>CONTACTS_SET</code></li>
<li>reducer 용 : <code>CONTACTS_SET_RESULT</code></li>
</ul>
</li>
<li><p>변경한 코드 (<code>CONTACTS_SET_RESULT</code> 추가)</p>
<ul>
<li><p>Action Types (types.js)</p>
<pre><code class="language-jsx">  export const contactsType = {
      CONTACTS_SET : &#39;CONTACTS_SET&#39;, //action, saga용
      CONTACTS_SET_RESULT : &#39;CONTACTS_SET_RESULT&#39; // reducer 용
  }</code></pre>
</li>
<li><p>Saga (contactsSaga.js)</p>
<pre><code class="language-jsx">  export function* setContacts(){
      try{
          const response = yield call(fetchApi().getAll);
          yield put({type: contactsType.CONTACTS_SET_RESULT, contacts : response.map(symbolizeObjectId)});
      } catch (error) {
          yield put({type: contactsType.CONTACTS_SET_RESULT, contacts : {}})
      } finally {
      }
  }

  const saga = [
      takeLatest(contactsType.CONTACTS_SET, contactsSaga.setContacts),
  ]
  export default saga;</code></pre>
</li>
<li><p>Reducer (contactReducer.js)</p>
<pre><code class="language-jsx">  import { contactsType } from &#39;../Actions/types&#39;;

  const contactsReducer = (state = [], action) =&gt; {
      switch (action.type) {
          case contactsType.CONTACTS_SET_RESULT:
              return action.contacts ? action.contacts : state;
          default:
              return state;
      }
  };

  export default contactsReducer;</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="핵심">핵심</h2>
<p>무한히 saga를 호출하지 않게 하기 위해서 <code>takeLatest</code>에서 지켜보는 type과 <code>put</code>하는 type를 같게 하면 안된다.</p>
<ul>
<li><p>error 주요 코드</p>
<pre><code class="language-jsx">  export function* setContacts(){
      try{
          const response = yield call(fetchApi().getAll);
          yield put({type: contactsType.CONTACTS_SET, contacts : response.map(symbolizeObjectId)});
      } catch (error) {
          yield put({type: contactsType.CONTACTS_SET, contacts : {}})
      } finally {
      }
  }

  // Action이랑 Saga 연결
  const saga = [
      takeLatest(contactsType.CONTACTS_SET, contactsSaga.setContacts)
  ];
  export default saga;</code></pre>
<ul>
<li><code>put</code>과 <code>takeLatest</code> type 같음</li>
</ul>
</li>
<li><p>good 주요 코드</p>
<pre><code class="language-jsx">  export function* setContacts(){
      try{
          const response = yield call(fetchApi().getAll);
          yield put({type: contactsType.CONTACTS_SET_RESULT, contacts : response.map(symbolizeObjectId)});
      } catch (error) {
          yield put({type: contactsType.CONTACTS_SET_RESULT, contacts : {}})
      } finally {
      }
  }

  // Action이랑 Saga 연결
  const saga = [
      takeLatest(contactsType.CONTACTS_SET, contactsSaga.setContacts)
  ];
  export default saga;</code></pre>
<ul>
<li><code>put</code>과 <code>takeLatest</code> type 다름</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Error] [React] [Redux-Saga] reducer null 반환]]></title>
            <link>https://velog.io/@mong-head/React-Redux-Saga-reducer-null-%EB%B0%98%ED%99%98</link>
            <guid>https://velog.io/@mong-head/React-Redux-Saga-reducer-null-%EB%B0%98%ED%99%98</guid>
            <pubDate>Wed, 15 Dec 2021 01:46:04 GMT</pubDate>
            <description><![CDATA[<h2 id="error">Error</h2>
<blockquote>
<p>Unhandled Rejection (Error): When called with an action of type &quot;CONTACTS_SET&quot;, the slice reducer for key &quot;contacts&quot; returned undefined. To ignore an action, you must explicitly return the previous state. If you want this reducer to hold no value, you can return null instead of undefined.</p>
</blockquote>
<h2 id="reducer-규칙">reducer 규칙</h2>
<ul>
<li>state 값으로 null, undefined 넘겨줄 수 없다.<ul>
<li>이전 state을 넘기거나 action에서 받아온 payload등을 넘겨야 함</li>
</ul>
</li>
</ul>
<h2 id="수정">수정</h2>
<ul>
<li>error<pre><code class="language-js">case contactsType.CONTACTS_SET:
  return action.contacts;</code></pre>
</li>
<li>good<pre><code class="language-js">case contactsType.CONTACTS_SET:
 return action.contacts ? action.contacts : state;</code></pre>
</li>
</ul>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://velog.io/@mokyoungg/Redux-Reducer-%EC%B6%94%EA%B0%80-%EB%82%B4%EC%9A%A9">reducer 규칙</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MySQL] 한글 깨짐 현상]]></title>
            <link>https://velog.io/@mong-head/MySQL-%ED%95%9C%EA%B8%80-%EA%B9%A8%EC%A7%90-%ED%98%84%EC%83%81</link>
            <guid>https://velog.io/@mong-head/MySQL-%ED%95%9C%EA%B8%80-%EA%B9%A8%EC%A7%90-%ED%98%84%EC%83%81</guid>
            <pubDate>Sat, 06 Nov 2021 11:36:26 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><img src="https://images.velog.io/images/mong-head/post/99c5a17f-ae72-4e82-bc29-ab7e3f9093f0/%EC%BA%A1%EC%B2%98.PNG" alt=""></p>
<p>한글이 깨져 이상한 문자로 보였다.</p>
<h2 id="해결">해결</h2>
<p>UTF8로 변경한다. 이때, 데이터베이스의 character set뿐만 아니라, 데이터베이스 내의 테이블의 character set도 변경한다.</p>
<ul>
<li>Database character set 변경<pre><code class="language-sql">alter database [DB명] default character set UTF8;</code></pre>
</li>
<li>Table character set 변경<pre><code class="language-sql">alter table [table명] convert to character set UTF8;</code></pre>
</li>
<li>해결한 코드
```sql</li>
<li><ul>
<li>character set 확인
show variables like &#39;c%&#39;;</li>
</ul>
</li>
</ul>
<p>-- database character set 변경
alter database covengers default character set UTF8;</p>
<p>-- table character set 변경
alter table room convert to character set UTF8;
alter table chat convert to character set UTF8;
alter table room convert to character set UTF8;
alter table room convert to character set UTF8;
alter table room convert to character set UTF8;</p>
<p>-- character set 확인
show variables like &#39;c%&#39;;
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] scss 관련 버전 문제]]></title>
            <link>https://velog.io/@mong-head/React-scss-%EA%B4%80%EB%A0%A8-%EB%B2%84%EC%A0%84-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@mong-head/React-scss-%EA%B4%80%EB%A0%A8-%EB%B2%84%EC%A0%84-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Sat, 06 Nov 2021 11:29:52 GMT</pubDate>
            <description><![CDATA[<h2 id="error">error</h2>
<pre><code class="language-text">Failed to compile.

./src/assets/scss/Index.scss (./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-5-1!./node_modules/postcss-loader/src??postcss!./node_modules/resolve-url-loader??ref--6-oneOf-5-3!./node_modules/sass-loader/dist/cjs.js??ref--6-oneOf-5-4!./src/assets/scss/Index.scss)
Error: Missing binding E:\project\covengers\hungry-chat-react\node_modules\node-sass\vendor\win32-x64-57\binding.node
Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 8.x   

Found bindings for the following environments:
  - Windows 64-bit with Node.js 14.x</code></pre>
<p> npm install을 하고 모듈 설치를 한 후 npm start를 했을 때 이러한 오류가 뜨며 리액트가 실행되지 않았다.</p>
<h2 id="해결">해결</h2>
<p>scss 문제는 대개 버전 관련 문제라고 한다. 오래 전 업데이트를 한 후 이후로 업데이트가 없어서 최신 버전의 Java 나 Node를 사용할 경우 해당 오류가 발생하게 된다.</p>
<ul>
<li>Java version 8~11</li>
<li>Node version 14<ul>
<li>Node 16 이나 8 이면 Node 제거하고 재설치</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Socket 이벤트 중복 호출 방지]]></title>
            <link>https://velog.io/@mong-head/React-Socket-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%A4%91%EB%B3%B5-%ED%98%B8%EC%B6%9C-%EB%B0%A9%EC%A7%80</link>
            <guid>https://velog.io/@mong-head/React-Socket-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%A4%91%EB%B3%B5-%ED%98%B8%EC%B6%9C-%EB%B0%A9%EC%A7%80</guid>
            <pubDate>Sun, 15 Aug 2021 10:45:13 GMT</pubDate>
            <description><![CDATA[<h3 id="상황">상황</h3>
<ul>
<li><p>Chatting app 개발 (socket.io,redis 이용 구현)</p>
</li>
<li><p>개발 환경</p>
<ul>
<li>backend : node</li>
<li>frontend : React</li>
</ul>
</li>
<li><p>문제 상황</p>
<ul>
<li>server(node)쪽에서 client(React)쪽으로 메세지를 보내줄 때마다 메세지를 보낼 때마다 메세지 받고 출력하는 이벤트가 급수적으로 추가적으로 불러져서 동일한 메세지가 여러개 생성되었습니다.</li>
</ul>
</li>
</ul>
<h3 id="문제">문제</h3>
<p>React에서 아무 장소에서나 socket 이벤트 호출(<code>socket.on(&#39;message&#39;,function)</code>)하는 코드를 작성하니 rendering 될 때마다 socket이 하나씩 추가되어 이벤트도 그에 따라 여러번 호출되는 현상이 발생하였습니다. </p>
<p>즉, 한 번 rendering될 때마다 socket이 하나씩 추가되고, 하나의 이벤트가 발생할 것이라고 예상한 것이 실제로는 생성된 socket수 만큼 이벤트를 발생하였기에 rendering한  수가 2번이면 socket 수가 2개이고, 이벤트도 2번 호출되었습니다.</p>
<h3 id="해결">해결</h3>
<p>찾아보니 rendering될 때마다 socket은 계속 생성되는 것이 맞습니다. 다만, 문제는 생성된 모든 socket 객체가 event를 실행하는 데에 있었습니다. </p>
<p>이 문제는 react component life-cycle과 관련이 있습니다. socket 호출(<code>socket.on</code>)부분은 component가 한 번 mount된 후(즉, 처음 socket이 생성되었을 때)만 호출되어야 합니다. component update될 때마다 socket 호출이 있게되면 생성된 소켓 수만큼 호출되게 됩니다. 따라서 한 번 mount된 직후에만 호출될 수 있도록(socket이 처음 생성된 후에만) 만드시면 됩니다.</p>
<p>따라서, <strong>class component</strong>인 경우, 밑처럼 <code>componentDidMount</code>내에서만 <code>socket.on</code>을 하시면 됩니다.</p>
<pre><code class="language-js">componentDidMount() {
  socket.on(&quot;comment&quot;, (info) =&gt; {
    this.textAreaAdd(info.name, info.room, info.message)
  }) 
}</code></pre>
<p><strong>function component</strong>인 경우, 밑처럼 hook함수인 useEffect를 이용해서 하시면 됩니다.</p>
<pre><code class="language-js">useEffect(() =&gt; {
  socket.on(&quot;comment&quot;, (info) =&gt; {
    this.textAreaAdd(info.name, info.room, info.message)
}, []);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MySQL] Port 충돌 문제 해결]]></title>
            <link>https://velog.io/@mong-head/MySQL-Port-%EC%B6%A9%EB%8F%8C-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@mong-head/MySQL-Port-%EC%B6%A9%EB%8F%8C-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Sun, 15 Aug 2021 08:25:04 GMT</pubDate>
            <description><![CDATA[<h3 id="환경">환경</h3>
<ul>
<li>windows 10<h3 id="문제">문제</h3>
MySQL Workbench에서 3306 포트로 접속한 DB와 Node에서 개발하기 위해 Sequelize에서 3306 포트로 접속한 DB의 내용이 다른 것을 보고 MySQL이 2개가 깔려있고, 포트가 서로 충돌이 일어나서 일정하지 않게 프로그램에 따라 다른 DB로 연결되는 것을 알게 되었습니다. </li>
</ul>
<p>문제를 확인 하기 위해 작업 관리자를 틀어보니 실제로 예전에 깔았던 bitnami에서 함께 깔았던 MySQL과 Oracle에서 깐 MySQL이 함께 있는 것을 볼 수 있었습니다.</p>
<ul>
<li>작업 관리자 화면
<img src="https://images.velog.io/images/mong-head/post/770a38de-a8ec-4138-9ff9-4f75ef24923e/K-065.jpg" alt=""><ul>
<li>mysqld가 두 개가 있는 것을 볼 수 있습니다.</li>
<li>하나는 bitnami를 통해 깐 MySQL이고, 다른 하나는 일반적으로 MySQL을 설치하는 방법인 Oracle 통한 MySQL 설치로 만들어진 MySQL server입니다.</li>
</ul>
</li>
</ul>
<h3 id="해결">해결</h3>
<p>저는 제가 관리하기 쉬운 MySQL의 포트를 변경하기로 하였습니다. 따라서, 예전에 사용했던 bitnami말고 현재 사용하는 Oracle 홈페이지에서 설치한 MySQL의 포트를 변경합니다. </p>
<p>DB의 설정파일은 my.ini파일에 있습니다. 따라서 윈도우 cmd창에서 my.ini파일을 찾아주었습니다. <code>C:\</code>경로에서 <code>dir /s my.ini</code>를 하시면 my.ini파일이 있는 것을 보실 수 있습니다.
<img src="https://images.velog.io/images/mong-head/post/b87e9f48-a39a-4d4e-a6f1-7aa84a0b2983/K-064.jpg" alt=""></p>
<p>전 여기에서 MySQL Server 8.0에 있는 my.ini파일의 포트를 변경해줄 것이기에 해당 경로 (<code>C:\ProgramData\MySQL\MySQL Server 8.0\my.ini</code>)의 my.ini파일을 틀고 port번호를 3306에서 3307로 변경해주었습니다. 두 군데에 있으니 두 군데 모두 변경해주시면 됩니다.</p>
<table>
<thead>
<tr>
<th align="center">변경 전</th>
<th align="center">변경 후</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><img src="https://images.velog.io/images/mong-head/post/f7d8d57b-f552-4648-944a-d6eceeb7fff0/K-066.jpg" alt=""></td>
<td align="center"><img src="https://images.velog.io/images/mong-head/post/b7d5d07e-a362-49f4-bdf9-7ae4d2d58be9/K-067.jpg" alt=""></td>
</tr>
</tbody></table>
<p>그 이후, 변경한 MySQL의 서비스를 중지한 후, 다시 실행해야 합니다. 윈도우 버튼을 눌러 &quot;서비스&quot;를 검색하셔서 어플을 실행시켜주신 후, MySQL80의 서비스를 중지한 후 다시 실행을 하시면 됩니다.
<img src="https://images.velog.io/images/mong-head/post/bf2226b2-6056-4aa7-ba24-2a75019113c3/K-064.jpg" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Node] Sequelize : foreign key 설정]]></title>
            <link>https://velog.io/@mong-head/Node-Sequelize-foreign-key-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@mong-head/Node-Sequelize-foreign-key-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Sat, 14 Aug 2021 08:16:14 GMT</pubDate>
            <description><![CDATA[<p>Sequelize에서 foreign key를 설정하는 방법은 밑과 같습니다.</p>
<p>예를 들어, participant, chat table이 있을 때, participant : chat 의 관계가 1 : N 이라 가정하겠습니다. chat table은 participant의 primary key인 no를 participantNo라는 foreign key를 가집니다. 
<img src="https://images.velog.io/images/mong-head/post/01df71eb-90d8-47c8-9da6-e902d53fb224/K-063.jpg" alt=""></p>
<p>파일에 대해 설명드리자면, models라는 폴더 내에 index.js, Chat.js, Participant.js가 존재합니다.
Chat.js, Participant.js는 sequelize.define 함수로chat, participant table을 정의하는 파일이고, index.js는 sequelize 생성(DB연결) 및 Chat과 Participant등등 table들의 관계( relation)를 명시하는 파일입니다.</p>
<p>이때, chat sequelize define에는 foreign key를 명시하지 않고, index.js에서 chat과 participant의 관계를 명시하면 됩니다. 즉, 밑처럼 관계를 index.js에서 밑 부분만 추가하시면 됩니다.</p>
<blockquote>
<p>models/index.js</p>
</blockquote>
<pre><code class="language-js">...
Participant.hasMany(Chat, {
    foreignKey: &#39;participantNo&#39;,
    allowNull: false,
    constraints: true,
    onDelete: &#39;cascade&#39;
});
Chat.belongsTo(Participant, {
    foreignKey: &#39;participantNo&#39;
});
...</code></pre>
<p>밑은 전체 코드입니다.</p>
<blockquote>
<p>models/index.js</p>
</blockquote>
<pre><code class="language-js">const { Sequelize, DataTypes } = require(&#39;sequelize&#39;);

const sequelize = new Sequelize(
    process.env.DB_NAME,
    process.env.DB_USER,
    process.env.DB_PASSWORD,{
        host: process.env.DB_HOST,
        port: process.env.DB_PORT,
        timezone: &quot;+09:00&quot;,
        dialect: &#39;mysql&#39;
    }
);

const Chat = require(&#39;./Chat&#39;)(sequelize);
const Participant = require(&#39;./Participant&#39;)(sequelize);

Participant.hasMany(Chat, {
    foreignKey: &#39;participantNo&#39;,
    allowNull: false,
    constraints: true,
    onDelete: &#39;cascade&#39;
});
Chat.belongsTo(Participant, {
    foreignKey: &#39;participantNo&#39;
});

Chat.sync({
    force: process.env.TABLE_CREATE_ALWAYS === &#39;true&#39;, // true : (drop) table 데이터 없어질 수 있음
    alter: process.env.TABLE_ALTER_SYNC === &#39;true&#39;     // 개발 끝나면 false로 하기
})
Participant.sync({
    force: process.env.TABLE_CREATE_ALWAYS === &#39;true&#39;, // true : (drop) table 데이터 없어질 수 있음
    alter: process.env.TABLE_ALTER_SYNC === &#39;true&#39;     // 개발 끝나면 false로 하기
})

module.exports = {sequelize, Chat, Participant};</code></pre>
<blockquote>
<p>models/Participant.js</p>
</blockquote>
<pre><code class="language-js">const { Sequelize, DataTypes } = require(&#39;sequelize&#39;);
const models = require(&#39;../models&#39;);

module.exports = function(sequelize){
    // foreign Key : (Room)room_no, (User)user_no
    const participant = sequelize.define(&#39;Participant&#39;, {
        no: {
            field: &#39;no&#39;,
            type: DataTypes.INTEGER,
            primaryKey: true,
            autoIncrement: true,
            allowNull: false
        },
        role: {
            field: &#39;role&#39;,
            type: DataTypes.STRING(45),
            allowNull: false
        },
        status: {
            field: &#39;status&#39;,
            type: DataTypes.ENUM(&#39;true&#39;, &#39;false&#39;) ,
            allowNull: false
        },
        createdAt: {
            field: &#39;createdAt&#39;,
            type: DataTypes.DATE,
            allowNull: false
        },
        lastReadAt: {
            field: &#39;lastReadAt&#39;,
            type: DataTypes.DATE,
            allowNull: false
        }
    }, {
        underscored: false, // updateAt -&gt; updateAt (underscored: update_at)
        freezeTableName: true,
        timestamps: true,
        createdAt: false,
        updatedAt: false,
        tableName: &#39;participant&#39;
    });
    return participant;
}</code></pre>
<blockquote>
<p>models/chat.js</p>
</blockquote>
<pre><code class="language-js">const { Sequelize, DataTypes } = require(&#39;sequelize&#39;);

module.exports = function(sequelize){
    // foreign Key : (Participant)participant_no
    return sequelize.define(&#39;Chat&#39;, {
        no: {
            field: &#39;no&#39;,
            type: DataTypes.INTEGER,
            primaryKey: true,
            autoIncrement: true,
            allowNull: false
        },
        type: {
            field: &#39;type&#39;,
            type: DataTypes.STRING(45),
            allowNull: false
        },
        createdAt: {
            field: &#39;createdAt&#39;,
            type: DataTypes.DATE,
            allowNull: false
        },
        contents: {
            field: &#39;contents&#39;,
            type: DataTypes.TEXT,
            allowNull: false
        },
        read: {
            field: &#39;read&#39;,
            type: DataTypes.INTEGER,
            allowNull: false
        }
    }, {
        underscored: false, // updateAt -&gt; updateAt (underscored: update_at)
        freezeTableName: true,
        timestamps: true,
        createdAt: false,
        updatedAt: false,
        tableName: &#39;chat&#39;
    });
}</code></pre>
<h3 id="결과">결과</h3>
<p>서버를 실행시키셨을 때, 밑처럼 실행된다면 성공입니다.</p>
<pre><code class="language-shell">Executing (default): CREATE TABLE IF NOT EXISTS `chat` (`no` INTEGER NOT NULL auto_increment , `type` VARCHAR(45) NOT NULL, `createdAt` DA
TETIME NOT NULL, `contents` TEXT NOT NULL, `read` INTEGER NOT NULL, `participantNo` INTEGER, PRIMARY KEY (`no`), FOREIGN KEY (`participant
No`) REFERENCES `participant` (`no`) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB;

Executing (default): CREATE TABLE IF NOT EXISTS `participant` (`no` INTEGER NOT NULL auto_increment , `role` VARCHAR(45) NOT NULL, `status
` ENUM(&#39;true&#39;, &#39;false&#39;) NOT NULL, `createdAt` DATETIME NOT NULL, `lastReadAt` DATETIME NOT NULL, `roomNo` INTEGER, `userNo` INTEGER, PRIMA
RY KEY (`no`), FOREIGN KEY (`roomNo`) REFERENCES `room` (`no`) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (`userNo`) REFERENCES `use
r` (`no`) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB;</code></pre>
]]></description>
        </item>
    </channel>
</rss>