2016년 12월 14일 수요일

브라우저 종류를 판단해주는 자바스크립트 함수

- 프로젝트를 진행할때 보면 ie7,8이 크로스브라우징이 안되어서 골치 아플때가 많다..
- Detectizr.js를 사용해서 해결해도 되지만 Detectizr.js는 modernizr.js가 있어야 작동되므로..
- 간단히 ie만 체크해야  할땐 아래 함수를 사용해서 해결하면 도움이 된다.
- 사용법은 출처 및 아래 첨부파일 다운






<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<script>
function checkBrowser(){ // 외부 라이브러리와 충돌을 막고자 모듈화.
    // 브라우저 및 버전을 구하기 위한 변수들.
    'use strict';
    var agent = navigator.userAgent.toLowerCase(),
        name = navigator.appName,
        browser;
    
    // MS 계열 브라우저를 구분하기 위함.
    if(name === 'Microsoft Internet Explorer' || agent.indexOf('trident') > -1 || agent.indexOf('edge/') > -1) {
        browser = 'ie';
        if(name === 'Microsoft Internet Explorer') { // IE old version (IE 10 or Lower)
            agent = /msie ([0-9]{1,}[\.0-9]{0,})/.exec(agent);
            browser += parseInt(agent[1]);
        } else { // IE 11+
            if(agent.indexOf('trident') > -1) { // IE 11 
                browser += 11;
            } else if(agent.indexOf('edge/') > -1) { // Edge
                browser = 'edge';
            }
        }
    } else if(agent.indexOf('safari') > -1) { // Chrome or Safari
        if(agent.indexOf('opr') > -1) { // Opera
            browser = 'opera';
        } else if(agent.indexOf('chrome') > -1) { // Chrome
            browser = 'chrome';
        } else { // Safari
            browser = 'safari';
        }
    } else if(agent.indexOf('firefox') > -1) { // Firefox
        browser = 'firefox';
    }

    // IE: ie7~ie11, Edge: edge, Chrome: chrome, Firefox: firefox, Safari: safari, Opera: opera
    document.getElementsByTagName('html')[0].className = browser;
    document.getElementById("browser_div").innerHTML = "브라우저 타입 : " + browser;
}
</script>
</head>
<body>
<input type="button" onClick="checkBrowser()" value="확인"/>
<br /><div id="browser_div"></div>
</body>
</html>

[출처] http://micropilot.tistory.com/category/Javascript?page=76

Javascript static function example

Javascript static 함수/변수 선언 예


<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Javascript static function demo</title>
<script type="text/javascript">
function Vector2D(x,y) {
     
    this.x = x;
    this.y = y;
     
    // 인스턴스 함수 선언
    this.add =  function(v2d){
        var x = this.x + v2d.x;
        var y = this.y + v2d.y;
        return new Vector2D(x,y);
    }
};
 
// static 변수선언
Vector2D.len = 0;
 
// static 함수 선언
Vector2D.add = function(v1,v2) {
    //alert(this.x); // this.x 를 인식하지 못함
    return new Vector2D(v1.x+v2.x, v1.y+v2.y);
}
 
// 인스턴스 함수 추가선언
Vector2D.prototype.length = function() {
    return Math.sqrt(this.x*this.x + this.y*this.y);
}
 
// 인스턴스 변수 추가선언
Vector2D.prototype.name = 'MyName'; // 이미 생성된 인스턴스에도 포함됨
 
<!-- var v2d = new Vector2D(3,4); -->
var tmp = new Vector2D(1,2);
var resultVec = v2d.add(tmp); // 인스턴스 함수호출
//console.log(resultVec.x);
 
var vec = Vector2D.add(v2d,tmp); // static 함수호출
 
console.log('v2d.length():'+v2d.length()); // 인스턴스 함수호출
console.log('Vector2D.len:'+Vector2D.len); // static 변수사용
 
</script>
</head>
<body>
 
</body>
</html>


2016년 12월 12일 월요일

자바스크립트 eval() 함수를 이용하여 문자열로 표현된 식이나 함수 실행하기

var str = '10 + 20' ;
var ans = eval ( str ); // 문자열을 표현식으로 해석하여 실행하면 위의 산술식이 실행되므로 30을 리턴한다

다음과 같이 함수(익명함수 포함)를 선언하고 즉시 호출하기 위한 코드는 오류를 발생한다. 함수선언은 반드시 마지막 ' } ' 으로 종료되어야 하기 때문이다

function() {
 alert('익명함수 호출실행됨1');
}(); // <-- 함수선언 문법 오류

오류가 발생한 위의 코드를 약간 수정하여 아래의 코드를 실행하면 선언과 동시에 호출할 수 있고 문제 없이 실행된다
괄호 안에 함수를 선언하면 선언문법을 지킬 수 있고, 그 함수를 호출하기 위해 괄호 밖에 함수호출을 위한 괄호를 사용한 것이다


(function() {
 alert('익명함수 호출실행됨1');
})();

다음과 같이 문자열 형식으로 선언된 함수가 있을 때 eval () 함수를 사용해서 실행할 수도 있다
var strFun = "function() { "+
 "alert('익명함수 호출실행됨3'); "+
"}";
eval("("+strFun+")()"); // <-- 함수선언 문법을 지키고 선언과 동시에 실행하기 위해 괄호를 사용한 것이다

[출처] http://micropilot.tistory.com/2752

onSubmit Event example



ID:


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Javascript onSubmit example</title>

<script>
function checkForm(form1){
 if(form1.id.value == "") {
  alert("ID required");
  form1.id.focus();
  return false;
 }
 else {
  ans = confirm("정말로 전송하시겠어요?");
  return ans;
 }
}
</script>

</head>
<body>
onSubmit.jsp
<form method="post" onSubmit="return checkForm(this);" action="http://localhost/onSubmit.jsp">
ID: <input type="text" name="id"> 
<input type="submit" value="전 송">
</form>

</body>
</html>


onSubmit.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR"%>
<html>
<body>
서버에 전송된 ID: 
<%=request.getParameter("id") %>
</body>
</html>

DIV영역 하단부가 상하로 이동하는 예제


And here is my very slick menu!

Toggle


<html>
<head>
 <title>Javascript test</title>
 <script language="javascript">
 
  var active = 1;
  var height = 100;

  function toggle_visible() {
  
   if(active == 0) {
    
    active = 1;
    
    divPlusOne();    
   
   } else if(active == 1){
   
    active = 0; 
     
    divMinusOne();
   
   }
  
  }
  
  function divPlusOne() {
   
   if(height <= 100) {
   
    document.getElementById('testDiv').style.visibility="visible"; 
   
    height = height + 1;
    document.getElementById('testDiv').style.height=height + 'px';  
    
    window.setTimeout('divPlusOne()', 1);
    
   }
  
  }
  
  function divMinusOne() {
   
   if(height >= 20) {
   
    height = height - 1;
    document.getElementById('testDiv').style.height=height + 'px';
    
    window.setTimeout('divMinusOne()', 1);
    
   } else {
   
    document.getElementById('testDiv').style.visibility="hidden";
   
   }
  }
 </script>
</head>
<body>

 <div id="testDiv" style="border: #000000 1px solid; height: 100px;">And here is my very slick menu!</div>
<br />

 <a href="#" onClick="toggle_visible()">Toggle</a><br />
<br />

</body>
</html>

[출처]http://micropilot.tistory.com/category/Javascript?page=75#

팝업 윈도우에서 입력한 값을 부모 윈도우에 설정하기

부모 윈도우(parent.html)
<HTML>
 <HEAD>
  <TITLE> opener Window </TITLE>

 <script>
  function showChild(){
   popup = window.open("child.html", "popWnd", "width=500,height=200,toolbar=no,location=no,directories=no,status=no,menubar=no, scrollbars=no,resizable=yes,copyhistory=no");

   document.getElementById("div01").innerHTML = "팝업 윈도우에서 변경할 문자열";
  }
 </script>

 </HEAD>
 <BODY><CENTER><br><br>

 <div id="div01"> 
 아래의 버튼을 누르면 팝업 윈도우가 보입니다.<br>
 팝업 윈도우의 폼에 임의의 문자열을 입력해 보세요.
 </div>

 <br><br>
 <input type='button' value="팝업 윈도우 보이기" onClick="showChild();">

 </CENTER></BODY>
