반응형

id, email : 입력

상품번호 : 자동생성

입력 받는 것은 중복체크를 해야 한다.

글번호 -> 일련번호

기본키로 분류나 검색 인덱싱

분류코드 + 일련번호

 

 

**기본키

기본키를 직접 입력받는 경우에는 중복검사를 해주는 것이 좋습니다.

이벤트는 포커스가 잃어버릴 때를 많이 이용하고 이 때 ajaxwebsocket을 이용해서 서버에게 기본키 입력값을 전송하고 서버는 넘어온 기본키 입력 값을 가지고 데이터베이스에서 조회하고 그 결과를 json이나 xml 형태로 클라이언트에게 알려주며 클라이언트느느 그 값을 가지고 중복 여부를 판단해서 처리를 합니다.

 

=>기본키를 일련번호 형태로 자동 생성하는 경우는 auto_incrementsequence를 이용하기도 하고 현재 입력된 번호 중 가장 큰 번호를 찾고 여기에 +1를 해서 생성하는 방법도 있습니다.

이 방법은 일반적으로 비 추천하고 되도록이면 숫자나 문자의 조합을 이용해서 분류의 기능을 갖도록 만드는 것을 권장합니다.

대표적으로 주민번호나 학번

 

**폼의 데이터 전송 시 유효성 검사

=>클라이언트에서의 유효성 검사

클라이언트에서 유효성 검사를 하게 되면 서버로 전송하지 않고 수행을 하기 떄문에 속도나 트래픽 면에서 유리하지만 보안지 되지 않기 때문에 클라이어느가 유효성 검사 로직을 파악할 수 있습니다.

=>폼의 경우는 submit이번트에서 유효성검사하고 유효성 검사를 통과하지 못하면 서버로 전송하지 못하도록 이벤트 객체의 preventDefault()를 호출하면 됩니다

=>가장 많이 수행하는 유효성 검사는 필수 입력 , 중복 검사 통과 여부 , 패턴 일치 , 2개의 값 일치 등이 있습니다.

필수 입력은 ->required에서 해서 sumit에서 안해도 된다.

 

 

실습insert.jsp에 유효성 검사를 위한 코드를 추가

//폼의 데이터를 전송할 때 발생하는 이벤트 처리

           document.getElementById("myform").addEventListener("submit",function(e){

                                  //중복 체크통과 여부 확인

                                  if(idcheck == false){

                                              iddiv.innerHTML = '아이디 중복검사를 하세요.';

                                              iddiv.style.color ='red';

                                              itemid.focus();

                                              //화면 이동을 안한다.

                                              e.preventDefault();

                                              return;

                                  }

                                 

                                  //price 입력란의 숫자만 입력되었는지 체크

                                  //+ - 기호를 앞에 붙일 수 있는지

                                  //,의 경우는 어떻게 할것인지

                                  //number은 모바일만 가능

                                  //길이는 - length, 개수는count

                                  var price = document.getElementById('price');

                                  for(var i = 0; i < price.value.length;i++){

                                              var ch = price.value.charAt(i);

                                              //console.log(ch);

                                              if(i == 0){

                                                         if(!(ch == '+' || ch == '-' || (ch >= '0' && ch <= '9'))){

                                                                     price.focus();

                                                                     alert("가격의 첫번째 자리는 숫자나 +,- 기호여야 합니다.")

                                                                     //화면 이동을 안한다.

                                                                     e.preventDefault();

                                                                     return;

                                                         }

                                              }else if(!(ch>= '0'  && ch <= '9')){

                                                         price.focus();

                                                         alert("가격은 숫자로만 입력하세요.")

                                                         //화면 이동을 안한다.

                                                         e.preventDefault();

                                                         return;

                                              }

                                  }

                       });

 

 

 

 

**spring에서의 file upload처리

=>MultipartFile 타입으로 처리

1. 준비사항

1)comons-fileupload: 라이브러리의 의존성 설정

2) CommonsMultipartResoulver 클래스의 bean을 생성

 

2.MultipartFile

=>파라미터를 직접 이 타입으로 받아도 되고 HttpServletReques대신에

MultipartHttpServletRequst를 이용해서 요청을 받고 getFile(String parameterName)을 이용해서 가져올 수 있습니다.

 

3.실습

1)파일 업로드 처리를 위한 라이브러리의 의존성을 pom.xml 파일에 추가

                       <!-- 파일 업로드 처리를 위한 의존성 라이브러리 -->

                       <dependency>

                                  <groupId>commons-fileupload</groupId>

                                  <artifactId>commons-fileupload</artifactId>

                                  <version>1.3.1</version>

                       </dependency>

                      

2)파일 업로드를 처리해 줄 수 있는 CommonsMultipart

=>servlet-context.xml파일에 추가

 

3)Dao클래스에 데이터를 삽입하기 위한 메소드를 생성하고 추가

          

           //데이터 1개를 삽입하는 메소드

           public int insertItem(Item item) {

                       sessionFactory.getCurrentSession().save(item);

                       return 1;

           }

 

4)ItemService에 인터페이스에 데이터를 삽입하기 위한 메소드를 선언

           //데이터 삽입(파일업로드 ) 처리를 위한 메소드

           public int insertItem(MultipartHttpServletRequest request);

 

5)ItemServiceImpl 클래스에 데이터를 삽입하기 위한 메소드를 구현

annotation자주 사용하는 것이 길거나 할 때 사용한다.

