우분투 간단한 온도 체크는 lm-sensors를, GUI를 통한 그래픽 모니터링 화면은 xsensors를 사용하여 확인할 수 있습니다.

 

alt + ctrl + t 단축키로 대충 터미널창을 열어줍니다

 

lm-sensors 설치

sudo apt install lm-sensors

 

 

센서 탐색

sudo sensors-detect

탐색중 yes를 입력하여 탐색을 진행

 

sensors를 실행하여 온도 확인 (watch sensors를 입력하면  실시간 모니터링)

sensors

watch sensors

 

 

 

GUI 모니터링

우분투 GUI를 사용한 온도 모니터링은 xsensors를 사용하여 확인할 수 있습니다.

 

xsensors 설치

sudo apt install xsensors

 

xsensors를 실행하여 온도 모니터링

xsensors

 

 

모듈 삭제

sudo apt remove 모듈명

유니티 외부에서 다운받은 FBX 파일과 여러 Light들을 배치하고, 라이트맵 굽기를 진행하였다.

GPU를 사용하여 라이트맵을 생성하였다.

그런데 이게 무슨일인가.

그림자가 이상하게 구워진다.

해결 내용

해당 오브젝트의 FBX 파일을 선택하여 Model의 Generate Lightmap UVs를 체크해주고

 

해당 오브젝트의 질감을 표현하는 Material들의 Double Sided Global Illumination 옵션을 체크하고, 다시 구웠다.

(Double Sided Global Illumination 옵션은 라이트맵 굽기의 Progressive 에서만 동작한다)

Window > Rendering > Lighting
문제의 오브젝트에 적용된 Material

 

다시 라이트맵을 굽고 정상적으로 작동하는것을 확인

라이트맵의 그림자 뭉개짐이 없어지고,

정상적으로 라이트맵의 그림자가 구워지는 것을 확인하였다.

한 화면에 Light 를 많이 배치하고 씬을 보면

일부 라이트만 동작하는것 같고, 나머지 라이트 효과가 재대로 동작하지 않는 경우가 있다.

 

Light들을 선택하여 Render Mode를 Auto에서 Important로 변경하면 모든 불빛이 표현된다.

 

Render Mode를 Important로 변경후 모든 불빛이 표현되는것을 볼 수 있다.

선언 및 초기화

//선언후, 초기화 방법
let dict1 = {}
dict1["apple"] = "사과";
dict1.orange = "오렌지";
console.log(dict1);

//변수 선언후, 변수명,값 으로 초기화 방법
let country = "한국";
let city = "서울";
let dict2 = {country, city};
console.log(dict2);

//생성 시 초기화 방법
let dict3 = {"apple":"사과", "orange":"오렌지"};
console.log(dict3);

결과물은 아래와 같음

 

키 사용

//딕셔너리 추가 및 데이터 활용
let dict = {"apple":"사과", "orange":"오렌지"};
dict.banana = "바나나";		//"banana" 추가
dict["melon"] = "메론";		//"melon" 추가

console.log(dict);			//딕셔너리 전체 출력
console.log(dict.apple);	//dict의 apple 참조
console.log(dict["melon"]);		//dict의 melon 참조
console.log(Object.keys(dict));		// 키 값 전부 출력
console.log(Object.keys(dict)[2]);		//키 값 배열 참조

결과물은 아래과 같이 해당 키의 값이 출력됨

 

키 분해하기 (변수에 저장)

기본 분해, 다른 이름의 변수에 분해

let dictionary = {name:"Tom", "age":28, "country":"Korea"}  //키값은 ""으로 감싸지 않아도됨

// 기본적인 키 분해 (변수에 저장)
let {name, age} = dictionary;     //변수 name, age 생성하며, dictionary의 name, age 값을 저장함
console.log(name);      //"Tom" 출력,  dictionary의 name값
console.log(age);       //28 출력,  dictionary의 age값

// 다른이름으로 키 분해  (다른이름의 변수에 저장)
let {country:nationality} = dictionary;      //다른이름(nationality)으로 dictionary의 country값 저장
console.log(nationality);       //"Korea 출력,  dictionary의 country값

결과

기본값 지정 분해(없을경우 생성)

// 지정값 키 분해 (존재하지 않으면 지정값을 변수에 저장)
let dictionary = {name:"Tom", "age":28, "country":"Korea"}  //키값은 ""으로 감싸지 않아도됨