</HTML>
자식 윈도우(child.html)
<HTML>
 <HEAD>
  <TITLE> Child Window </TITLE>

 <script>
  function passToOpener(){
   opener.document.getElementById("div01").innerHTML=document.childForm.field01.value;
   window.close();
  }
 </script>

 </HEAD>

 <BODY><CENTER>

  <form name="childForm">
   입력:<input type="text" name="field01"><br><br>

   <input type="button" value="위에 입력한 내용을 부모 윈도우로 보내기" onClick="passToOpener()">
  </form>

 </CENTER></BODY>
</HTML>

[출처]http://micropilot.tistory.com/category/Javascript?page=78

innerHTML Example


document.getElementById("xxx").innerHTML="Hello World";
다음 2개의 라인 중 한개를 반복해서 클릭해 보세요.

1. Click (링크를 이용한 경우)


2.innerHTML Test (<div>태그를 이용한 경우)



<SCRIPT>
message = "<font color='red'><center>Hello World<br />";
message += "1<br />2<br />3<br />4<br />5</center></font>"; 

on=1;
function toggle(){
  if(on==1){
    document.getElementById("msg").innerHTML=message;
    on=0;
  }else{
    document.getElementById("msg").innerHTML="";
    on=1;
  }
}
</SCRIPT>

<CENTER><STRONG><FONT size=4>document.getElementById("xxx").innerHTML="Hello World";</FONT></STRONG> 
<P>
<br /> 다음 2개의 라인 중 한개를 반복해서 클릭해 보세요.
<br />
<br />1. <A href="javascript:toggle();">Click</A> (링크를 이용한 경우)<br /><br />
<DIV onclick=toggle();>2.innerHTML Test (<div>태그를 이용한 경우)</DIV><br />
<DIV id=msg> </DIV>
</CENTER>

[출처]http://micropilot.tistory.com/category/Javascript?page=79

자바스크립트를 이용하여 마우스 위치 구하기

<html>
<body>

<form name="Show">
<input type="text" name="MouseX" value="0" size="4"> X<br>
<input type="text" name="MouseY" value="0" size="4"> Y<br>
</form>

<script language="JavaScript1.2">
<!--

// Detect if the browser is IE or not.
// If it is not IE, we assume that the browser is NS.
var IE = document.all?true:false

// If NS -- that is, !IE -- then set up for mouse capture
if (!IE) document.captureEvents(Event.MOUSEMOVE)

// Set-up to use getMouseXY function onMouseMove
document.onmousemove = getMouseXY;

// Temporary variables to hold mouse x-y pos.s
var tempX = 0
var tempY = 0

// Main function to retrieve mouse x-y pos.s

function getMouseXY(e) {
  if (IE) { // grab the x-y pos.s if browser is IE
    tempX = event.clientX + document.body.scrollLeft
    tempY = event.clientY + document.body.scrollTop
  } else {  // grab the x-y pos.s if browser is NS
    tempX = e.pageX
    tempY = e.pageY
  }  
  // catch possible negative values in NS4
  if (tempX < 0){tempX = 0}
  if (tempY < 0){tempY = 0}  
  // show the position values in the form named Show
  // in the text fields named MouseX and MouseY
  document.Show.MouseX.value = tempX
  document.Show.MouseY.value = tempY
  return true
}

//-->
</script>
</body>
</html>

메인 윈도우에서 생성한 팝업 윈도우에서 서버에 요청하고 그 응답을 메인 윈도우에서 받는 예제

main.html 이 브라우저에 로드되면 mainWnd라는 이름을 붙여주고 
현재 윈도우에서 생성된 팝업 윈도우(popup.html)가  웹서버에 요청하고 그 응답(response.html)이
mainWnd를 갱신하도록 한다.

main.html (Parent Window)


<HTML>
<HEAD><TITLE> Main.html </TITLE>
<script>
 function openWnd(){
  window.open("popup.html", "pop", "toolbar=no,menubar=no,width=300,height=200,resizable=yes,left=200,top=200");
 }
</script>
</HEAD>
<BODY onLoad="window.name='mainWnd'">
<input type="button" value="Winopen" onClick="openWnd();">
</BODY>
</HTML>

popup.html (Child Window)

<HTML>
<HEAD><TITLE> Popup window </TITLE></HEAD>
<BODY>  
<!--폼을 처리하는 response.html은 target이 mainWnd이므로
폼을 전송하면 그 결과가 mainWnd라는 이름의 브라우저 화면에 나타난다.-->

<form action="response.html" method="post" target="mainWnd" onSubmit="window.close();">
<input type="submit" value="Send">
</form>

</BODY>
</HTML>

response.html

<HTML>
<HEAD><TITLE> response.html</TITLE></HEAD>
<!--이 문서는 mainWnd라는 이름의 브라우저 화면에 나타난다-->
<BODY>
Acton.html
</BODY>
</HTML>

2016년 12월 11일 일요일

자바스크립트 타이머, 스타일시트를 이용하여 지정된 시간 경과후 내용 보여주기

<script language="javascript">

setTimeout("hello()", 4000);

function hello(){
   document.getElementById("answer").style.visibility="visible";
}

</script>

<div id="answer" style="visibility: hidden;">
<span style="color: red;">
</span>
<br />
<h1>
<span style="color: red;">Hello World</span></h1>
</div>

2016년 12월 1일 목요일

HTML TIP

margin과 padding의 차이
http://clason.tistory.com/321

2016년 11월 23일 수요일

인적분할 VS 물적분할

인적분할 VS 물적분할

인적분할 VS 물적분할

기업분할은 인적분할과 물적분할로 나눌 수 있다. 분할을 통해 새로 생기게 되는 기업(신설법인)의 주식을 기존 주주들에게 배분하면 인적분할이고, 기업에서 100% 자회사 형태로 보유하면 물적분할이다. 즉, 인적분할과 물적분할은 신설법인의 주주구성을 어떻게 하느냐에 따라 나뉘게 된다. 

물적분할은 기업을 완전히 분리한다기보다는 보통 경영 효율성 제고를 위해 전략적 으로 구분한다고 볼 수 있다. 사무실에 일종의 칸막이(파티션)를 치는 것과 같다. 반면 인적분할은 기업의 특정 사업부문을 완전히 떼어내는 것이다. 해당 사업부문을 아예 다른 사무실이나 건물로 옮겨버리는 것과 비슷하다. 인적분할은 보통 지주회사 체제로 전환하려는 기업에서 많이 활용한다. 때때로 공동창업자 혹은 주주 간의 관계정리를 위해 인적분할을 하기도 한다. 물적분할은 주로 특정 사업부문을 완전히 독립시키기 위해 활용하는 편이다. 또한 특정 사업부문을 매각하기 위해 진행하는 경우도 많다. 모기업의 100% 자회사가 되는 형태이기 때문에 M&A를 통한 매각이 용이해지기 때문이다.

인적분할 시, 신설법인의 주식은 기존 주주들이 존속법인의 지분율을 그대로 적용하여 나누어 갖게 된다. 그렇기에 각 주주들이 존속법인과 신설법인에서 갖는 영향력에는 변함이 없다. 인적분할을 하고 나면 존속법인은 당연히 상장기업의 지위를 유지한다. 뿐만 아니라 신설법인도 일정한 절차를 거치면 상장할 수 있다. 이미 상장요건을 충족한 기업을 일정 비율에 따라 나눈 것이기 때문이다. 따라서 인적분할 후에는 존속법인, 신설법인 두 상장기업이 생겨나게 되는 것이 보통이다.

인적분할은 상장심사 기준이 까다롭지 않다 보니 우회상장을 위한 수단으로 활용되기도 한다. 비상장기업이 상장기업과 합병한 후에 다시 인적분할하여 분리하면 인수기업과 피인수기업 모두 상장기업의 지위를 유지할 수 있기 때문이다. 한편 완화된 상장심사 기준을 악용하여 부실 사업부문을 신설법인에 넘긴다든가, 존속법인에 남기는 식으로 한쪽에 몰아넣을 가능성도 있다. 그렇기에 투자자는 재상장 이후에 존속법인 혹은 신설법인의 주식을 지속적으로 보유하는 것에 대해 면밀하게 검토해볼 필요가 있다.