호출할 때 앞뒤에 코드가 들어간다.

           @Override

           @Transactional

           public int insertItem(MultipartHttpServletRequest request) {

                       // 파라미터 읽기

                       String itemid = request.getParameter("itemid");

                       String itemname = request.getParameter("itemname");

                       String price = request.getParameter("price");

                       String description = request.getParameter("description");

                      

                       //Dao 객체의 파라미터 만들기

                       Item item = new Item();

                       item.setItemid(Integer.parseInt(itemid));

                       item.setItemname(itemname);

                       item.setPrice(Integer.parseInt(price));

                       item.setDescription(description);

                      

                       //파일 읽기

                       MultipartFile mf = request.getFile("pictureurl");

                       //업로드할 파일이 있는 경우에만

                       if(mf.isEmpty() == false) {

                                  //원본 파일 이름 가져오기

                                  String originalName = request.getFile("pictureurl").getOriginalFilename();

                                  //원본 파일 이름은 여러개의 파일을 업로드 하다모변 중복될 수 있기 때문에

                                  //파일이름을 만들 때는 동일한 디렉토리에 저장한다면 중복되지 않도록

                                  //파일 이름을 생성할 필요가 있습니다.

                                  //기본키와 파일염을 합치는 방법이 있고 uuid클래스를 이용해서 만드는 방법

                                  String uploadName = itemid + originalName;

                                  item.setPictureurl(uploadName);

                                 

                                  //파일을 저장할 경로를 생성

                                  //프로젝트의 내의 경로를 가지고 절대경로를 생성

                                  //프로젝트 내의 경로가 아니면 직접 경로를 작성

                                  String uploadPath = request.getRealPath("./img");

                                  //servlet 3.0 이을 사용하면 request.getServletContext().getRealPath("./img")

                                 

                                  //업로드할 file객체 생성

                                  File file = new File(uploadPath + "\\" + uploadName);

                                  try {

                                             request.getFile("pictureurl").transferTo(file);

                                  } catch (IllegalStateException e) {

                                              e.printStackTrace();

                                  } catch (IOException e) {

                                              e.printStackTrace();

                                  }

                       }

                      

                       //데이터 삽입

                       return hibernateDao.insertItem(item);

           }

 

 

3)HomeController클래스에 insertfpost방식으로 요청했을 때 처리를 위한 메소드를 생성

 

 

7)실행하고 파일을 업로드 했을 때 파일을 확인해야 하는 디렉토리

자신의 워크스 페이스 \ 프로젝트 이름

 

=>프로젝트는 원래 모양 그대로 있고 실행이 될때는 프로젝트의 내용을 build해서 위의 디렉토리에 있는 내용이 실행되는 것입니다.

 

=>프로젝트를 복사해서 다른 곳에서 실행하는 경우 프로젝트를 만들 때 존재했던 파일들은 그대로 있지만 실행 중 생성한 파일들은 없습니다.

개발환경에서 운영환경으로 이전(이 작업을 이행이라고 합니다.) 할 때 기존 데이터베이스 내용을 전부 삭제해야 할 때도 있습니다.

 

 

 

 

 

applicataion server

db server

file server

 

 

 

**websocket

=>httphttps는 연결형 프로토콜이기는 하지만 한 번 요청을 해서 응답을 받으면 연결이 끊어집니다.

=>채팅과 같은 애플리케이션을 만들 때 httphttps를 이용하는 것은 어려운 작업입니다.

데이터를 여러번 주고 받고자 하는 경우 연결하고 끊고 다시 연결하고 끊고 하는 작업을 반복해야 합닏.

데이터를 주고받는 시간보다 연결과 해제에 많은 자원을 소모합니다.

그래서 등장방법 중의 하나는 애플리케이션을 설치하는 방법이었습니다.

=>순수 웹 환경에서 실시간 양방향 통신을 위한 Spec  HTML5에서 추가가 되었는데 Spec WebSocket입니다.

websocket은 한 번 연결하면 close할 때 까지 계속 연결되어 있습니다.

 

=>최근에는 Andriod ios 에서도 웹 소켓에 접속하는 api가 추가

 

1.클라이언트(웹 브라우저)에서의 사용 방법(자바스크립트)

1)websocket 객체 생성

new WebSocket("ws://domain/demo")

 

2)데이터 전송

websocket객체.send("데이터")

 

3)데이터 전송받기 - 콜백 사용

WebSocket객체.addEventListener("message",function(e){

           //매개변수 e가 전송된 데이터입니다.

});

 

4)기타 이벤트

open, close이벤트

 

 

5)연결 해제

WebSocket객체.close()

 

 

2.spring 을 이용한 websocket서버 설정

=>websocketHandler인터페이스를 구현한 클래스를 생성하고 메소드 재정의

 

=>클래스 위에 @EnableWebScocket이나 설정 파일에 websocket:handlers태그를 이용해서 웹 소켓 서버 설정

 

3.websockethandler인터페이스르 구현한 클래스

=>TextWebSocketHandler, AbstractWebSocketHandler

 

4.의존성 라이브러리

spring-websocket

 

5.주의할점

=>springwebsocket은 서블릿 3.0부터 사용 가능

 

6.실습

1)pom.xml파일에 spring-websocket의존성 설정

                       <dependency>

                                  <groupId>org.springframework</groupId>

                                  <artifactId>spring-websocket</artifactId>

                                  <version>${org.springframework-version}</version>

                       </dependency>

 

 

2)websocket 서버 클래스를 생성

=>TextWebSocketHandler클래스를 상속

=>기본 패지키 안에 생성

=>com.pk.util.ChatHandler

연결 되면 유저 정보 연결하고 연결이 끊어질때 유저정보 끊고 메세지를 왔을 때 전부 다 보내주면 된다.

//Bean생성을 자동으로 해주기 위한 어노테이션

@Component

//웹 소켓 채팅 서버 클래스

public class ChatHandler extends TextWebSocketHandler {

           //접속한 유저 목록을 가질 List를 생성

           private List<WebSocketSession> users = new ArrayList<WebSocketSession>();

          

           //클라이언트가 접속했을 때 호출될 메소드

           //매개변수로  대입된 데이터가 접속한 클라이언트

           @Override

           public void afterConnectionEstablished(WebSocketSession sesssion) {

                       //List에 추가

                       //접속을 했으면 추가

                       users.add(sesssion);

           }

          

           //클라이언트가 해제했을 때 호출될 메소드

           //매개변수로  대입된 데이터가 접속한 클라이언트

           @Override

           public void afterConnectionClosed(WebSocketSession sesssion,CloseStatus status) {

                       //해제된 이후

                       //List에 제거

                       users.remove(sesssion);

           }

          

           //메시지가 전송되었을 대 호출되는 메소드

           @Override

           public void handleTextMessage(WebSocketSession session, TextMessage message) {

                       System.out.println(message.getPayload()+"가 전송됨");

                       for(WebSocketSession ses: users) {

                                  try {

                                              ses.sendMessage(new TextMessage(message.getPayload()));

                                  } catch (IOException e) {

                                              e.printStackTrace();

                                  }

                       }

           }

}

 

3)ChatHandler클래스를 url과 매핑하는 코드를 servlet-context.xml파일에 작성