let {name = "James", gender = "남성"} = dictionary;     //변수 name, gender 생성하며, dictionary의 name, gender 값을 저장함, 단 없을경우 지정된 값으로 초기화
console.log(name);      //"Tom" 출력,  dictionary의 name값 (name 키값이 없는경우 James로 대체)
console.log(gender);       //남성 출력,  지정된 초기값 "남성" 출력  (dictionary에 존재하지 않는 키, 지정값으로 초기화됨)

결과

나머지 분해(지정하지 않은 나머지도 생성)

// 나머지 키 분해 (나머지도 변수에 저장)
let dictionary = {name:"Tom", "age":28, "country":"Korea"}  //키값은 ""으로 감싸지 않아도됨

let {name, ...others} = dictionary;     //변수 name,others 생성하며, others에는 name을 제외한 dictionary가 저장됨
console.log(name);      //"Tom" 출력,  dictionary의 name값
console.log(others);       //{"age":28, "country":"Korea"}출력,  dictionary의 name을 제외한 나머지값 출력

결과

 

키 체크

let dict = {"apple":"사과", "orange":"오렌지"};

//키 체크 ("키값" in 사전변수)
console.log("tiger" in dict); // false 존재하지 않음
console.log("Apple" in dict); // false 대소문자 구분
console.log("apple" in dict); // True

 

Dictionary 길이 확인, length

// Object.keys(사전).length 형태로 사용하면 길이가 반환됨

// key 값이 같은경우
let data1 = {"Name" : "Jh", "Name":"TOM", "Name":"sue"}

console.log(Object.keys(data1).length);		//길이 1 반환됨 (key값이 Name으로 동일하여 덮어씌워짐)
console.log(data1.Name);    //console.log(data1["Name"]);		//마지막에 입력된 "sue"가 출력됨


// 일반적인 사용
let data2 = {"Banana" : "바나나", "Tiger":"호랑이", "country":"국가"}

console.log(Object.keys(data2).length);		//길이 3(키 3개)이 반환됨


// 딕셔너리 배열 사용할때
let data3 = [{"Name" : "TOM", "Age" : 24}, {"Name":"Jake", "Age":25}, {'Name':"John", "Age":23}, {'Name':"James", "Age":18}];

console.log(Object.keys(data3));		//['0', '1', '2', '3'] 배열 인덱스가 출력됨
console.log(Object.keys(data3[0]));			//['Name', 'Age'] 0번 인덱스의 키가 반환됨
console.log(Object.keys(data3).length);		//4 사전 배열의 길이가 반환됨
console.log(Object.keys(data3[0]).length);		//2 0번 인덱스 사전의 키 길이가 반환됨
console.log(data3.length);			//4 배열의 길이가 반환됨

Object.keys(사전).length 형태로 키 값의 길이를 확인하는 형식

위 코드의 결과는 아래와 같음

 

유니티 웹상에 띄우기는 이전글로 확인해주세요

이전 글을 참고해 주세요

[Node.js] 유니티 WebGL 웹에서 유니티 띄우기 :: 에러 로그 (tistory.com)

 

[Node.js] 유니티 WebGL 웹에서 유니티 띄우기

유니티 WebGL 빌드 유니티 상단에 File 메뉴에서 Build Setting을 눌러줍니다 Build Setting에서 WebGL을 누르고 변경해줍니다 이후 Build를 눌러 프로젝트를 빌드해줍니다. 웹(node.js) 적용 설명은 node.js..

wls3189.tistory.com

 

유니티 프로젝트를 만들고, C# 스크립트 생성

프로젝트 생성 후, C#스크립트를 한개 생성해줍니다.

한글 폰트 지정 및 스크립트 장착

텍스트 오브젝트를 선택하여 Font를 지정해줍니다. (무료 폰트 인터넷에 많이 있으니 한글 폰트를 지정해줍시다.)

- 한글 폰트 미지정 시 WebGL에서 한글이 안나옵니다. (유니티 자체에서는 한글이 있는 폰트를 자동으로 선택해서 보여줘서 보인다고 함)

 

작성한 스크립트를 오브젝트에 붙여줍니다 (저는 "Sphere" 오브젝트에 붙였습니다. 스크립트로 캔버스의 UI Text를 끌어서 지정해주었습니다.)

 