물적분할은 신설법인이 발행하는 주식을 전부 존속법인이 보유하는 형태이기 때문에 신설법인은 존속법인의 100%자회사 구조가 된다. 따라서 단순물적분할에 대해서는 별도의 분할비율을 산정할 필요가 없다. 단일 주주 형태를 보이기 때문에 주식분산기준을 충족시키지 못해 비상장기업으로 된다.


- 160503. 일동제약 증권신고서(분할)
- 160803. 일동제약 증권발행실적보고서(합병등)

일동제약은 인적분할과 물적분할을 동시에 진행하는 특이한 사례다. 일동제약은 인적분할의 방법으로 일동제약(주)을 신설하고, 물적분할의 방법으로 일동바이오사이언스(주)와 일동히알테크(주)를 신설한다. 분할 후 존속회사는 일동홀딩스(주)이다. 즉, 분항를 통해 일동홀딩스, 일동제약, 일동바이오사이언스, 일동히알테크 4개의 회사로 나뉘게 된다. 이를 통해 지주회사의 면모를 갖추게 된다.

인적분할로 인해 나눠지는 일동홀딩스와 일동제약 주식의 비율은 약 0.29 대 0.71이며, 기존 일동제약 주식을 소유한 주주는 해당 비율에 따라 일동홀딩스와 일동제약 신주를 각각 배정받게 된다. 분할기일은 2016년 08월 01일이고, 주식 재상장 예정일은 8월 31일이다.

- 160503. 일동제약 증권신고서(분할)

일동제약 측은 각 사업부문의 전문화와 책임경영 체제를 확립하고, 신속 정확한 의사결정을 도모하여 목표달성 및 수익창출을 유도하기 위해 기업분할을 한다고 밝혔다. 지주회사 형태로 전환됨에 따라 결과적으로는 경영권 강화로 이어질 것으로 보인다.

출처 : 주식투자, 전자공시부터 똑바로 보자!

[주식ABC] 인적분할과 물적분할

최근 주식시장에서 신세계의 기업분할이 큰 화제가 됐습니다. 신세계 그룹은 지난달 20일 오후 3시 할인점 이마트 부문과 신세계 백화점 부분을 분할하겠다는 내용을 발표했습니다. 

기업분할은 말 그대로 기업 자체를 쪼개는 행위입니다. 기업분할은 넓은 의미로 보면 분사(Spin-off)의 한 형태입니다. 

기업분할은 분할 기업별로 각자의 특성에 맞는 경영을 효율적으로 할 수 있다는 장점을 가집니다. 기업분할을 통해 우량사업과 부실사업을 분리하면 우량사업에서 벌어들인 돈으로 부실사업의 손실을 메우는 일도 없어집니다. 

신세계 백화점 부문과 할인점 이마트 부문은 신세계라는 기업에 속해 있었지만, 앞으로는 각각의 사업 부문은 개별 기업으로 운영됩니다. 신세계는 양측의 사업이 서로 다르며 이제 둘 다 규모가 커져 회사를 나눠야 오히려 전문성이 높아지고 경쟁력이 제고될 수 있다고 강조했습니다. 

기업분할 방식은 크게 두 가지로 나뉩니다. 분할되는 기업의 주식을 원래 존재했던 회사(모기업)가 100% 보유할 경우 이를 물적분할이라고 합니다. 반면 분할되는 기업의 주식을 모기업 주주들이 일정 비율로 분배하면 이를 인적분할로 부릅니다. 

물적분할은 모기업이 지분을 100% 보유하기 때문에 물적분할로 쪼개져 나온 회사는 별도로 상장되지 않고 비공개 회사로 남습니다. 

인적분할의 경우 원래 있었던 회사는 물론 쪼개진 회사도 재상장ㆍ등록 절차를 거쳐 상장이 가능합니다. 이미 상장 심사를 통과했던 기업을 일정 비율에 따라 나눈 것이기 때문에 인적분할된 기업의 재상장ㆍ등록 심사는 크게 까다롭지 않은 편입니다. 인적분할로 쪼개진 기업의 주가는 시가총액을 분할 비율로 나눠서 결정합니다. 분할 비율은 각각의 순자산가치를 따져 회사 측이 결정합니다. 

물적분할은 구조조정을 목적으로 이뤄지는 경우가 많습니다. 물적분할 방식으로 실적이 나쁜 사업부문을 떼어서 매각할 수 있다면 모기업에 입장에서는 이익입니다. 인적분할은 원래 있었던 기업과의 연계성을 유지하면서 별도 회사로 가는 것이 경영전략이나 주가관리 차원에서 유리하다고 판단될 경우 시행되는 경우가 많습니다.

신세계는 인적분할 방식을 택할 예정입니다. 신세계는 인적분할이 분리된 회사의 전략적인 독립성을 보장하고 주주 가치도 높일 수 있다고 판단, 이 방식을 택할 예정이라고 설명했습니다. 분할 비율은 아직 정해지지 않았습니다. 

만약 백화점 부문과 할인점 이마트 부문의 분할이 20 대 80의 비율로 이뤄지면, 기존 신세계 주식 100주를 가진 주주는 백화점 주식 20주와 이마트 주식 80주를 받게 됩니다. 따라서 신세계가 두 회사로 나뉘더라도 대주주와 특수관계자의 지분 구조는 변하지 않습니다. 

단 물적분할과 인적분할은 회사가치나 주주의 주식가치에는 영향을 미치지 않기 때문에 주주에게 주식 매수청구권을 주지 않습니다.

기업분할이 주가에는 어떤 영향을 미칠까요? 반드시 긍정적인 영향을 미치는 것은 아닙니다. 신세계 주가는 발표한 20일 당일은 마감 직전 25분간 4% 올랐지만 이후 떨어져 지난 1일에는 발표 전보다 1.8% 하락했습니다. 전문가들은 투자자들이 기업분할을 통해 기업가치가 상승할 가능성을 잘 따져봐야 한다고 조언합니다.

[출처]http://biz.chosun.com/site/data/html_dir/2011/02/07/2011020700752.html

2016년 11월 16일 수요일

[windows] 포트 사용여부 확인하기 80 포트 죽이기

1. 80 포트 확인 PID 확인
netstat -ano | find "80"   또는 netstat -o -n -a | findstr 0.0:80
사용중이면 리스트에 나타난다.
 예) TCP 0.0.0:80 0.0.0.0:0 LISTENING 21120
2. pid 찾기
 tasklist /FI "PID eq 21120"
3. 해당 포트 프로세스 중지하기
 C:\> for /f "tokens=5" %p in (' netstat -ano ^| find ":80" ') do taskkill /F /PID %p
4.해당 포트를 사용하는 프로세스를 직접 확인하는 방법
C:\> for /f "tokens=5" %p in (' netstat -ano ^| find ":80" ') do tasklist /FI "PID eq %p"

출처
http://ilovehsk.tistory.com/101

이클립스+nodejs+git 설정

이클립스와 Git 연동하여 사용하기
http://itmir.tistory.com/461

nodejs 시작하기-이클립스
http://ourcstory.tistory.com/36

2016년 11월 8일 화요일

remoteCSE와 AE

oneM2M에서 제공하는 기능을 호출하기 위한 소프트웨어 객체를 등록하기 위해서는 두가지 방법이 있다. IoT 장치가 자체 CSE를 통한 oneM2M 기능을 일부 탑재한 경우에는 <remoteCSE>자원 타입을 사용하고, IoT  장치가 서버에 존재하는 CSE를 통한 기능만을 활용하는 경우에는 <AE> 자원 타입을 사용한다. 대다수의 저 사양 IoT 장치는 현실적으로 자체 CSE를 탑재하기 어려우므로 기능 호출을 위한 객체 등록은 <AE> 자원 타입을 주로 활용한다.

Yellow Turtle 과 Thyme은 <AE>로 등록 사용되고 &Cube : Rosemary v21.14는 MN 이 사용됨.

2016년 11월 2일 수요일

SQL의 데이터 조작 기능(3)

SQL의 데이터 조작 기능(3)

8. 그룹별 검색