=>servlet-context.xml파일에 websocket넴임스페이스를 추가

           <!-- websocket 클래스와  url매핑 -->

           <websocket:handlers>

                       <!-- handler에서 bean id를 작성하고 path는 클라이언트의 접속할 url -->

                       <websocket:mapping handler="chatHandler" path="/chat-ws"/>

           </websocket:handlers>

 

 

4)home.jsp 파일에 채팅페이지로 이동할 링크를 추가

           <a href="chat">websocket을 이용한 채팅 구현</a><br/>

 

5)HomeController클래스의 위의 요청을 처리하는 메소드를 작성

           //chat이라는 요청이 오면 chat이라는 문자열을 가지고 ViewResolver설정을 확인해서

           //뷰 페이지를 결정 -web-inf/views/?.jsp

           @RequestMapping(value="/chat",method = RequestMethod.GET)

           public String chat(MultipartHttpServletRequest request, Model model) {

                       return "chat";

           }

 

6) views디렉토리에 chat.jsp파일을 만들고 작성

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>채팅</title>

<style type="text/css">

           #chatArea{

                       width: 200px;

                       height: 100px;

                       overflow-y : auto;

                       border : 1px solid black;

           }

</style>

</head>

<body>

           <!--  -->

           <a href ="./">메인화면으로 이동</a>

           이름<input type="text" id="nickname"/>

           <input type="button" id="enterbtn" value="입장"/>

           <input type="button" id="exitbtn" value="나가기"/>

          

           <h1>채팅창</h1>

           <div id="chatArea">

                       <div id="chatmessagearea"></div>

           </div>

           <br/>

          

           <input type="text" id="message"/>

           <input type="button" id="sendbtn" value="전송" />

          

           <script type="text/javascript">

                       //웹 소켓 변수

                       var wsocket;

                      

                       //변수에 ㅇ이름을 기재하고 함수를 대입합면

                       //이 함수를 만들고 난 후 뒤에서 사용가능해집니다.

                       //function이름(매개변수){}로 만들면 순서에 상관없이 아무곳에서나 호출가능

                      

                       //문자열을 출력하는 함수

                       var appendMessage = function(msg){

                                  document.getElementById("chatmessagearea").innerHTML = msg+"<br/>" + document.getElementById("chatmessagearea").innerHTML;

                       }

                      

                       //이번체 처리 함수                    

                       var onOpen = function(){

                                  appendMessage("연결 되었습니다.");

                       }

                      

                       var onClose = function(){

                                  appendMessage("연결 해지되었습니다.");

                                  wsocket.close();

                       }

                      

                       var onMessage = function(evt){

                                  var data = evt.data;

                                  appendMessage(data);

                       }

                      

                       var send = function(){

                                  //입력한 내용을 websocket서버에게 전달하고 message 란은 클리어

                                  var nickname = document.getElementById("nickname").value;

                                  var msg = document.getElementById("message").value;

                                  wsocket.send(nickname+":"+msg);

                                  document.getElementById("message").value="";

                       }

                      

                      

                       //웺 소켓 연결함수

                       var connect = function(){

                                  //http://localhost:9000/db/chat-ws - 자기 컴퓨터에서만 접속

                                  wsocket = new WebSocket("ws://ip주소:9000/db/chat-ws");

                      

                                  //이벤트 핸들러 연결

                                  wsocket.addEventListener("open",onOpen);

                                  wsocket.addEventListener("message",onMessage);

                                  //wsocket.addEventListener("close",onClose);

                       }

                      

                       //message 입력란에어 키보드 이벤트가 발생하면

           document.getElementById("message").addEventListener("keypress",function(e){

                                  //enter를 누르면 send()호출

                                  event = e || window.event;

                                  var keycode = (event.keyCode?event.keyCode:event.widch);

                                  if(keycode == 13){

                                              send();

                                  }

                                  event.stopPropagation();

                       });

                       //버튼 들의 이번트 처리

               document.getElementById('sendbtn').addEventListener('click',function(){

                                  send();

                       });

               document.getElementById('enterbtn').addEventListener('click',function(){

                                  connect();

                       });

                 document.getElementById('exitbtn').addEventListener('click',function(){

                                  onClose();

                       });

           </script>

</body>

</html>

 

7)pom.xml파일의 서블릿 설정을 2.53.1.0으로 수정

                       <dependency>

                                  <groupId>javax.servlet</groupId>

                                  <artifactId>javax.servlet-api</artifactId>

                                  <version>3.1.0</version>

                       </dependency>

 

 

 

**로그인 기능 추가

1.데이터베이스에 접속해서 로그인 처리를 테이블을 생성하고 샘플 데이터를 입력

CREATE TABLE MEMBER(

num NUMBER(10),         

userid varchar2(100) UNIQUE,

userpw varchar2(100) NOT NULL,

nickname varchar2(100),

           PRIMARY KEY (num)

);

 

 

INSERT INTO MEMBER VALUES (1,'root','1234','관리자');

INSERT INTO MEMBER VALUES (2,'hhh','1234','김');

INSERT INTO MEMBER VALUES (3,'jessica','1234','제시카');

 

COMMIT;

 

 

2.테이블과 매핑할 dto클래스를 생성

=>com.pk.db.domain.Member

@Data

public class Member {

           private int num;

           private String userid;

           private String userpw;

           private String nickname;

}

 

3.dao 패키지와 클래스와 데이터베이스 테이블을 매핑시키는 xml파일을 생성

=>member.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.pk.db.domain">

           <class name="Member" table="MEMBER">

                       <id name="num" column="NUM">

                       </id>

                       <property name="userid" column="USERID" />

                       <property name="userpw" column="USERPW" />

                       <property name="nickname" column="NICKNAME" />

           </class>

</hibernate-mapping>

 

4.Hibernate설정 파일을 등록하는 코드를 root-context.xml파일에 추가

                                             <value>com/pk/db/dao/member.hbm.xml</value>

 

5.hibernate 사용을 위한 dao클래스를 만들고 로그인 관련 메소드를 작성

=>dao.MemberDao

@Repository

public class MemberDao {

 

           @Autowired

           private SessionFactory sessionFactory;

          

           //로그인 관련 메소드

           //idpw를 매개변수로 받아서 일치하는 데이터가 있는지 찾아옵니다.