이전 글을 참고하여 유니티 프로젝트를 Build 하고, 생성된 파일을 웹 프로젝트에 포함시킵니다.

[Node.js] 유니티 WebGL 웹에서 유니티 띄우기 :: 에러 로그 (tistory.com)

 

[Node.js] 유니티 WebGL 웹에서 유니티 띄우기

유니티 WebGL 빌드 유니티 상단에 File 메뉴에서 Build Setting을 눌러줍니다 Build Setting에서 WebGL을 누르고 변경해줍니다 이후 Build를 눌러 프로젝트를 빌드해줍니다. 웹(node.js) 적용 설명은 node.js..

wls3189.tistory.com

 

웹에서 유니티에 데이터 전달하기

전체 index.html 코드

우선 유니티 빌드를 통해서 생성된 index.html 파일을 수정한 전체 index.html 코드

- 그대로 가져다 쓰면 정상 동작 하지 않습니다.

<!DOCTYPE html>
<html lang="en-us">
<head>
  <meta charset="utf-8">
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Unity WebGL Player | WebGL_Test</title>
  <link rel="shortcut icon" href="TemplateData/favicon.ico">
  <link rel="stylesheet" href="TemplateData/style.css">
  <script src="TemplateData/UnityProgress.js"></script>
  <script src="Build/UnityLoader.js"></script>
  <script>
    var gameInstance = UnityLoader.instantiate("gameContainer", "Build/TestApp.json", {onProgress: UnityProgress});
  </script>
</head>
<body>
<div class="webgl-content">
  <div id="gameContainer" style="width: 960px; height: 600px"></div>
  <div class="footer">
    <div class="webgl-logo"></div>
    <div class="fullscreen" onclick="gameInstance.SetFullscreen(1)"></div>
    <div class="title">WebGL_Test</div>
  </div>
</div>

<div id="btn1" onclick="btn1()">버튼1</div>
<div id="btn2" onclick="btn2()">버튼2</div>
</body>

<script>
  function btn1(){
    gameInstance.SendMessage("Sphere", "setText1", 77.7);
  }
  function btn2(){
    dataSet = {data1: "데이터1", data2: "데이터2"}
    gameInstance.SendMessage("Sphere", "setText2", JSON.stringify(dataSet));
  }
</script>

</html>

 

순차적 적용 내용-----

생성된 index.html 파일중 gameInstance 를 통해 SendMessage 함수로 유니티로 데이터를 전달하게 됩니다.

 

모바일 포함된 경우에는 index.html 파일이 아래와 같이 모양이 약간 다릅니다.

생성된 파일중 index.html 파일의 하단 script 태그 내부에 unityInstance 를 통해 데이터를 유니티로 전달할 수 있게 됩니다.

다른 위치에서 사용하기 위해 gameInstance 변수에 담았습니다.

 

gameInstance.SendMessage("물체이름", "함수이름", 데이터)

물체 이름은 유니티 내 오브젝트의 이름이고, 함수이름은 C#스크립트에 작성한 함수의 이름이고, 데이터는 함수에 정의된 매개변수 타입으로 전송하시면 됩니다. (배열은 전송 불가능 >> 데이터 여러개 보낼때는 최하단 내용 참고)

 

웹 서버를 실행시키고 접속합니다.

웹 상의 버튼1, 버튼2를 누르면 TextUI의 값이 변경됩니다.

버튼 1 누름

 

여러개의 데이터를 보낼때

LitJson.dll 파일을 다운받아 유니티 프로젝트 내 Plugins 폴더에 넣어둡니다.

 

유니티의 C#스크립트에서 먼저 제이슨 데이터를 받을수 있도록 변경합니다.

using LitJson으로 Plugins 폴더의 LitJson을 불러옵니다.

setText2(string) 함수를 선언하며 제이슨 문자열을 받아 처리하는 함수를 만들어줍니다.

LitJson 라이브러리의 JsonData 객체를 생성하여 JsonMapper.ToObject 함수를 사용하여 받아온 Json문자열을 변환합니다.

 

이후 데이터는 jsonPlayer 변수에 담겨서, jsonPlayer["데이터 명"]; 형식으로 사용합니다.

문자열로 간단히 변환하기 위해 "" 문자열 + jsonPlayer["data1"]; 형식으로 사용하였습니다.

 