테이블에서 특정 속성의 값이 같은 투플을 모아 그룹을 만들고, 그룹별로 검색을 하기 위해 GROUP BY 키워드를 사용한다. 그룹에 대한 조건을 추가하려면 GROUP BY 키워드를 HAVING 키워드와 함께 사용하면 된다. GROUP BY 키워드가 없는 SELECT 문에서는 테이블 전체를 하나의 그룹으로 하여 검색을 진행하는 것으로 이해할 수 있다. 그룹별로 검색하는 SELECT 문의 기본 형식은 다음과 같다.

SELECT [ ALL | DISTINCT ] 속성_리스트
FROM 테이블_리스트
[ WHERE 조건 ]
[ GROUP BY 속성_리스트 [ HAVING 조건 ] ]
[ ORDER BY 속성_리스트 [ ASC | DESC ] ];

주문 테이블에서 주문제품별 수량의 합계를 검색해보자. 속성값은 총주문수량으로 한다.
SELECT product, SUM(quantity) AS '총주문수량' FROM order_info GROUP BY product;

주문제품별 수량의 합계를 구하기 위해 동일 제품을 주문한 투플을 모아 그룹으로 만들고, 그룹별로 수량의 합계를 계산한다.

그룹별로 검색할 때는 그룹을 나누는 기준이 되는 속성을 SELECT 절에도 작성하는 것이 좋다. SELECT 절에 그룹을 나누는 기준 속성을 작성하지 않아도 실행은 되지만 어떤 그룹에 대한 검색 결과인지를 결과 테이블에서 확인하기 어렵기 때문이다.

제품 테이블에서 제조업체별로 제조한 제품의 개수와 제품 중 가장 비싼 단가를 검색하되, 제품의 개수는 재품수라는 이름으로 출력하고 가장 비싼 단가는 최고가라는 이름으로 출력해보자.

 SELECT manufacturer, COUNT(*) AS 재품수, MAX(price) AS 최고가 FROM product GROUP BY manufacturer;

제품 테이블에서 제품을 3개 이상 제조한 제조업체별로 제품의 개수와, 제품 중 가장 비싼 단가를 검색해보자. 제품의 개수는 제품수, 가장 비싼 단가는 최고가로 속성을 표기한다.

SELECT manufacturer, COUNT(*) AS 제품수, MAX(price) AS 최고가 FROM product GROUP BY manufacturer HAVING COUNT(*)>=3;

고객 테이블에서 적립금 평균이 1000원 이상인 등급에 대해 등급별 고객 수와 적립금 평균을 검색해보자.

SELECT grade, COUNT(*) AS 고객수, AVG(saved_money) AS 평균적립금 FROM customer GROUP BY grade HAVING AVG(saved_money) >= 1000;

그룹별로 검색할 때는 집계 함수나 GROUP BY 절에 있는 속성 외의 속성은 SELECT 절에 사용할 수 없다. 예를 들어 각 주문고객이 주문한 총주문수량을 주문제품별로 검색하기 위해 SELECT 문을 다음과 같이 작성하면 오류가 발생한다. GROUP BY 절에 없는 주문고객 속성을 SELECT 절에서 사용했기 때문이다.

주문 테이블에서 각 주문고객이 주문한 제품의 총주문수량을 주문제품별로 검색하라.

SELECT product, customer, SUM(quantity) AS 총주문수량 FROM order_info GROUP BY product, customer;

9. 여러 테이블에 대한 조인 검색


여러 개의 테이블을 연결하여 데이터를 검색하는 것을 조인 검색이라 한다. 조인 검색을 하려면 테이블을 연결해주는 속성이 필요하고 이 속성을 조인 속성이라 한다. 테이블을 연결하려면, 조인 속성의 이름은 달라도 되지만 도메인은 반드시 같아야 한다. 일반적으로 테이블의 관계를 나타내는 외래키를 조인 속성으로 이용한다.

조인 검색을 위한 SQL 문은 FROM 절에 검색에 필요한 모든 테이블을 나열하고, WHERE 절에는 조인 속성의 값이 같아야 함을 의미하는 조인 조건을 제시한다. 여러 테이블을 이용하는 조인 검색은 이름이 같은 속성이 서로 다른 테이블에 존재할 수도 있기 때문에 속성의 이름 앞에 해당 속성이 소속된 테이블의 이름을 표시해주는 것이 좋다. 테이블의 이름과 속성의 이름은 "." 기호로 연결한다.

판매 데이터베이스에서 banana 고객이 주문한 제품의 이름을 검색해보자.

SELECT product.name AS 제품명 FROM order_info, product WHERE order_info.product = product.id AND order_info.customer = 'banana';

FROM 절에 검색에 필요한 제품 테이블과 주문 테이블을 모두 나열한다. 그리고 WHERE  절에는 주문고객이 banana라는 조건과 함께, 조인 속성인 주문제품 속성이 값과 제품번호 속성의 값이 같아야 함을 의미하는 조인 조건을 제시한다.

판매 데이터베이스에서 나이가 30세 이상의 고객이 주문한 제품의 주문제품(product)과 주문일자를 검색해보자.

SELECT order_info.product AS '주문제품', order_info.order_date AS 주문일자 FROM customer, order_info WHERE order_info.customer = customer.id AND customer.age >= 30;

테이블 이름이 길면 속성 이름 앞에 소속 테이블을 표기하는 일이 번거로울 수 있다. 이 경우 테이블의 이름을 대신하는 단순한 별명을 사용할 수 있다. FROM 절에 테이블의 이름과 별명을 함께 제시하면 된다. 다음과 같이 별명을 사용할 수 있으며 별명을 부여하기 위해 사용하는 AS 키워드는 생략할 수 있다.

SELECT o.product AS '주문제품', o.order_date AS 주문일자 FROM customer AS c, order_info AS o WHERE o.customer = c.id AND c.age >= 30;

판매 데이터베이스에서 고명석 고객이 주문한 제품의 제품명을 검색해보자.

SELECT product.name AS 제품명 FROM order_info, customer, product WHERE order_info.customer = customer.id AND order_info.product = product.id AND customer.name = '고명석';

10. 부속 질의문을 이용한 검색
SELECT 문 안에 또 다른 SELECT 문을 포함할 수도 있다. 다른 SELECT 문 안에 내포된(nested) SELECT 문을 부속 질의문 또는 서브 질의문(sub query)이라 한다. 그리고 다른 SELECT 문을 포함하는 SELECT 문을 상위 질의문 또는 주 질의문(main query)이라 한다. 부속 질의문은 괄호로 묶어 작성하고 ORDER BY 절을 사용할 수 없으며, 상위 질의문보다 먼저 수행된다. 부속 질의문을 이용한 검색은 이어 달리기처럼 부속 질의문을 먼저 수행하고, 그 결과를 이용해 상위 질의문을 수행하여 최종 결과 테이블을 반환한다.

부속 질의문은 하나의 행을 결과로 반환하는 단일 행 부속 질의문과, 하나 이상의 행을 결과로 반환하는 다중 행 부속 질의문으로 분류한다. 부속 질의문과 상위 질의문을 연결하는 연산자가 필요한데 부속 질의문의 종류에 따라 사용할 수 있는 연산자가 다르므로 주의해야 한다. 단일 행 부속 질의문은 일반 비교 연산자를 사용할 수 있지만, 다중 행 부속 질의문은 일반 비교 연산자를 사용할 수 없다.

판매 데이터베이스에서 달콤비스켓과 같은 제조업체에서 제조한 제품의 제품명과 단가를 검색해보자.

SELECT product.name, product.price FROM product WHERE manufacturer = (SELECT manufacturer FROM product WHERE name = '달콤비스켓');

판매 데이터베이스에서 적립금이 가장 많은 고객의 고객이름과 적립금을 검색해보자.
SELECT customer.name, customer.saved_money FROM customer WHERE saved_money = (SELECT MAX(customer.saved_money) FROM customer);

최대 적립금이 단일 값이므로 위의 예제의 부속 질의문은 단일 행 부속 질의문이다. 그러므로 = 연산자를 사용할 수 있다. 단일 행 부속 질의문은 = 연산자 외에도 <>,>,<,>=,<= 와 같은 다른 비교 연산자도 사용할 수 있다. 반면, 다중 행 부속 질의문은 이러한 일반 비교 연산자를 사용할 수 없다.