           public Member login(Member member) {

                      

                       //setString(0,member.getUserid())

                       //userid가 기보ㄴ키가 아니라서 sql을 이용해서 직접 조회

                       List<Member> list = sessionFactory.getCurrentSession().createSQLQuery("select * from Member where userid=:userid").addEntity(Member.class).setString("userid",member.getUserid()).list();

                       if(list == null || list.size() < 1) return null;

                       return list.get(0);

           }

}

 

6.home.jsp 파일에 로그인과 로그아웃 링크를 생성

=>로그인에 성공하면 member라는 속성에 회원정보를 저장할 것임

=>로그인 여부는 sessionmember라는 속성에 데이터가 있으면 로그인 된것이고 그렇지 않으면 로그인이 되지 않은 것으로 간주

빨간 표시가 나면 지우고 다시 입력하면 된다.예쩐 jsp에서 나오는 것이 남을 수 있다.

           <c:if test ="${member == null} ">

                       <a href="login">로그인</a>

           </c:if>

           <c:if test = "${member != null }">

                       ${member.nickname} <a href="logout">로그아웃</a>

           </c:if>

 

7.login요청이 Get방식으로 오면 login페이지로 포워딩 하도록 메소드를 HomeController에 작성

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>로그인</title>

</head>

<body>

           <form method="post" id="loginform">

                       아이디 <input type="text" id="userid" name ="userid" required="required">

                       비밀번호 <input type ="text" id="userpw" name ="userpw" required="required">

                       <input type="submit" value="전송">

           </form>

</body>

</html>

 

8.MemberService인터페이스를 만들고 로그인 처리 메소드를 선언

public interface MemberService {

           //로그인 처리 메소드

           public Member login(HttpServletRequest request);

}

 

 

9.MemberService implements를 한 MemberServiceImpl클래스를 만들고 로그인 처리 메소드를 구현

package com.pk.db.service;

 

import javax.servlet.http.HttpServletRequest;

import javax.transaction.Transactional;

 

import org.apache.ibatis.executor.ReuseExecutor;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

 

import com.pk.db.dao.MemberDao;

import com.pk.db.domain.Member;

 

@Service

public class MemberServiceImpl implements MemberService {

          

           @Autowired

           public MemberDao memberDao;

          

           @Override

           @Transactional

           public Member login(HttpServletRequest request) {

                       Member member = null;

                      

                       //파라미터 읽기

                       String userid= request.getParameter("userid");

                       String userpw = request.getParameter("userpw");

                      

                       //userid에 해당하는 데이터 찾아오기

                       member = memberDao.login(member);

                       //userid에 해당하는 데이터가 있다면

                       if(member != null) {

                                  if(member.getUserpw().equals(userpw)) {

                                              //로그인 성공한 경우는 session에 로그인 정보를 저장

                                              member.setUserpw(null);//비밀번호를 저장하고 싶지 않았을 경우

                                             request.getSession().setAttribute("member", member);

                                  }else {

                                              //로그인 실패

                                              member  = null;

                                  }

                       }

                      

                       return member;

           }

 

}

 

10. HomeController에서 login요청이 post방식으로 오면 처리하는 메소드를 생성

1)새로운 서비스를 주입받는 코드를 작성

@Autowired

private MemberService memberService;

 

 

2)요청을 처리하는 메소드를 생성

           @RequestMapping(value="/login",method = RequestMethod.POST)

           public String login(HttpServletRequest request, Model model,RedirectAttributes attrs) {

                       //RedirectAttributes redirect를 할 때 한번만 사용하는 데이터를 저장할 수 있는 spring이 제공하는 클래스

                      

                       //서비스의 메소드를 호출

                       Member member = memberService.login(request);

                       //로그인 처리도 redirect로 이동

                       if(member == null) {

                                  //로그인 실패의 경우

                                  attrs.addFlashAttribute("msg", "없는 아이디이거나 잘못된 비밀번호입니다.");

                                  return "redirect:login";

                       }else {

                                  //로그인 성공이면 메인 페이지로 이동

                                  return "redirect:./";//main페이지로 이동

                       }

                      

           }

 

 

11. login.jsp파일에 로그인 실패 메시지를 출력할 영역을 생성

 

 

반응형

'Study > spring' 카테고리의 다른 글

spring-8  (0) 2020.10.26
spring-7  (0) 2020.10.26
spring-5  (0) 2020.10.23
spring-4  (0) 2020.10.23
spring-3  (0) 2020.10.23
반응형

데이터베이스 개론

데이터베이스  파일 관리 시스템

rdbms많이 사용하고

NoSQL ->새로운 기술에 인력소요가 많기 때문에

oracle->가장 강력한 데이터베이스

db2

sap의 사이베이스나 하나db

하나db->많은 양의 데이터 읽는뎅 강하다.

orcle->많은 양의 데이터 쓰기에 강하다.

티맥스 tibero->

비밀버호 1234

mysql, maria db

java

페도라 ->centos->redhat

 

 

관계형 데이터베이스를 구성하는 용어

릴레이션(Relation) : 정보저장의기본형태가2차원구조의테이블

속성(attribute) : 테이블의각열을의미 ->coloumn filed

도메인(Domain) : 속성이가질수있는값들의집합 ->하나의 컬럼이 가질 수 있는 값의 집합 ->자료형->제약조건도 포함

                       ->업무에 관련된 것도 도메인이다.

                       ->도메인 지식이 중요하다.

튜플(Tuple) : 테이블이한행을구성하는속성들의집합 ->레코드 row

카디널리티(Cardinality) : 서로다른테이블사이에대응되는수-내 데이터 하나에 몇개 연결되여있는가

 

(key) 하나의 행을 구분할 수 있는 것들

->릴레이션을구성하는각튜플들을데이터값들에의해유일하게식별할수있는속성또 는속성의집합

 

후보키(Candidate Key) ->최소의 키로 구분할수 있는것 예: 학번

->릴레이션의한속성집합(K)이릴레이션이전체속성집합A의부분집합이면서유일 성(uniqueness)과최소성(minimality)을만족하는속성또는속성의집합(K)

 

기본키(PimaryKey) 후보키중에서 개발자가 선정하는 것 테이블에 하나만 가능하다.

하나만 가능한 것인지 하나의 속성으로 할 필요 없다.

->후보키중에서선정한키로릴레이션의튜플들을유일하게식별할수있는키

필수는 아니지만 하는 게 좋다.

pk ->index가 생성된다. 조회 빠르게 된다.구분하기 위해서

 