다시 유니티 프로젝트 빌드하여 웹 서버에 포함시킵니다.

유니티의 전체 C# 스크립트 소스

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using LitJson;

public class Web_controller : MonoBehaviour
{
    public Text text1;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    public void setText1(double value)
    {
        text1.text = "데이터 한개 : " + value + "입니다";
    }

    public void setText2(string jsonString)
    {
        JsonData jsonPlayer = JsonMapper.ToObject(jsonString);

        string text_val1 = "" + jsonPlayer["data1"];
        string text_val2 = "" + jsonPlayer["data2"];

        text1.text = "data1 : " + text_val1 + "\n"
                    + "data2 : " + text_val2;

        //text1.text = "data1 : " + jsonPlayer["data1"] + "\n" + "data2 : " + jsonPlayer["data2"];
    }

}

 

웹 서버로 돌아와서 index.html 파일에 btn2() 함수를 추가해줍니다

데이터(dataSet)를 Dictionary 형태로 만들어 줍니다

해당 데이터는 버튼2를 눌렀을때 SendMessage 함수를 통해 JSON.stringify() 함수를 사용하여 문자열로 변환시켜 전송됩니다.

웹서버를 실행시키고 접속하여, 버튼 2를 누르면 전송한 {data1: "데이터1", data2: "데이터2"}가 유니티의 Json 문자열로 받아서 처리됐습니다.

버튼 2 누름

 

 

 

유니티 WebGL 빌드 

유니티 상단에 File 메뉴에서 Build Setting을 눌러줍니다

Build Setting에서 WebGL을 누르고 변경해줍니다

이후 Build를 눌러 프로젝트를 빌드해줍니다.

 

웹(node.js) 적용

설명은 node.js express 서버를 기반으로 작성하겠습니다.

프로젝트 빌드 후 생성된 파일을 웹 서버에 포함시킵니다.

index.html 파일을 열어서 추가한 파일의 경로를 알맞게 지정해줍니다

모바일이 포함된경우 아래 처럼 스크립트를 통해 경로 지정이 따로됨

 

이제 다른 뷰 페이지를 생성해서 해당 페이지를 붙이고 싶은 위치에 붙였습니다

 

그리고 서버를 실행 시키고 접속을 하면 페이지가 화면에 출력됩니다.

 

 

 

무한로딩 발생 시 처리방법

유니티 프로젝트를 빌드 하실때 파일이 압축되는데, 압축파일이 재대로 동작하지 않아 무한 로딩화면만 뜨는경우가 있습니다

유니티 Build Setting >> Player Setting... 누릅니다.

Player Setting 창에서 webgl 로고를 누르고 Publishing Settings의 Compression Format을 Disable로 변경합니다

 

이후 위의 빌드 >> 적용 단계를 다시 진행하시면, 무한로딩이 해결됩니다.

conf파일을 수정하여 오래 걸린 쿼리를 찾기 위해 기록 남기기 설정

저의 경우 Centos 7을 활용하고 있으며, PostgreSQL 설정 파일은 PostgreSQL 설치 위치에 존재 (제 경우엔 /var/lib/pgsql/9.6/data에 postgresql.conf 파일이 있습니다)

해당 파일을 vi편집기 또는 텍스트 편집기를 이용하여 'log_min_duration_statement'의 값을 설정해줍니다 (저는 7초 이상 걸린 쿼리의 로그를 찍겠습니다)

 - log_min_duration_statement 앞에 '#' 이 붙어있으면 지워주세요.

log_min_duration_statement = [시간(ms)]

 

변경이 끝났으면 pg의 설정값을 재로딩 해야합니다.

해당 SQL문을 사용하여 서버 재가동 없이 로딩이 가능합니다

SELECT pg_reload_conf();

 - conf파일의 일부 설정은 서버 재가동이 필요하며, reload 만으로는 적용되지 않는 설정도 있습니다.

 

설정 및 리로드가 완료되고, 슬로우 쿼리가 발생하면 로그 파일에 기록되며, pg가 설치된 폴더 (제 경우엔 /var/lib/pgsql/9.6/data/pg_log)에서 로그 파일을 확인할 수 있습니다.

요일별로 로그가 분리되어 있고, 설정시간 이상의 슬로우 쿼리가 발생하였던 제 서버에는 로그가 남아있습니다.