판매 데이터베이스에서 banana 고객이 주문한 제품의 제품명과 제조업체를 검색해보자.
<부속 질의문>
SELECT product.name, product.manufacturer FROM product WHERE product.id IN (SELECT order_info.product FROM order_info WHERE order_info.customer = 'banana');
<조인 질의를 이용>
SELECT product.name, product.manufacturer FROM product, order_info WHERE product.id = order_info.product AND order_info.name = 'banana';
<EXISTS 연산자를 이용한 SELECT 문>
SELECT product.name, product.manufacturer FROM product WHERE EXISTS(SELECT * FROM order_info WHERE order_info.customer = 'banana' AND order_info.product = product.id);

주문 테이블에서 banana 고객이 주문한 제품의 번호를 부속 질의문으로 먼저 검색하고 그 결과를 이용해 제품 테이블에서 제품의 제품명과 제조업체를 상위 질의문으로 검색한다. 위의 부속 질의문은 결과 값을 여러 개 반환하는 다중 행 부속 질의문이다. 그러므로 = 연산자 대신 IN 연산자를 함께 사용해야 한다. IN 연산자는 부속 질의문의 결과 값들 중에서 하나라도 일치하는 것이 있으면 검색 조건이 참이 되는, 수학의 집합에 사용되는 ∈ 연산자와 같은 역할을 한다.

판매 데이터베이스에서 banana 고객이 주문하지 않은 제품의 제품명과 제조업체를 검색해보아라.
SELECT product.name, product.manufacturer FROM product WHERE product.id NOT IN(SELECT order_info.product FROM order_info WHERE order_info.customer = 'banana');

<다중 행 부속 질의문에 사용 가능한 연산자>

  • IN : 부속 질의문의 결과 값 중 일치하는 것이 있으면 검색 조건이 참
  • NOT IN : 부속 질의문의 결과 값 중 일치하는 것이 없으면 검색 조건이 참
  • EXISTS : 부속 질의문의 결과 값이 하나라도 존재하면 검색 조건이 참
  • NOT EXISTS : 부속 질의문의 결과 값이 하나도 존재하지 않으면 검색 조건이 참
  • ALL : 부속 질의 문의 결과 값 모두와 비교한 결과가 참이면 검색 조건을 만족(비교 연산자와 함께 사용)
  • ANY 또는 SOME : 부속 질의문의 결과 값 중 하나라도 비교한 결과가 참이면 검색 조건을 만족(비교 연산자와 함께 사용)
판매 데이터베이스에서 대한식품이 제조한 모든 제품의 단가보다 비싼 제품의 제품명, 단가, 제조업체를 검색해보자.
SELECT product.name, product.price, product.manufacturer FROM product WHERE product.price > ALL(SELECT product.price FROM product WHERE manufacturer = '대한식품');

판매 데이터베이스에서 2013년 3월 15일에 제품을 주문한 고객의 고객이름을 검색해보자.
SELECT customer.name FROM customer WHERE customer.id = ANY(SELECT order_info.customer FROM order_info WHERE order_date = '2013-03-15');
SELECT customer.name FROM customer WHERE EXISTS(SELECT * FROM order_info WHERE customer.id = order_info.customer AND order_info.order_date = '2013-03-15');

판매 데이터베이스에서 2013년 3월 15일에 제품을 주문하지 않은 고객의 고객이름을 검색해보자.
SELECT customer.name FROM customer WHERE NOT EXISTS(SELECT * FROM order_info WHERE customer.id = order_info.customer AND order_info.order_date = '2013-03-05');

[출처] 한빛아카데미 데이터베이스 개론 김현희지음

2016년 10월 26일 수요일

SQL의 데이터 조작 기능(2)

SQL의 데이터 조작 기능(2)

5. NULL을 이용한 검색

검색 조건에서 특성 속성의 값이 널 값인지를 비교하려면 IS NULL 키워드를 사용한다. 마찬가지로 특정 속성의 값이 널 값이 아닌지를 비교하려면 IS NOT NULL 키워드를 사용한다.

고객 테이블에서 나이가 아직 입력되지 않은 고객이름을 검색해보자.
SELECT name FROM customer WHERE age IS NULL;
검색 조건에서 나이가 아직 입력되지 않았다는 것은 나이 속성이 널 값임을 의미하며 이러한 검색 조건은 'age = NULL' 형태로 표현해서는 안된다.

고객 테이블에서 나이가 이미 입력된 고객의 고객 이름을 검색해보자.
SELECT name FROM customer WHERE age IS NOT NULL;
검색 조건에서 나이가 이미 입력되었다는 것은 나이 속성이 널 값이 아님을 의미한다. 이러한 검색 조건은 'age <> NULL' 의 형태로 표현하지 않고 반드시 'age IS NOT NULL' 형태로 표현해야 한다.

검색 조건에서 널 값은 다른 값과 크기를 비교하면 결과가 모두 거짓이 된다. 아래에서 재고량 stock의 값이 널이면 어떤 비교 연산자를 사용해도 결과가 모두 거짓이다.

재고량 > 10
재고량 < 10
재고량 >= 10
재고량 <= 10
재고량 = 10
재고량 <> 10

6. 정렬 검색

SELECT 문의 검새 결과 테이블은 일밙거으로 DBMS가 정한 순서로 출력된다. 결과 테이블의 내용을 사용자가 원하는 순서로 출력하려면 ORDER BY 키워드를 사용한다. 결과 테이블의 내용을 원하는 기준에 따라 정렬하여 출력하는 SELECT 문의 기본 형식은 다음과 같다.

SELECT [ ALL | DISTINCT ] 속성_리스트
FROM 테이블_리스트
[ WHERE 조건 ]
[ ORDER BY 속성_리스트 [ ASC | DESC ] ];

ORDER BY 키워드와 함께 정렬 기준이 되는 속성을 지정하고, 오름차순 정렬이면 ASC, 내림차순 정렬이면 DESC로 표현한다. 기본 정렬 방법은 오름차순이므로 특별히 지정하지 않으면 오름차순으로 기본 정렬한다.

문자 데이터를 오름차순으로 정렬하면 알파벳이나 사전 순으로 출력된다. 날짜 데이터는 빠른 날짜가 먼저 출력된다. 널 값은 오름차순에서 맨 먼저 출력되고 내림차순에서는 맨 마지막에 출력된다.

결과를 여러 기준에 따라 정렬하려면 ORDER BY 키워드와 함께 정렬 기준이 되는 속성을 차례로 제시하면 된다.

고객 테이블에서 고객이름, 등급, 나이를 검색하되, 나이를 기준으로 내림차순 정렬해보자.
SELECT name, grade, age FROM customer ORDER BY age DESC;

주문 테이블에서 수량이 10개 이상인 주문의 주문고객, 주문제품, 수량, 주문일자를 검색해보자. 단, 주문제품을 기준으로 오름차순 정렬하고, 동일 제품은 수량을 기준으로 내림차순 정렬해보자.
SELECT name, product, quantity, date FROM order_info ORDER BY product ASC, quantity DESC;

7. 집계함수

함수의미사용 가능한 속성의 타입
COUNT속성 값의 개수
MAX속성 값의 최대값모든 데이터
MIN속성 값의 최소값
SUM속성 값의 합계숫자 데이터
AVG속성 값의 평균

집계 함수를 사용할 때 다음과 같은 사항에 주의해야 한다.
  • 집계 함수는 널인 속성 값은 제외하고 계산한다.
  • 집계 함수는 WHERE 절에서는 사용할 수 없고 SELECT 절이나 HAVING 절에서만 사용할 수 있다.
제품 테이블에서 모든 제품의 단가 평균을 검색해보자.
SELECT AVG(price) FROM product;

한빛제과에서 제조한 제품의 재고량 합계를 제품 테이블에서 검색해보자. 출력할 때 속성이름을 재고량 합계로 표시하자.

SELECT SUM(price) AS '재고량 합계' FROM product WHERE manufacturer = '한빛제과';

고객 테이블에 몇 명이 등록되어 있는지 검색해보자.
SELECT COUNT(*) FROM customer;

집계 함수는 널인 속성 값은 제외하기 때문에 널 값을 포함하고 있는 속성으로 COUNT 함수를 적용하면 다른 값이 나올 수 있다. 개수를 정확히 계산하려면 널 값이 없는 속성에 COUNT 함수를 적용하는 것이 좋기 때문에 보통 기본키 속성이나 * 를 이용해 계산한다.