대체키(Alternate Key) 

           기본키를제외한나머지후보키(Candidate Key)

 

외래키(Foreign Key) 

           다른테이블의행을식별할수있는속성

           다른테이블에서는기본키이거나유일한값을갖는속성

 

제약조건

개체무결성(Entity Inetgrity) 

           기본키는null이거나중복될수없음

참조무결성(Referential Intigrity) 

           릴레이션은 참조할수없는외래키의값을가져서는안됨

           외래키의값은다른테이블에존재하는값이거나null 이어야함

 

NoSQL이무엇의약자인지는No SQL, Not Only SQL, Non-Relational Operational Database

SQL로엇갈리는의견들이있습니다만,현재Not Only SQL로풀어설명하는것이다수를차지

 

NoSQL 분류 ->dict map

Key Value DB: KeyValue의쌍으로데이터가저장되는가장단순한형태의솔루션으로 AmazonDynamo Paper에서유래되었으며Riak, Vodemort, Tokyo

          Wide Columnar Store: Big Table DB라고도하며GoogleBigTablePaper에서유래되었 으며Key Value 에서발전된형태의Column Family 데이터모델을사용하고있고HBase, Cassandra, ScyllaDB->windows에서 안됨 linux등에서 가능

          Document DB: Lotus Notes에서유래되었으며, JSON, XML과같은Collection 데이터모 델구조를채택하는형태로MongoDB, CoughDB

Cassandra ->java로 만들었다.

MongoDB->c++기반으로 되여있다.

          Graph DB: Euler & Graph Theory에서유래한DBNodes, Relationship, Key-Value 데이 터모델을채용하는형태인데Neo4J, OreientDB

           기존의 관계형 등 여러가지 많이 사용한다.

 

Oracle은 보통  linux  unix에서 한다. Mac에서 설치되지 않는다.windows에서 불안전하다.

Mac은 서버쪽 관련 공부하는 것이 안좋아서 container우에 깔아야 한다.

9i ->internet

10g, 11g->grid

12c ->cloud

 

Sid  두개

Orcl(enter prise)

Xe(expre )->비밀번호만 여는 것

서비스에 가서

저장소 xe

원본을 사용하는 것이 아니다. 저장소에서 한다.

Sqlplus->원본을 사용한다.

Sqldeveloper java가 있어야 한다.

dbbeaver유료버전은 mongodb등 접속가능하다.

Os authen  아이디 비밀번호 없는 것이다.

어디에 있는 것인가 ?

System

 

Driver oracle과 툴

driver혹은 interface이다.

 

사용자가 없어서 만들어줘야 한다.

 

--USER추가

CREATE USER scott IDENTIFIED BY tiger;

ALTER USER scott DEFAULT TABLESPACE USERS;

ALTER USER scott TEMPORARY TABLESPACE TEMP;

GRANT CONNECT , DBA, RESOURCE TO SCOTT;

;->한명령어를 여기까지 한번에 해주세요

 

Set ->데이터가  7 ,9 ,14

List는 순서데로 저장한다.없는 데이터 찾는데 오래 걸린다. 다 검색해야 한다.

Set 7을 열경우 계산한다. 3으로 나눈 나머지 가지고 저장해야 한다.

0 ,1 , 2->이런석으로 해서 bucket에 나눈다.중복은 안된다.hash로 한다.

찾는데 걸리는 시간이 같다.

시노님 : 개체에 대한 별명 ->별명을 한다.

식별하기 좋게 한다. 알아보기 쉽게 유지보수 하기 쉽게 위해서

오라클 시퀸스는 좀더 강력하다.

Index 대상을 빨리 찾기 위해서 한다.

우리는 순서데로 옇지만 index한다. index가지고 빠르게 찾는다.

 

Function return하는데

Procedure return이 필요없다. 일만 하면 된다.  Plsql

package묶어 논다.

PL/SQL (Procedural Language/Structured Query Language) 

 SQL  관계형 데이터베이스(오라클) 위한 오라클 사의 절차적인 확장 언어이다.
Transact-SQL (T-SQL)  

 마이크로소프트 사와 사이베이스  소유의  SQL 확장 언어이다. Transact-SQL SQL Server 사용하기 위해 중심이 된다모든  어플리케이션은 사용자 인터페이스에 개의치 않고

Transact-SQL 구문을 서버로 전송함으로써  SQL Server 인스턴스와 통신한다.
trigger삭제 할 때 탈퇴 등 관련하여 가입시 여기 확인해서 탈퇴시 여기 가입해야한다.

명령어를 하나의 것으로 해야한다. 이것을 사용하는 것이 transaction이다.

특정한 날짜에만 사용못하게 하세요 ->trigger를 한다.

명령어 실행 못하게 끔 하는 것

SQL(Structured Query Language)

SEQUEL(Structured English QUeryLanguage)

SQL은비절차적

대화식언어로사용가능

다른종류의범용프로그래언어로작성된프로그램에내장(embed)시킨형태로도 사용가능

각각의튜플단위가아니라튜플들을집합단위로처리

반복문으로 하는것이다.

데이터 분석의 데이터는 vector데이터 이다.

R은 통계학자  return하다 분석을 할 때 원본 데이터 망가지면 안되서 원본데이터 보존해야 한다.

           분석 ->읽기 전용

python은 프로그래머 읽기 쓰기 전용

dql데이터 읽기만 하는 것

7. SQL

D->데이터 관리 하는 분만 한다.

로그아웃 하면서 하는 것이 복사본에 저장한다.

Show user

Conn scott/tiger;

 

 

--DROP TABLE DEPT;

CREATE TABLE DEPT

       (DEPTNO NUMBER(2) CONSTRAINT PK_DEPT PRIMARY KEY,

       DNAME VARCHAR2(14) ,

       LOC VARCHAR2(13) ) ;

--DROP TABLE EMP;

CREATE TABLE EMP

       (EMPNO NUMBER(4) CONSTRAINT PK_EMP PRIMARY KEY,

       ENAME VARCHAR2(10),

       JOB VARCHAR2(9),

       MGR NUMBER(4),

       HIREDATE DATE,

       SAL NUMBER(7,2),

       COMM NUMBER(7,2),

       DEPTNO NUMBER(2) CONSTRAINT FK_DEPTNO REFERENCES DEPT);

INSERT INTO DEPT VALUES

       (10,'ACCOUNTING','NEW YORK');