해당 쿼리가 무엇 때문에 오래 걸렸는지, 확인 후 조치하여 현재 제 서버의 문제점은 해결되었습니다.

작은 도움이라도 되셨길 바랍니다.

락 상태 확인

--락 상태 확인
SELECT relation :: regclass, mode, granted, pid, * FROM pg_locks;


-- 실행중인 쿼리 확인
SELECT * FROM pg_stat_activity ORDER BY query_start ASC;

-- 활동중인 쿼리만 확인 ('1 sec'를 적어 1초가 지난 'active' 상태인 쿼리 확인)
SELECT current_timestamp - query_start AS runtime, datname, usename, pid, query
FROM pg_stat_activity
WHERE state = 'active' AND current_timestamp - query_start > '1 sec'
ORDER BY 1 DESC

granted가 True 면 락이 허가되어 실행중

락 걸린 쿼리 중지

-- 해당 쿼리만 중지 (PID를 매개변수로 적어주면됨)
SELECT pg_cancel_backend(3209);


-- 위의 명령으로 잠금이 풀리지 않을때, 상위 명령까지 전부 종료
SELECT pg_terminate_backend(3209) FROM pg_stat_activity;

 

락 종류

  • 크게 Exclusive Lock 과 Shared Lock으로 나눌수 있음
  • Shared Lock은 읽기 잠금(read lock)이라고도 하며, 데이터를 동시에 읽을수 있게 허용하지만, 변경은 불가능한 상태 (Shared Lock이 한개라도 걸려있으면 Exclusive Lock을 걸수 없음)
  • Exclusive Lock은 쓰기 잠금(write Lock)이라고도 하며, 해당 락을 건 트랜잭션이 완료 될때까지 테이블, 혹은 레코드를 다른 트랜잭션에서 읽거나 쓰지 못함  
------------------------------------------
  • ACCESS SHARE – SELECT 명령은 쿼리에서 참조된 테이블에서 이 잠금을 획득, 일반적인 규칙은 테이블을 읽기만 하는 모든 쿼리가 이 잠금을 획득합니다.
  • ROW SHARE – SELECT FOR UPDATE 및 SELECT FOR SHARE 명령은 대상 테이블에서 이 잠금을 획득합니다(쿼리에서 참조된 모든 테이블에 대한 ACCESS SHARE 잠금).
  • ROW EXCLUSIVE – UPDATE, INSERT 및 DELETE 명령은 대상 테이블에 대한 이 잠금을 획득합니다(쿼리에서 참조된 모든 테이블에 대한 ACCESS SHARE 잠금). 일반적인 규칙은 테이블을 수정하는 모든 쿼리가 이 잠금을 획득한다는 것입니다.
  • SHARE UPDATE EXCLUSIVE – VACUUM(FULL 제외), ANALYZE, CREATE INDEX CONCURRENTLY 및 일부 형태의 ALTER TABLE 명령은 이 잠금을 획득합니다.
  • SHARE – CREATE INDEX 명령은 쿼리에서 참조하는 테이블에 대한 잠금을 획득합니다.
  • SHARE ROW EXCLUSIVE – 어떤 명령으로도 암시적으로 획득되지 않습니다.
  • EXCLUSIVE – 이 잠금 모드에서는 이 잠금을 획득한 트랜잭션과 병렬로 읽기만 처리할 수 있습니다. 명령에 의해 암시적으로 획득되지 않습니다.
  • ACCESS EXCLUSIVE – ALTER TABLE, DROP TABLE, TRUNCATE, REINDEX, CLUSTER 및 VACUUM FULL 명령은 쿼리에서 참조하는 테이블에 대한 잠금을 획득합니다. 이 모드는 LOCK 명령의 기본 모드입니다.
  • 참고 사이트 : https://engineering.nordeus.com/postgres-locking-revealed/

 

 

사설 - Index 수정중 락으로 인해 발생한 문제...

더보기

최근 인덱스에 문제가 있어 Drop index 또는 Reindex index 를 통해 인덱스를 수정하려던 중 작동하지 않아 명령을 취소하였더니, 해당 테이블이 먹통이 돼버렸음 (원래 20ms 면 나오던 데이터가 10000ms를 넘겨서 나오는 현상이...)

 