DISTINCT 키워드를 사용해 특정 속성 값의 중복을 없애고 집계 함수를 적용할 수도 있다.

제품 테이블에서 제조업체의 수를 검색해보자. 속성값은 '제조업체 수'로 표시한다.
SELECT COUNT(DISTINCT manufacturer) AS '제조업체 수' FROM product;


[출처] 한빛아카데미 데이터베이스 개론 김현희지음

2016년 10월 19일 수요일

SQL의 데이터 조작 기능(1)

SQL의 데이터 조작 기능(1)

데이터 검색 SELECT
데이터 삽입 INSERT
데이터 수정 UPDATE
데이터 삭제 DELETE

INSERT INTO customer VALUES ('apple', '정소화', 20, 'gold', '학생', 1000);
INSERT INTO customer VALUES ('banana', '김선우', 25, 'vip', '간호사', 2500);
INSERT INTO customer VALUES ('carrot', '고명석', 28, 'gold', '교사', 4500);
INSERT INTO customer VALUES ('orange', '김용욱', 22, 'silver', '학생', 0);
INSERT INTO customer VALUES ('melon', '성원용', 35, 'gold', '회사원', 5000);
INSERT INTO customer VALUES ('pear', '채광주', 31, 'silver', '회사원', 500);
INSERT INTO customer VALUES ('peach', '오형준', NULL, 'silver', '의사', 300);

INSERT INTO product VALUES ('p01', '그냥만두', 5000, 4500, '대한식품');
INSERT INTO product VALUES ('p02', '매운쫄면', 2500, 5500, '민국푸드');
INSERT INTO product VALUES ('p03', '쿵떡파이', 3600, 2600, '한빛제과');
INSERT INTO product VALUES ('p04', '맛난초콜렛', 1250, 2500, '한빛제과');
INSERT INTO product VALUES ('p05', '얼큰라면', 2200, 1200, '대한식품');
INSERT INTO product VALUES ('p06', '통통우동', 1000, 1550, '민국푸드');
INSERT INTO product VALUES ('p07', '달콤비스켓', 1650, 1500, '한빛제과');

INSERT INTO order_info VALUES ('o01', 'apple', 'p03', 10, '서울시 마포구', '13/01/01');
INSERT INTO order_info VALUES ('o02', 'melon', 'p01', 5, '인천시 계양구', '13/01/10');
INSERT INTO order_info VALUES ('o03', 'banana', 'p06', 45, '경기도 부천시', '13/01/11');
INSERT INTO order_info VALUES ('o04', 'carrot', 'p02', 8, '부산시 금정구', '13/02/01');
INSERT INTO order_info VALUES ('o05', 'melon', 'p06', 36, '경기도 용인시', '13/02/20');
INSERT INTO order_info VALUES ('o06', 'banana', 'p01', 19, '충청북도 보은군', '13/03/02');
INSERT INTO order_info VALUES ('o07', 'apple', 'p03', 22, '서울시 영등포구', '13/03/15');
INSERT INTO order_info VALUES ('o08', 'pear', 'p02', 50, '강원도 춘천시', '13/04/10');
INSERT INTO order_info VALUES ('o09', 'banana', 'p04', 15, '전라남도 목포시', '13/04/11');
INSERT INTO order_info VALUES ('o10', 'carrot', 'p03', 20, '경기도 안양시', '13/05/22');

1. 데이터의 검색

1. 기본 검색

SELECT [ALL | DISTINCT ] 속성_리스트 FROM 테이블_리스트;

SELECT 키워드와 함께 검색하고 싶은 속성의 이름을 콤마(,) 로 구분하여 차례로 나열한다. 그리고 FROM 키워드와 함께 검색하고 싶은 속성이 있는 테이블의 이름을 콤마(,) 로 구분하여 차례로 나열한다. SELECT 문은 검색 결과를 테이블 형태로 반환한다. 즉, 테이블을 대상으로 하는 SELECT 문의 수행 결과도 테이블이다.

고객 테이블에서 고객아이디, 고객이름, 등급 속성을 검색해본다.
SELECT id, name, grade FROM customer;


고객 테이블에 존재하는 모든 속성을 검색해본다.
SELECT id, name, age, grade, job, saved_money FROM customer;

고객 테이블에 존재하는 모든 속성을 검색해보자.
SELECT * FROM customer;
결과는 컬럼을 모두 나열한 앞의 예와 동일하다.

제품 테이블에서 제조업체를 검색해보자.
SELECT manufacturer from product;
위 결과와 같이 SELECT 문의 결과 테이블은 관계 데이터 모델의 일반 릴레이션과 큰 차이가 있다. 관계 데이터 모델의 일반 릴레이션은 투플의 집합 개념으로 이해할 수 있으며 투플의 유일성을 만족해야 하기 때문에 릴레이션 하나에서 동일한 투플이 중복되면 안되다. 그러나 SELECT 문의 수행 결과로 반환되는 결과 테이블에서는 동일한 투플이 중복될 수 있다.

결과 테이블이 중복을 허용하도록 ALL 키워드를 명시적으로 사용할 수 있다.
SELECT ALL manufacturer from product;
결과는 위의 예와 동일하다.

결과 테이블에서 투플의 중복을 제거하고 한 번씩만 출력되도록 하려면 DISTINCT 키워드를 사용한다.

제품 테이블에서 제조업체 속성을 중복 없이 검색해보자.
SELECT DISTINCT manufacturer FROM product;


결과 테이블에서 출력되는 속성의 이름을 다른 이름으로 바꾸어 출력할 수도 있다. AS 키워드를 변경할 이름과 함께 지정하면 된다. 원래 테이블의 속성 이름이 실제로 바뀌는 것은 아니다. 지정하는 이름에 공백이 포함되어 있으면 작은 따옴표나 큰 따옴표로 묶어주어야 한다. 그리고 AS 키워는 생략할 수 있다.

제품 테이블에서 제품명과 단가를 검색하되, 단가를 가격이라는 새 이름으로 출력하자.
SELECT name, price AS 가격 FROM product;

2. 산술식을 이용한 검색

SELECT 키워드와 함께 산술식을 제시할 수 있다. 산술식은 속성의 이름과 +, -, *, / 등의 산술 연산자와 상수로 구성한다.

제품 테이블에서 제품명과 단가 속성을 검색하되, 단가에 500원을 더해 조정단가라는 새 이름으로 출력해보자.

SELECT name, price + 500 AS 조정단가 FROM product;

3. 조건 검색


조건을 만족하는 데이터만 검색하는 SELECT 문의 기본 형식은 다음과 같다.
SELECT [ ALL | DISTINCT ] 속성_리스트 FROM 테이블_리스트 [ WHERE 조건 ];

WHERE 키워드와 함께 비교 연산자(=, <>, <, >, <=, >=)와 논리 연산자(AND, OR, NOT)를 이용하여 검색 조건을 제시한다.
비교 연산자를 이용해 문자나 날짜 값을 비교할 수 있다.
'A' < 'C' '2013-12-01' < '2013-12-02'
조건에서 숫자값은 그대로 작성해도 되지만 문자나 날짜 값은 속성의 이름과 구별할 수 있도록 작은 따옴표로 묶어야 한다.
논리 연산자는 조건을 여러 개 결합하거나 조건을 만족하지 않는 데이터를 검색하고자 할 때 이용한다.

제품 테이블에서 한빛제과가 제조한 제품의 제품명, 재고량, 단가를 검색하자.
SELECT name, stock, price FROM product WHERE manufacturer = '한빛제과';
주문 테이블에서 apple 고객이 15개 이상 주문한 주문제품, 수량, 주문일자를 검색해보자.
SELECT product, quantity, order_date FROM order_info WHERE customer = 'apple' AND quantity >= 15;

주문 테이블에서 apple 고객이 주문했거나 15개 이상 주문된 제품의 주문제품, 수량, 주문일자, 주문고객을 검색해보자.
SELECT product, quantity, order_date, customer FROM order_info WHERE customer = 'apple' OR quantity >= 15;

제품 테이블에서 단가가 2000원 이상이면서 3000원 이하인 제품의 제품명, 단가, 제조업체를 검색해보자.
SELECT name, price, manufacturer FROM product WHERE price >= 2000 AND price <= 3000;