INSERT INTO DEPT VALUES (20,'RESEARCH','DALLAS');

INSERT INTO DEPT VALUES

       (30,'SALES','CHICAGO');

INSERT INTO DEPT VALUES

       (40,'OPERATIONS','BOSTON');

INSERT INTO EMP VALUES

(7369,'SMITH','CLERK',7902,to_date('17-12-1980','dd-mm-yyyy'),800,NULL,20);

INSERT INTO EMP VALUES

(7499,'ALLEN','SALESMAN',7698,to_date('20-2-1981','dd-mm-yyyy'),1600,300,30);

INSERT INTO EMP VALUES

(7521,'WARD','SALESMAN',7698,to_date('22-2-1981','dd-mm-yyyy'),1250,500,30);

INSERT INTO EMP VALUES

(7566,'JONES','MANAGER',7839,to_date('2-4-1981','dd-mm-yyyy'),2975,NULL,20);

INSERT INTO EMP VALUES

(7654,'MARTIN','SALESMAN',7698,to_date('28-9-1981','dd-mm-yyyy'),1250,1400,30);

INSERT INTO EMP VALUES

(7698,'BLAKE','MANAGER',7839,to_date('1-5-1981','dd-mm-yyyy'),2850,NULL,30);

INSERT INTO EMP VALUES

(7782,'CLARK','MANAGER',7839,to_date('9-6-1981','dd-mm-yyyy'),2450,NULL,10);

INSERT INTO EMP VALUES

(7788,'SCOTT','ANALYST',7566,to_date('13-7-1987','dd-mm-yyyy')-85,3000,NULL,20);

INSERT INTO EMP VALUES

(7839,'KING','PRESIDENT',NULL,to_date('17-11-1981','dd-mm-yyyy'),5000,NULL,10);

INSERT INTO EMP VALUES

(7844,'TURNER','SALESMAN',7698,to_date('8-9-1981','dd-mm-yyyy'),1500,0,30);

INSERT INTO EMP VALUES

(7876,'ADAMS','CLERK',7788,to_date('13-7-1987','dd-mm-yyyy'),1100,NULL,20);

INSERT INTO EMP VALUES

(7900,'JAMES','CLERK',7698,to_date('3-12-1981','dd-mm-yyyy'),950,NULL,30);

INSERT INTO EMP VALUES

(7902,'FORD','ANALYST',7566,to_date('3-12-1981','dd-mm-yyyy'),3000,NULL,20);

INSERT INTO EMP VALUES

(7934,'MILLER','CLERK',7782,to_date('23-1-1982','dd-mm-yyyy'),1300,NULL,10);

 

--DROP TABLE SALGRADE;

CREATE TABLE SALGRADE

      ( GRADE NUMBER,

       LOSAL NUMBER,

       HISAL NUMBER );

INSERT INTO SALGRADE VALUES (1,700,1200);

INSERT INTO SALGRADE VALUES (2,1201,1400);

INSERT INTO SALGRADE VALUES (3,1401,2000);

INSERT INTO SALGRADE VALUES (4,2001,3000);

INSERT INTO SALGRADE VALUES (5,3001,9999);

COMMIT;

 

SELECT * FROM DEPT;

SELECT * FROM EMP;

SELECT * FROM SALGRADE;

 

@script파일 명령어 쓰면 된다.

@하고 sql관련 내용을 땡기면 된다.

DESC dept;--ORA-00900: invalid SQL STATEMENT

--dbeaver에서 안된다. 왜냐하면 현제것 보여주기때문에

SELECT * FROM show_user;# SELECT * FROM show_user;

--dbeaver에서 사용안한다.

 

--색갈이 다른것은 제약어이다.

오라클 대문자

Mysql 소문자. Ibatis

 

3 select

 

 

1.기본적인Select

From -> where->condition ->Select ->order by

1bytes  10bytes

1이면 null

0이면 not null

Nvl()로 준다.

Null+숫자 ànull이다.

 

LITERAL 정해진 값 집여 옇기  사용자가 입력한 상수 ‘a’

숮자 안쓰고

문자 날짜 ‘’

Null은 그냥 쓴다.

Constant ready only 변수  a= 10 a는 변수

Const a = 10 ->수정불가

 

Distinct는 전체 영향을 준다.

한번밖에 못 쓴다.

 

곱하기 * 이것이다. X가 아니다.

And 앞에것 거짓이면 뒤에것 안한다.

%3 == 0 and %4 ==0

%4 == 0 and %3 ==0->이것으로 하는게 좋다. 뒤에것 안해도 되기 때문에

and앞에것 거짓이 확률이 높은 것

or앞에것 참인 확률이 높은 것

WHERE 절의 연산자

BETWEEN A AND B : A B사이 (A B 포함)

NOT BETWEEN A AND B:A B 사이가 아닌

 

 

SELECT *

FROM EMP e;

--특정 클럼만 조회

--emp 테이블에서 empno ename 조회

SELECT EMPNO,ENAME

FROM EMP e;

 

--컬럼 별명 부여

SELECT EMPNO AS 사원번호

        , ENAME AS 사원이름 --벌명에 영문 대문자가 있으면 ""안에 기제

FROM EMP e

 

---23페이지

--EMP 테이블의모든데이터를조회

SELECT *

FROM emp;

 

--EMP 테이블에서중복되지않는deptno를조회

SELECT DISTINCT deptno

FROM EMP e;

 

--EMP 테이블의enamejob를연결하여조회

SELECT ENAME || ' ' ||JOB

FROM EMP e;

 

--날짜도 숫자이기 때문에 크기 비교가능

--EMP테이블에서 HIRDATE 1982 1 1 부터 1982 12 31 데이터의 HIREDATE 조회

--날짜는 일반적인 형식의 문자열로 작성이 가능

SELECT ENAME,HIREDATE

FROM EMP e

WHERE HIREDATE BETWEEN '1982/01/01' AND '1982/12/31';

 

--sal 값이 1000-3000사이

SELECT ENAME, SAL

FROM EMP e

WHERE SAL BETWEEN 1000 AND 3000;

 

--in (목록)

--보통은 or 대체가 가능하지만 subquery에서는 or 대체가 안됨

--emp table에서 jobdl clerk또는 salesman 데이터의 모든 컬럼을 조회

SELECT *

FROM EMP

WHERE JOB IN ('CLERK','SALESMAN')

 

--like

--패턴에 일치하는 데이터를 조회할 사용