해서 인덱스 상태를 확인한 결과 해당 테이블의 인덱스가 동작하지 않고있었음 (새로 추가되는 데이터만 인덱스 fetch되고 있었음)

-- Index 확인 쿼리
SELECT
    schemaname AS schema_name,
    relname AS table_name,
    indexrelname AS index_name,
    pg_size_pretty(pg_relation_size(indexrelid::regclass)) AS index_size,
    idx_scan,
    idx_tup_read,
    idx_tup_fetch
FROM pg_stat_user_indexes
ORDER BY idx_scan ASC;

그래서 reindex 명령으로 인덱스를 살리려고 노력하는데 명령이 몇시간이 지나도 끝나지 않았음,

SELECT relation :: regclass, mode, granted, pid, * FROM pg_locks

확인해보니 granted가 막혀있었음, 다른 트랜잭션에서 이미 락을 걸고 사용중이었음, 사이트에 데이터가 너무 느리게 뜨자, 여기저기서 전화가;;;

급한대로 빨리 reindex를 해서 인덱스를 살려야 해서, 해당 relation과 관련된 락을 건 pid를 중지 시켰음

SELECT pg_cancel_backend(5957);

-- 위의 명령으로 중지해서는 먹히지 않아 아래껄로 중지함
SELECT pg_terminate_backend(5957) FROM pg_stat_activity;

첫번째 명령으로 처리가 안되어, 급한대로 아래의 pg_terminate_backend를 사용하여 상위 프로세스 까지 중지시켰음

그러자 락이 성공적으로 걸리면서 작업을 마무리 할수 있었음

2시간 기다리던 reindex.... 락이 풀리자 몇초만에 끝나...

인덱스 용량만 610Mb를 넘겨서 오래걸리는줄 알았던 작업이... 락이 풀리자 몇 초만에 끝나버렸다...

전화는 계속오고, 실행 중인줄 알았던 쿼리는 2시간이 넘도록 동작 안하고 있었고... 뻘짓하다 글 쓰게 됨...

 

전체 쿼리 동작 상태 보는 쿼리

SELECT * FROM pg_stat_activity ORDER BY query_start ASC;

 

동작 상태인 쿼리중 오래 걸리는 쿼리 확인

SELECT current_timestamp - query_start AS runtime, datname, usename, pid, query
FROM pg_stat_activity
WHERE state = 'active' AND current_timestamp - query_start > '1 sec'
ORDER BY 1 DESC

13분이나 처리를 못하고 말썽 피우는 쿼리

 

쿼리 중지시키기

--프로세스 ID값을 이용한 정지
SELECT pg_cancel_backend('PID');
--상위 프로세스 까지 정지
SELECT pg_terminate_backend('PID') FROM pg_stat_activity;

--저의 경우엔 PID가 23858
SELECT pg_cancel_backend(23858);

 

select를 통해 가져온 데이터를 가지고 insert하는 기본 문법

INSERT INTO 저장될테이블이름 SELECT * FROM 불러올테이블이름

 

일부 컬럼만 지정하여 insert하는 방법

INSERT INTO 저장할테이블이름 (컬럼명1, 컬럼명2, 컬럼명3)
    SELECT 컬럼명A, 컬럼명B, 컬럼명C FROM 불러올테이블이름

 

 

기본 INSERT 방법

-- 테이블에 존재하는 컬럼 갯수만큼 데이터를 지정해준경우
INSERT INTO 테이블명 VALUES(데이터A, 데이터B, 데이터C)


-- 일부 컬럼만 지정하여 값을 넣는 경우
INSERT INTO 테이블명 (컬럼명1, 컬럼명2,...) VALUES (데이터A, 데이터B,...)


-- 여러개의 튜플을 한번에 추가하는 경우
INSERT INTO 테이블명 (컬럼명1, 컬럼명2,...) VALUES
(데이터A, 데이터B, 데이터C,....),
(데이터K, 데이터L, 데이터M,....),
			.
            .
            .
            .
(데이터1, 데이터2, 데이터3,....);



-- SELECT를 통해 추가하는경우
INSERT INTO 테이블명A (컬럼명1, 컬럼명2, 컬럼명3, 컬럼명4,....)
    SELECT *(또는 컬럼명시) FROM 테이블명B WHERE 조건

 

+ Recent posts