4. LIKE를 이용한 검색

검색 조건을 정확히 몰라 부분적으로 일치하는 데이터를 검색하고 싶다면 LIKE 키워드를 사용한다. 검색 조건을 정확히 알면 = 연산자로 조건을 표현한다. 단 LIKE 키워드는 문자열을 이요하는 조건에만 사용할 수 있다. 

LIKE 키워드와 함께 사용할 수 있는 기호
  • % : 0개 이상의 문자(문자의 내용과 개수는 상관없음)
  • _ : 한 개의 문자(문자의 내용을 상관 없음)
LIKE 키워드의 사용 예
  • LIKE '데이터%' : 데이터로 시작하는 문자열(데이터로 시작하기만 하면 길이는 상관 없음)
  • LIKE '%데이터' : 데이터로 끝나는 문자열(데이터로 끝나기만 하면 길이는 상관 없음)
  • LIKE '%데이터%' : 데이터가 포함된 문자열
  • LIKE '데이터___' : 데이터로 시작하는 6자 길이의 문자열
  • LIKE '__한%' : 세 번째 글자가 '한'인 문자열
고객 테이블에서 성이 김씨인 고객의 고객이름, 나이, 등급, 적립금을 검색해보자.
SELECT name, age, grade, saved_money FROM customer WHERE name LIKE '김%' ;
고객 테이블에서 고객아이디가 5자인 고객의 고객아이디, 고객이름, 등급을 검색해보자.
SELECT id, name, grade FROM customer WHERE id LIKE '_____';



[출처] 한빛아카데미 데이터베이스 개론 김현희지음

Mysql root 패스워드 분실한 경우 처리

기본으로 윈도우에 Mysql을 설치한 경우 다음의 위치에
각 버전에 대한 데이터 디렉토리가 생성된다.

C:\ProgramData\MySQL\MySQL Server 5.6

해당 디렉토리에서
my.ini 파일을 열어서
skip-grant-tables 구문을 추가한다.

이후 Mysql을 재구동 하면  패스워드를 물어보지 않는다.

다음으로 명령창을 열어서 다음과 같이 실행한다.

$mysql -uroot mysql
mysql> UPDATE user SET password=PASSWORD('변경할 비밀번호') WHERE user='root';

마지막으로 my.ini 파일의
skip-grant-table 구문을 제거하고 Mysql을 재구동한다.

2016년 10월 12일 수요일

SQL의 데이터 정의 기능

SQL의 데이터 정의 기능

1. 테이블 생성

CREATE TABLE

CREATE TABLE 테이블_이름 (
    속성_이름 데이터 타입 [NOT NULL] [DEFAULT 기본_값]
    [PRIMARY KEY (속성_리스트)]
    [UNIQUE (속성_리스트)]
    [FOREIGN KEY (속성_리스트) REFERENCES 테이블_이름(속성_리스트)]
    [ON DELETE 옵션] [ON UPDATE 옵션]
    [CONSTRAINT 이름] [CHECK(조건)]
);

참조무결성 제약조건
왜리키가 어떤 테이블의 무슨 속성을 참조하는지를 REFERENCES 키워드 다음에 명확히 제시하여 참조되는 테이블에서 투플을 함부로 삭제하거나 변경하지 못하게 한다.

참조되는 테이블에서 투플을 삭제할 때 처리하는 방법
1) ON DELETE NO ACTION(투플을 삭제하지 못하게 함)(디폴트)
2) ON DELETE CASCADE(관련 투플을 함께 삭제함)
3) ON DELETE SET NULL(관련 투플의 외래키 값을 NULL로 변경함)
4) ON DELETE SET DEFAULT(관련 투플의 외래키 값을 미리 지정한 기본 값으로 변경함)

참조되는 테이블에서 투플을 변경할 때 처리하는 방법
1) ON UPDATE NO ACTION(투플을 변경하지 못하게 함)(디폴트)
2) ON UPDATE CASCADE(관련 투플에서 외래키 값을 함께 변경함)
3) ON UPDATE SET NULL(관련 투플의 외래키 값을 NULL로 변경함)
4) ON UPDATE SET DEFAULT(관련 투플의 외래키 값을 미리 지정한 기본 값으로 변경함)

데이터 무결성 제약조건의 정의
CREATE TABLE 문으로 테이블을 정의할 때 CHECK 키워드를 사용해 특정 속성에 대한 제약조건을 지정한다. 테이블에 새로운 투플을 삽입하거나 기존 투플을 수정할 때도 이 제약조건을 반드시 지켜야 한다. 이는 테이블에 항상 정확하고 유효한 데이터를 유지하기 위해 데이터 무결성을 위한 제약조건을 표현하는 방법이다.

CHECK(재고량 >=0 AND 재고량 <=1000)
or CONSTRAINT CHK_CPY CHECK(제조업체 = '한빛제과')

고객 테이블
CREATE TABLE customer (
    id                VARCHAR(20) NOT NULL, /* 고객 아이디 */
    name           VARCHAR(10) NOT NULL, /* 고객 이름 */
    age              INT, /* 나이 */
    grade           VARCHAR(10) NOT NULL, /* 등급 */
    job              VARCHAR(20), /* 직업 */
    saved_money INT DEFAULT 0, /* 적립금 */
    PRIMARY KEY(id)
);

제품 테이블
CREATE TABLE product (
    id                CHAR(3) NOT NULL, /* 제품번호 */
    name           VARCHAR(20), /* 제품명 */
    stock           INT, /* 재고량 */
    price            INT, /* 단가 */
    manufacturer VARCHAR(20), /* 제조업체 */
    PRIMARY KEY(id),
    CHECK (stock >= 0 AND stock <= 10000)
);

주문 테이블
CREATE TABLE order_info (
    id            CHAR(3) NOT NULL, /* 주문번호 */
    customer   VARCHAR(20), /* 주문고객 */
    product     CHAR(3), /* 주문제품 */
    quantity     INT, /* 수량 */
    destination VARCHAR(30), /* 배송지 */
    order_date DATETIME, /* 주문일자 */
    PRIMARY KEY(id),
    FOREIGN KEY(customer) REFERENCES customer(id),
    FOREIGN KEY(product) REFERENCES product(id)
);
-- 오라클에서는 주문일자 속성의 데이터 타입은 DATE로 지정

2. 테이블 변경

ALTER TABLE 문을 이용해 새로운 속성 추가, 기존 속성 삭제, 새로운 제약조건 추가, 기존 제약조건 삭제 등이 가능하다.

새로운 속성의 추가

ALTER TABLE 테이블_이름 ADD 속성_이름 데이터_타입 [NOT NULL] [DEFAULT 기본_값];
ex) ALTER TABLE customer ADD join_date DATETIME;

기존 속성의 삭제

ALTER TABLE 테이블_이름 DROP 속성_이름 CASECADE | RESTRICT;

ALTER TABLE 문을 작성할 때는 삭제할 속성과 관련된 제약조건이 존재하거나 이 속성을 참조하는 다른 속성이 존재하는 경우에 처리하는 방법을 선택할 수 있다. 관련된 제약조건이나 참조하는 다른 속성을 함께 삭제하기 위해 CASCADE를 지정하거나, 관련된 제약조건이나 참조하는 다른 속성이 존재하면 삭제가 수행되지 않도록 RESTRICT를 지정할 수 있다.
ex) ALTER TABLE customer DROP grade CASCADE;

새로운 제약조건의 추가

ALTER TABLE 테이블_이름 ADD CONSTRAINT 제약조건_이름 제약조건_내용
ex) ALTER TABLE customer ADD CONSTRAINT CHK_AGE CHECK(age >= 20);

기존 제약조건의 삭제

ALTER TABLE 테이블_이름 DROP CONSTRAINT 제약조건_이름;
ex) ALTER TABLE customer DROP CONSTRAINT CHK_AGE;


3. 테이블 제거

DROP TABLE 테이블_이름 CASECADE | RESTRICT;

DROP TABLE 문을 작성할 때 삭제할 테이블을 참조하는 다른 테이블도 함께 삭제하려면 CASCADE를 지정한다. 반대로 삭제할 테이블을 참조하는 테이블이 있으면 삭제가 수행되지 않도록 하려면 RESTRICT를 지정한다.