--2개의 wild card문자를 이용

--% 글자 수와 상관없이 매칭

--_ 1글자와만 매칭

--%A% A 포함됨

--%A  A 끝나는

--A%  A 시작하는

--_A A 끝나는 2글자

--WILD CARD문자를 조회하는 경우

--_ 포함함

--LIKE '%\_%' escape '\':\다음에 나오는 글자는 하나의 문자로 해석 있는 거데로 인식하라

--hiredate 1982 데이터의 ename hiredate 조회

--HIREDATE 12월인 데이터의 ENAME HIREDATE 조회

SELECT ename,hiredate

FROM EMP e

WHERE HIREDATE LIKE '___12%';

--yy/MM/dd

--___01%

--___01___

 

--NULL조회 IS NULL,IS NOT NULL

-- NULL 조회하게 되면 입력된 데이터가 'NULL' 데이터를 조회

SELECT ENAME,COMM

FROM EMP e

WHERE COMM = NULL;

 

 

SELECT ENAME,COMM

FROM EMP e

WHERE COMM IS NULL;

-- = NULL 대신 IS NULL 조회

 

-- AND OR사용시 주의점

-- AND 앞쪽의 조건이 FALSE이면 뒤의 조건을 확인하지 않습니다.

-- OR 앞쪽의 조건이 TRUE이면 뒤의 조건을 확인하지 않습니다.

-- AND OR 사용할 떄는 조건을 확인해서 AND 앞쪽에 FALSE 가능성이 높은 조건을 배치하고 OR 경우에는 TRUE 가능성이 높은 조건을 하는 것이 좋습니다.

-- AND OR 같이 사용될 때는 AND 우선순위가 높습니다.

-- A OR B AND C:(B이고 C 데이터 )또는 A 데이터로 해석

-- OR 우선순위를 높일려면 괄호를 해야 합니다. (A OR B) AND C

 

-- ORDER BY

-- SELECT구문의 결과를 정렬하기 위한

-- SELECT 가장 마지막 절이고 마지막으로 수행됩니다.

-- 2 이상의 데이터를 조회하는 경우 해주는 것이 좋습ㄴ디ㅏ.

-- 관계형 데이터베이스에 데이터를 저장하게 되면 데이터의 순서는 데이터베이스가 결정합니다.

-- 입력 순서와는 무관하게 저장됩니다.

-- 사용형식

-- ORDER BY 컬럼이름  [ASC|DESC],컬럼이름  [ASC|DESC]

-- ASC ->DEFUALT(작은 것에서 순으로 ) 오름차순

-- DESC ->내림차순( 것에서 순으로 )

-- 컬럼이름 대신에 SELECT에서 만든 별명 사용가능

-- SELECT에서의 INDEX 사용해도 가능(데이터베이스에서는 인덱스가 1부터 시작)

-- 컬럼이름을 2 이상 사용하면 앞의 데이터 값이 동일할 적용

-- 컬럼 이름 대신에 연산식도 가능하다.

 

--EMP테이블의 모든 데이터를 조회

--HIREDATE 오름차순으로 정렬

SELECT EMPNO,ENAME,JOB,MGR,HIREDATE 입사일,SAL, COMM, DEPTNO

FROM EMP e

ORDER BY HIREDATE;

 

SELECT EMPNO,ENAME,JOB,MGR,HIREDATE 입사일,SAL, COMM, DEPTNO

FROM EMP e

ORDER BY 입사일;

 

SELECT EMPNO,ENAME,JOB,MGR,HIREDATE,SAL, COMM, DEPTNO

FROM EMP e

ORDER BY 5;

--DEPTNO 내림차순 정렬하고 동일한 값이면 EMPNO 오름차순으로 정렬

SELECT *

FROM EMP

ORDER BY DEPTNO DESC, EMPNO;

 

--SELECT 구문

--SELECT       -5

-- FROM        -1

-- WHERE       -2

-- GROUP BY -3

-- having      -4

-- ORDER BY -6

--select from 필수 이다.

 

 

 

--1.EMP 테이블에서sal3000이상인사원의empno, ename, job, sal을조회하는SELECT 문장을 작성

SELECT EMPNO,ENAME,job,SAL

FROM EMP e

WHERE sal >= 3000;

--결과는  SCOTT,KING,FORD

 

--2.EMP 테이블에서empno7788인사원의enamedeptno를조회하는SELECT 문장을작성

SELECT ENAME,DEPTNO

FROM EMP e

WHERE EMPNO = 7788;

--결과는  SCOTT

 

--3.EMP 테이블에서hiredate1981220일과198151일사이에입사한사원의 ename, job, hiredate을조회하는SELECT 문장을작성(hiredate순으로조회)

--1).

SELECT ENAME,JOB, HIREDATE

FROM EMP e

WHERE HIREDATE BETWEEN '1981/02/20' AND '1981/05/01'

ORDER BY hiredate;

 

--2).

SELECT ENAME,JOB, HIREDATE

FROM EMP e

WHERE HIREDATE >= '1981/02/20'; --13

 

SELECT ENAME,JOB, HIREDATE

FROM EMP e

WHERE HIREDATE <= '1981/05/01'; --5

 

SELECT ENAME,JOB, HIREDATE

FROM EMP e

WHERE HIREDATE <= '1981/05/01' AND HIREDATE >= '1981/02/20';

 

 

-- 4.EMP 테이블에서deptno10, 20인사원의모든정보를조회하는SELECT 문장을작성( ename순으로조회)

SELECT *

FROM EMP e

WHERE DEPTNO IN ('10','20')

ORDER BY ENAME;

 

 

-- 5.EMP 테이블에서sal1500이상이고deptno10, 30인사원의enamesal를조회하는 SELECT 문장을작성(HEADINGemployeeMonthly Salary로조회)

SELECT ENAME employee, SAL "Monthly Salary"

FROM EMP

WHERE SAL >= 1500; --8

 

SELECT ENAME employee, SAL "Monthly Salary"

FROM EMP

WHERE DEPTNO IN ('10','30');--9

 

 

SELECT ENAME employee, SAL "Monthly Salary"

FROM EMP

WHERE SAL >= 1500

  AND DEPTNO IN ('10','30');

 

-- 6.EMP 테이블에서hiredate1982년인사원의모든정보를조회하는SELECT 문을작성

SELECT *

FROM EMP e

WHERE HIREDATE LIKE '82%';

 

-- 50페이지

-- 1.EMP 테이블에서MGR NULL 인사원의enamejob 컬럼을조회

SELECT ENAME, JOB

FROM EMP e

WHERE MGR IS NULL;

 

-- 2.EMP 테이블에서COMMNULL이아닌사원의모든정보를조회하는SELECT 문을작성

SELECT *

FROM EMP e

WHERE COMM IS NULL;

-- 3.EMP 테이블에서comm sal보다10% 이상많은사원에대하여ename, sal, comm를조회하 SELECT 문을작성

SELECT *

FROM EMP E

WHERE COMM IS NOT NULL

  AND COMM  >= (SAL * 1.1);

 

 

-- 4.EMP 테이블에서jobCLERK이거나ANALYST이고sal1000, 3000, 5000이아닌사원의모 든정보를조회하는SELECT 문을작성

SELECT *

FROM EMP e

WHERE JOB IN ('CLERK','ANALYST'); --6

 

SELECT *

FROM EMP e

WHERE SAL NOT IN ('1000','3000','5000');--11

 

SELECT *

FROM EMP e

WHERE JOB IN ('CLERK','ANALYST')

  AND SAL NOT IN ('1000','3000','5000');

 

-- 5.EMP 테이블에서enameA E를모두포함하고있는사원의enamesal을조회

SELECT ENAME, SAL

FROM EMP e

WHERE (ENAME LIKE '%A%') ;-- 7

 

 

SELECT ENAME, SAL

FROM EMP e

WHERE (ENAME LIKE '%E%') ; --6

 

--A E를모두포함

SELECT ENAME, SAL

FROM EMP e

WHERE (ENAME LIKE '%E%') AND (ENAME LIKE '%A%');

 

-- 6.EMP 테이블에서(enameL이두자이상이포함되어있고deptno30)이거나mgr7566 인사원의모든정보를조회하는SELECT 문을작성

--enameL이두자이상

SELECT *

FROM EMP e

WHERE ENAME LIKE '%L%L%';--2

 

--deptno30

SELECT *

FROM EMP e

WHERE deptno IN ('30');--6

 

--mgr7566

SELECT *

FROM EMP e

WHERE MGR = '7566';

 

SELECT *

FROM EMP e

WHERE ENAME LIKE '%L%L%'

  AND deptno IN ('30')

   OR MGR = '7566';

 

 

 

 

 

** 오라클 제공함수

1.     함수 분류

1). 단일 행 함수 :하나의 행에 적용되는 함수

2). 다중 행 함수 : 0개 이상의 행에 적용되는 함수

 

2.     dual테이블

=>오라클에서 제공하는 가상의 테이블

=>실제 데이터를 저장할 목적이 아니라 연산의 결과나 확인 등을 하기 위한 테이블

=>select구문에서 from이 없으면 에러가 발생하는데 오늘날짜 같은 데이터는 실제 테이블에 존재하는 데이터가 아닙니다.

오늘 날짜 확인

Select sysdate

From dual;

 

3.     숫자 관련 함수

=>ABS(절대값), COS, EXP(지수), FLOOR(올림), LOG(로그),POWER,SIGN, TAN, ROUND(반올림),TRUNC(올림), MOD

ROUND(데이터[,자릿수]):자릿수가 없으면 소수 첫째 자리에서 반올림 정수로 리턴

자릿수를 적으면 그 자리 뒤에서 반올림해서 리턴

자릿수를 음수를 적으면 정수부분에서 반올림을 합니다.

-1: 1의 자리 반올림

-2: 10의 자리 반올림

 

 

 

--EMP테이블에서 입사 몇칠을 근무했는지 조회

SELECT ENAME, ROUND(SYSDATE - HIREDATE,2) AS 근무일수

FROM EMP e;

 

SELECT ENAME, ROUND(SYSDATE - HIREDATE,-2) AS 근무일수

FROM EMP e;

--14250.72 ->14300

 

SELECT ENAME, TRUNC(SYSDATE - HIREDATE,-2) AS 근무일수

FROM EMP e;

 

 

SELECT ENAME, FLOOR(SYSDATE - HIREDATE) AS 근무일수

FROM EMP e;

 

4.  대소문자 관련 함수

UPPDER:모두 대문자로 변경

LOWER:모두 소문자로 변경

INITCAP:단어의 첫글자만 대문자로 변경

영문 조회할 때는 대소문자 관련 부분을 고려

iOS,iPhone

 

Select ename,sal

From emp

Where job= ‘manager’;

 

Select ename,sal

From emp

Where lower(job)= ‘manager’;

 

 

Select ename,sal

From emp

Where UPPER(job)= ‘MANAGER;

 

encoding:데이터를 컴퓨터에 저장하는 형태로 변경하는 것

Decoding:컴퓨터에 저장된 데이터를 출력하기 위한 형태로 변경하는 것

 

영문은 전세계 모든 코드 체계에서 동일한 방식으로 인코딩과 디코딩을 수행

A->65

a->97

 

한글은 ms949(cp949),euc-kr,utf-8 방식의 인코딩이 있습니다.

ms949: ms-windows인코딩 방식 한글 한글자가 2byte

euc-kr:예전 웹에서 한글을 표현하기 위한 인코딩 방식 한글자가 2byte

utf-8: 전 세계 모든 문자를 표현하기 위한 인코딩 방식 한글자가 3byte

 

다른 인코딩 방식으로 인코딩 된 데이터를 읽으면 제대로 디코딩을 못하기 때문에 글자가 깨집니다.

오픈 소스들에서는 기본 인코딩이 .iso-8859-1(iso latin 1)으로 되어 있는 경우가 많은데 이 방식에서는 한글 표현이 안됩니다.

mysql 은 기본이 iso-8859-1이기때문에 한글 사용불가하다.

그래서 “utf-8”로 지정해야 한다.

b ->byte 오라클 3byte인데 byte로 하면 9byte이다.

substr 문자 수 가지고

substrb byte수로 해야 한다 . 한글자에 에 3byte

      한글은 2혹은 3으로 되여있다.

반응형

'Study > DB' 카테고리의 다른 글

DB-6  (0) 2020.09.18
DB-5  (0) 2020.09.17
DB-4  (0) 2020.09.15
DB-3  (0) 2020.09.15
DB-2  (0) 2020.09.13

+ Recent posts