ex) DROP TABLE customer RESTRICT;

2016년 9월 11일 일요일

Mosquitto 설치

MQTT 브로커인 Mosquitto 를 설치한다.

모스키토 다운로드 페이지

Mosquitto 설치시
Mosquitto 설치 디렉토리에 다음 파일을 복사에 주어야 한다.

OpenSSL dll 파일들(ssleay32.dll, libeay32.dll)과 pthreadVC2.dll
파일들
최근 버전의 OpenSSL 에는 ssleay32.dll과 libeay32.dll 파일들이 없으므로
Win32OpenSSL_Light-1_0_2h 이전 버전을 다운받아야 한다.

Win32OpenSSL 다운로드 페이지
pthreadVC2.dll 다운로드 페이지

설치후 실행중 에러 조치사항

컴퓨터에 MSVCR100.dll이(가) 없어 프로그램을 시작할 수 없습니다.
프로그램을 다시 설치하여 이 문제를 해결하십시오
시스템 오류 팝업이 뜨는 경우

Visual C++ 재배포 가능 패키지 다운로드
운영체제가 32비트인 경우 vredist_x86.exe
운영체제가 64비트인 경우 vredist_x64.exe와 vredist_x86.exe 둘다 다운로드

커맨드 창에서 unknown 에러가 뜨는 경우

Mosquitto Broker 서비스가 잘못 실행되는 경우가 있다. 컴퓨터를 재시작하고
[제어판][관리도구][서비스] 에서
Mosquitto Broker 서비스를 수동 혹은 자동으로 변경해준다.

[참고 페이지]
http://midnightcow.tistory.com/entry/MQTT-Sever-Mosquitto
http://deneb21.tistory.com/416
http://dalkomit.com/119
http://programmerchoo.tistory.com/132



2016년 9월 8일 목요일

[LoRa]Device Classes – Not All Nodes Are Created Equal

End-devices는 다양한 애플리케이션을 제공하고 다른 요구사항들을 갖는다. 다양한 end 애플리케이션 프로파일을 최적화하기 위해 LoRaWAN 은 각각 다른 device classes를 사용한다. 장치 class들은 네트워크 다운로드 통신 대기 시간(반응 시간)에 대해 배터리 수명의 균형을 맞춘다.제어 또는 구동 타입의 애플리케이션에서 다운로드 통신 반응시간은 중요한 요소이다.



양 방향의 end-devices(Class A):Class A의 End-device들은 양방향 통신을 위해 각
end-device의 상방향 전송 이후에 두개의 짧은 하방향 수신 윈도우가 따라온다. end-device에 의해 스케줄되는 전송 슬롯은 랜덤 시간 기반(ALOHA-type의 프로토콜)에 약간의 변형을 가하여 자신의 통신 필요에 기초를 둔다. 이 Class A 작업은 end-device가 상방향 전송을 보낸 후에 서버로부터 짧은 하방향 통신을 필요로 하는 가장 적은 전력을 소비하는 애플리케이션을 위한 end-device 시스템이다. 다른 시간의 서버로부터 하방향 통신은 다음 스케줄된 상방향 통신 때까지 기다려야 할 것이다.

스케줄된 수신 슬롯을 가진 양 방향의 end-devices(Class B): Class A 의 랜덤 수신
윈도우와 더불어, Class B 장치는 예정된 시간에 추가적인 수신 윈도우를 연다. end-device가 예정된 시간에 수신 윈도우를 열기 위해 게이트웨이로부터 시간 동기화된 신호를 받는다. 이는 서버가 end-device가 언제 귀기울이고 있는지를 알게 해준다.

최대 수신 슬롯을 가진 양방향 en-devices(Class C):Class C의 end-device는
전송시에만 닫아놓고 거의 계속해서 수신 윈도우를 열어놓는다.

2016년 9월 3일 토요일

[퍼온글]AI 스피커를 가진 자, IoT 지배한다

[아이티투데이 이경탁 기자] 최근 인공지능(AI) 기술이 음성인식 기반의 스피커 형태로 구체화되고 있다. 아마존, 구글, 애플, 페이스북 등의 글로벌 기업이 이미 제품을 출시하거나 준비할 뿐 아니라 국내 대표 ICT 기업인 삼성전자, 네이버도 한창 개발 중인 것으로 알려졌다.

SKT 또한 지난달 31일 음성인식 기반 인공지능 서비스 ‘누구‘와 전용기기를 공개했다. 이처럼 각 분야에서 내노라 하는 AI 스피커 제품을 개발하는 이유는 향후 사물인터넷(IoT), 특히 스마트홈이라 불리는 홈 IoT 시장을 선점할 수 있기 때문이다.

스마트홈은 집안의 가전제품, 수도, 전기, 보안기기 등 모든 것을 통신망으로 연결해 모니터링과 제어할 수 있는 기술이 구현된 집을 뜻한다. IoT 구현에는 빅데이터 서비스가 핵심기술로 사용. 예를 들면 우리 집 냉장고가 나의 퇴근 시간 패턴을 빅데이터로 분석한 뒤 퇴근 시간에 맞춰 저녁 메뉴를 추천해주는 상황이 가능해지는 것이다.

경제협력개발기구(OECD) 조사에 따르면 현재 가정당 인터넷에 연결된 기기는 10개 수준이며 오는 2022년에는 가정당 인터넷에 연결된 기기가 50개에 이를 것으로 예상된다.


x
▲ 최근 AI 기술이 음성인식 기반의 스피터 형태로 구체화되고 있다 (사진=위키피디아)
하지만 안 그래도 수 많은 앱이 깔려 복잡한 스마트폰에서 홈IoT까지 구현하기에는 사용자들의 피로성을 증가시킬 수 있다는 지적이다. 이에 기업들이 집안의 기기들을 목소리만으로 간편하게 컨트롤할 수 있는 AI 스피커 제품을 개발하는 것이다.

AI 스피커는 딥러닝(사람처럼 학습하는 인공신경망) 기술을 활용한 인공지능 알고리즘이 제품 속에 탑재된 사용자와 음성으로 커뮤니케이션을 할 수 있는 기기다. 예를 들어 사용자가 음성으로 “신나는 음악을 틀어줘”, “날씨가 더운데 에어컨을 틀어줘”같은 명령어를 내리면 수행하게 된다.

아마존이 지난 2014년 선보인 에코 같은 경우는 음성인식과 블루투스 기능을 갖췄다. ‘알렉사’라고 불러 음악 재생을 요청하거나 인터넷에 연결된 조명을 켜고 끌 수 있다. 이외에도 길이나 위치에 대해 물어보거나 스포츠 경기는 언제 하는지 물어보고 전자책을 읽어 달라할 수 있다.

아마존에서 에코의 제품 평점은 5점 만점에 4.4점 사용자들의 평가도 후한 편이다. 아마존은 지속적인 기술 개발을 통해 같은 가격 또한 대폭 낮춘다는 계획이다.
▲ 아마존 AI 알렉사가 탑재된 스피커 '에코' (사진=플리커)
구글 또한 지난 5월 구글개발자회의에서 ‘구글 어시스턴트’를 탑재한 구글홈을 선보였다. 현재 구글의 지주회사 알파벳의 홈 기술 기업 네스트의 엔지니어들이 구글에 투입되어 기술 개발에 더욱 박차를 가하고 있다.

SKT의 누구는 음악 스트리밍 서비스, 조명, 제습기, 플러그, TV 등 가전기기를 제어하고 음악추천 및 자동 재생, 날씨·일정 등 정보 안내, 스마트폰 위치 찾기 등의 기능이 가능하다.

박일환 SK텔레콤 디바이스 지원단장은 “과거 키보드에서 마우스로, 이후 터치로 입력방식이 진화하며 우리의 일상이 크게 변해 왔다”며 “누구를 시작으로 음성인식과 인공지능이 생활 전반을 획기적으로 바뀌는 AI 대중화 시대를 열어갈 것”이라고 밝혔다.

한편, 삼성전자도 마찬가지로 스피커 형태 인공지능 홈 비서 ‘스쿱’을 준비 중인 것으로 알려졌다. 네이버는 연내 출시를 목표로 홈 비서인 ‘라온’을 개발 중에 있지만 타사와 같이 스피커 제품 형태로 내놓을지는 미정이다.