Filter 를 이용한 한글 인코딩 적용 - 심우곤님 at www.jlab.net

1.5.4. Tomcat에서의 한글문제

작성자: 심 우곤 (wgshim@greenbell.co.kr)
본 문서는 JLab (http://www.jlab.net) 홈페이지에서도 보실 수 있습니다.

Tomcat의 악명 높은 한글 문제입니다. HTML의 <FORM>을 통해 한글 정보를 전달하면 이 값이 깨져버리는데, 이 문제는 Tomcat이 넘어오는 데이터를 내부적으로 변환해 버리기 때문이지요. 물론, 한글을 변환하는 빈을 만들어서 처리하는 방법도 있습니다만, 매 페이지마다 빈을 불러서 처리해야 하는 것이 귀찮지요.


여기서 알려드리려 하는 방법은 Tomcat으로 하여금 <FORM>을 통해 전달하는 값을 URL 인코딩을 하지 않고 EUC_KR로 변환하여 넘기도록 합니다. 이는 한글문제에 대해 고민을 하지 않아도 된다는 것이지요.


물론, 매 페이지는 한글을 잘 표현할 수 있도록 다음과 같은 지시문을 둘 거라 생각합니다.
<%@ page language="java" contentType="text/html; encoding=euc_kr"%>
이제 본격적으로 Tomcat의 한글문제를 다루도록 합시다. 사실 여기서 다루려는 해결방안은 Tomcat을 설치하면서 딸려 들어오는 예제코드(4.0.5나 4.1.12 모두에서 찾아볼 수 있습니다)에서 내용을 찾을 수 있었습니다. -_-;; 놀라셨다구요? 저도 놀랐습니다. 정말 등잔 밑이 어둡다고 하더니만, 이렇게 가까운 곳에 해결책이 있을 줄이야!


%CATALINA_HOME%\webapps\examples\WEB-INF에 존재하는 web.xml을 열어보면, 다음과 같은 부분을 찾을 수 있습니다.
이 방법은 Filter를 사용하는 방법으로 사용자의 입력을 서블릿이 처리하기 전에 해당 정보를 Filter가 적절한 방식으로 변환할 수 있도록 합니다.


그림 20. Tomcat 예제의 web.xml

참 이런걸 보면, 2 Bytes 문자체계를 지원하는 솔루션은 일본인들을 위해서 먼저 만들어진다는 것이 안타깝습니다. 하지만 이로 인해서 우리나라도 유사한 방법으로 한글문제를 쉽게 해결할 수 있지만요.. 잠깐 푸념이었습니다.


물론 위에 보이는 <filter>의 encoding 파라미터의 값을 EUC_JP에서 EUC_KR로 변경해야겠죠? 여기서 한글변환을 위해 사용된 SetCharacterEncodingFilter 클래스는 %CATALINA_HOME%\webapps\examples\WEB-INF\classes\filters에서 찾을 수 있습니다
[그림 21].

그럼 정리하겠습니다.


[ Filter를 사용하여 Tomcat에서의 한글문제 해결방안 ]


1. 구축하고자 하는 여러분의 웹 어플리케이션의 WEB-INF\classes 폴더에 filters라는 새로운 폴더를 생성합니다.


2. 이제 WEB-INF\classes\filters에 SetCharacterEncodingFilter.class 파일을 %CATALINA_HOME%\webapps\examples\WEB-INF\classes\filters 폴더에서 복사합니다.


3. 그 후 여러분의 웹 어플리케이션의 WEB-INF\web.xml의 상단에 다음 라인을 추가합니다.
<filter>
  <filter-name>Set Character Encoding</filter-name>
  <filter-class>filters.SetCharacterEncodingFilter</filter-class>
  <init-param>
    <param-name>encoding</param-name>
    <param-value>EUC_KR</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>Set Character Encoding</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

※ 참고: <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> 인지를 확인합니다. 간혹 2.2버전의 파일이 있는데, 이 때는 아래의 <filter> 및 <filter-mapping>인지하지 못합니다.)

매번 SetCharacterEncodingFilter.class 파일을 WEB-INF\classes\filters에 복사하는 것이 귀찮으시다구요?


Tomcat은 여러 웹 어플리케이션들간에 클래스를 공유할 수 있는 공간을 마련해 두었습니다. Tomcat 4.0.5에서는 %CATALINA_HOME%\classes폴더가 Tomcat 4.1.12에서는 %CATALINA_HOME%\common\classes 폴더가 있는데, 이들 폴더가 바로 그 공간입니다. 자 그럼 이곳에 공용 클래스인 SetCharacterEncodingFilter.class를 공유공간에 복사해 봅시다. 절차는 다음과 같습니다:


Tomcat 4.0.5를 사용하시는 분은 %CATALINA_HOME%\classes에, Tomcat 4.1.12를 사용하시는 분은 %CATALINA_HOME%\common\classes에 filters폴더를 만들고SetCharacterEncodingFilter.class 파일을 복사합니다.
혹은, 매번 폴더 만들고 복사하기가 귀찮으시다면 jar로 압축된 파일을 여기( http://ietmserver.greenbell.co.kr/~wgshim/java/TomcatCharacterEncodingFilter.jar )서 받으시기 바랍니다. 그냥 제가 묶어 놓은 것입니다. 여러분도 예제로부터 쉽게 만들어 사용하시면 됩니다. [파일명: TomcatChracterEncodingFilter.jar]

Tomcat 4.1.12를 사용하시는 분은 %CATALINA_HOME%\lib에, Tomcat 4.1.12를 사용하시는 분은 %CATALINA_HOME%\common\lib에 받으신 jar파일을 복사합니다.


이로써 우리는 앞으로 만들게 될 웹 어플리케이션에서 SetCharacterEncodingFilter 클래스를 공유하게 되었습니다. 그 결과, 여러분들은 위에 언급한 세 단계의 절차 중 첫 번째와 두 번째 항목을 매 어플리케이션마다 수행하실 필요가 없어진 것이지요. 단지 web.xml 파일에 내용을 추가하시기만 하면 됩니다.


감격의 순간이지 않습니까? 저는 이런 방법이 있다는 사실을 다수의 국내 개발자들이 모르고 있다는 것이 안타깝습니다. 널리 이 방법을 전파시켜 주시길 바랍니다. 한글 변환 빈을 만들어서 매번 불편하게 사용해 왔다면, 정말 신선한 방법이겠죠? ^_^


작성자: 심 우곤 (wgshim@greenbell.co.kr)
본 문서는 JLab (http://www.jlab.net) 홈페이지에서도 보실 수 있습니다.

Tag
tag는 게시물의 성격을 나타내는 키워드를 입력하는 공간입니다. login 후 사용하실 수 있습니다.
  • 이 필더는 Servlet으로 넘어가는 데이터만 Tomcat 내부에서 한글 처리하는 것입니다. -- 심우곤님 메일중에...
  • kenu
  • 2002-10-29 09:43:33
  • x
  • 이 내용을 다른 게시판에 올려도 되는지요..좋은 내용입니다.한글 해결이 쉬어지겠네요..
  • hyejin
  • 2002-10-29 17:26:43
  • x
  • 심우곤님과 jlab 저작권표시만 제대로 해주세요.
    그럼 될 것입니다.
  • kenu
  • 2002-10-29 20:17:06
  • x
  • 4.X 버전부터 지원이 되었던걸로 알고 있습니다.
    3.3a 버전의 경우는 자동으로 인터셉터를 했었구여...
    참고하시기 바랍니다.
  • ksany
  • 2002-11-05 19:31:53
  • x
  • request.setCharacterEncoding(String encoding)과 같은 것이겠죠?
  • 최재웅
  • 2002-11-19 11:32:25
  • x
  • 예.. 동일한 것입니다.
  • 심우곤
  • 2002-11-27 12:10:51
  • x
  • ㅠㅠ 감사합니다 ㅠㅠ
  • 허접 jsper
  • 2003-07-25 17:45:07

'프로그래밍 > Web' 카테고리의 다른 글

02 실전에서 쓰는 소스  (0) 2007.11.28
01 로그인....  (0) 2007.11.28
context-param  (0) 2007.11.27
밑의 에러 페이지 처리에 이어서.  (0) 2007.11.27
에러 페이지 처리  (0) 2007.11.27

context-param

프로그래밍/Web 2007. 11. 27. 15:17 Posted by galad

ConnectionPool을 새로 만들어봤습니다.

1. MySql용입니다.
2. timeout, db-server reset 등으로 DB 와 연결을 잃었을 때
   좀비가 되는 문제를 해결하였습니다.
3. ConnectionPool클래스를 web.xml에 Listener로 등록하고 getConnection()메소드를
   static 으로 만들어 어디서든지 풀에 접근가능하도록 하였습니다.
4. Connection반환은 필수입니다. 저는 ConnectionPool에 접근하는 중간계층의 클래스
   를 만들어 사용하기 때문에 풀자체에서 반환여부를 체크하지 않습니다.


5. web.xml 설정예제 : context-param 을 이용해 풀에 필요한 정보를 전달합니다.
  context-param 과 listener 의 위치에 주의하십시요.
 
 
<web-app>
  <display-name></display-name>
  <description></description>

   <context-param>
      <param-name>database</param-name>
      <param-value>#dbname#</param-value>
   </context-param>
   <context-param>
      <param-name>database_user</param-name>
      <param-value>#user-name#</param-value>
   </context-param>
   <context-param>
      <param-name>database_password</param-name>
      <param-value>#password#</param-value>
   </context-param>
   <context-param>
      <param-name>database_min</param-name>
      <param-value>3</param-value>
   </context-param>
   <context-param>
        <param-name>database_max</param-name>
        <param-value>10</param-value>
    </context-param>
 

    <!--  
    <filter>..</filter>
    <filter-mapping>..</filter-mapping>
    -->
   
   
    <listener><listener-class>kr.co.korm.sql.ConnectionPool</listener-class></listener>
   
    <!--기타 태그들 -->

</web-app>


---------------------------------------------------------------------------------------------------


/*
   Copyright (C) www.korm.co.kr 박정규
   
   본 프로그램은 공개소프트입니다. 여러분은 이 프로그램을 마음껏 수정하시고
   배포하실수 있읍니다. 여러분에게 도움이 되는 프로그램이기를 바랍니다.
      
   최종수정일 2003년 6월 29일
*/

package kr.co.korm.sql;
import java.util.Vector;
import java.sql.*;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContext;


public class ConnectionPool  implements ServletContextListener {

     static Vector connections = new Vector();
     static String url="jdbc:mysql://localhost:3306/#database#?autoReconnect=true&useUnicode=true&characterEncoding=euc-kr";
     static String user = null;
     static String passwd = null;
     static int max = 1;
     static int min = 1;
     
     
     private ServletContext context = null;
     
    /**
     *  Context 가 시작되었을 때 호출된다.
     */
    public void contextInitialized(ServletContextEvent event) 
      {
      	context = event.getServletContext();
     	  String database = context.getInitParameter("database");
     	  url = url.replaceAll("#database#", database);
        user = context.getInitParameter("database_user");
        passwd = context.getInitParameter("database_password");
       
       try { min = Integer.parseInt(context.getInitParameter("database_min")); } catch(Exception e){}
       try { max = Integer.parseInt(context.getInitParameter("database_max")); } catch(Exception e) {}
 
       try {
             Class.forName("org.gjt.mm.mysql.Driver");   
     
            // 최소수만큼의 연결을 생성해놓는다.
            for(int i=0;i<min;i++)
              {
     	          connections.add( DriverManager.getConnection(url, user, passwd) );
     	        }
     	     }
 	     catch(Exception e)  { 	 context.log(e.getMessage());   }
 	   }  


    /**
     *  Context 가 종료될때 호출된다.
     */
    public void contextDestroyed(ServletContextEvent event) 
      {
    	  for(int i=0;i<connections.size();i++)
   	  	  {
            Connection con = (Connection)connections.elementAt(i);
            try { con.close(); } catch(Exception e){}
     	    }
       	connections.clear();
      }

    /**
     *  풀로부터 Connection 객체를 얻는 함수
     */     
    public static Connection getConnection() throws Exception
      {     
       	Connection con = null;
    	  int try_count=0;
     	  
     	   while(true)
     	      {
     	  	     try { return (Connection)connections.remove(0); } 
     	  	     catch(Exception e){}  // 모든 Connection이 사용중이면 Excetion이 발생한다.
                	  
               try { return DriverManager.getConnection(url, user, passwd); }
               catch(Exception e){}  // 더 이상 데이타베이스서버로부터 Connection을 가져올 수 없으면 Exception발생
                    
               if(try_count++>3) throw new ConnectionException("일시적으로 사용자가 너무 많아 데이타베이스에 연결할 수 없습니다.");
                
               try { Thread.sleep(50); } catch(Exception e){} //0.05초 후에 재시도한다.
            }      	
     }	


    /**
     *   풀에 Connection 객체를 반납한다. 
     */
    public static void free(Connection con)
      {
      	try {
            	if(connections.size() < max) connections.add(con);
            	else con.close();
            }
        catch(Exception e){}	
      }	
}

'프로그래밍 > Web' 카테고리의 다른 글

01 로그인....  (0) 2007.11.28
[펌] Filter 를 이용한 한글 인코딩 적용  (0) 2007.11.27
밑의 에러 페이지 처리에 이어서.  (0) 2007.11.27
에러 페이지 처리  (0) 2007.11.27
열혈강의 6장 실습하기  (0) 2007.11.27

밑의 방식으로는 이전 페이지가 넘어오지 않는다 ㅡ.ㅡ;;

포워딩 해서 그런지


null
/Wonderland/common/addressForward.jsp
http://localhost:8080/Wonderland/common/addressForward.jsp
/common/addressForward.jsp
null
/blog/blogMain.jsp?blog_address=Wonderland/common/addressForward.jsp
/Wonderland/common/addressForward.jsp


이런 식으로 포워드 된 페이지만 나온다..


따라서


<%

    Enumeration em = request.getAttributeNames();
    while( em.hasMoreElements() ) {
        String name = (String)em.nextElement();
        System.out.println(name + " , " + request.getAttribute(name));       
    }

%>


를 이용한다. 단, 톰캣 5.0 / 5.5 이상. 즉, 서블릿 / jsp 버젼에 관계있다.


javax.servlet.forward.request_uri , /Wonderland/tb/lonelycat
javax.servlet.forward.context_path , /Wonderland
javax.servlet.forward.servlet_path , /tb/lonelycat
javax.servlet.forward.path_info , /common/addressForward.jsp
javax.servlet.error.servlet_name , default
javax.servlet.error.message , /Wonderland/tb/lonelycat
javax.servlet.error.request_uri , /Wonderland/tb/lonelycat
javax.servlet.error.status_code , 404


결과는 이런 식.


즉, requets.getAttribute("javax.servlet.forward.servlet_path");


를 하면 컨텍스트 패스를 제외한 뒷부분 /tb/lonelycat 이 나온다.


이걸 이용해서 싸이월드 형식의 주소 포워딩이 가능할 듯.

'프로그래밍 > Web' 카테고리의 다른 글

[펌] Filter 를 이용한 한글 인코딩 적용  (0) 2007.11.27
context-param  (0) 2007.11.27
에러 페이지 처리  (0) 2007.11.27
열혈강의 6장 실습하기  (0) 2007.11.27
04 JSP 액션  (0) 2007.11.27

에러 페이지 처리

프로그래밍/Web 2007. 11. 27. 15:15 Posted by galad
<%--
/******************************************************************************
*   파일      : error.jsp
*   용도      :
*   작성자   : 성홍제
*   Version : 0.1 / 2007. 01. 23 -
******************************************************************************/
--%>

<%@ page
    language="java"
    contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"
%>
<%
    // 종종 web.xml의 에러 페이지가 안 먹힐 때 - 에러 페이지로 왔다가 로컬의 에러 페이지로 가는 경우가 있다.
    // 아래처럼 에러 설정을 해주면? 제대로 동작한다
    response.setStatus(200);
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
</head>
<body>

<!--
 이 페이지를 호출한 이전 페이지의 주소를 얻어낸다. 링크 등의 경우 및 직접 주소창에 넣어도 된다
 -->
<%=request.getHeader("referer")%>
<br>

<!--
현재 주소창에서 URI값을 얻어온다.
예를 들어 http://www.naver.com/news
도메인을 제외한 /new가 나온다
 -->
<%=request.getRequestURI()%>
<br>

<!--
request의 쿼리문을 얻어낸다
예를 들어 http://www.naver.com/news?type=sports
type=sports가 나온다
 -->
<%=request.getQueryString()%>
<br>

<a href="<%=request.getContextPath()%>/lonelycat">TEST</a>

</body>
</html>

'프로그래밍 > Web' 카테고리의 다른 글

context-param  (0) 2007.11.27
밑의 에러 페이지 처리에 이어서.  (0) 2007.11.27
열혈강의 6장 실습하기  (0) 2007.11.27
04 JSP 액션  (0) 2007.11.27
03 JSP 시작  (0) 2007.11.27

열혈강의 6장 실습하기

프로그래밍/Web 2007. 11. 27. 15:14 Posted by galad

★ 친구들 연락처를 관리하기 위한 웹 서비스??


★ server.xml 수정


<Context path="/FriendsList" reloadable="true" docBase="D:\www\Tomcat 5.5\webapps\FriendsList">

  <Resource name="jdbc/FriendsDB"
     auth="Container"
     type="javax.sql.DataSource"
        driverClassName="oracle.jdbc.OracleDriver"
     url="jdbc:oracle:thin:@61.109.232.128:1521:ora92"
     username="lonelycat"
     password="itea"
     maxActive="20"
     maxIdle="10"
     maxWait="-1"/>

</Context>


★ <host> ~ </host> 사이에 추가


★ context를 압축해서 올림...

'프로그래밍 > Web' 카테고리의 다른 글

밑의 에러 페이지 처리에 이어서.  (0) 2007.11.27
에러 페이지 처리  (0) 2007.11.27
04 JSP 액션  (0) 2007.11.27
03 JSP 시작  (0) 2007.11.27
02 HelloWorld!!!  (0) 2007.11.27

04 JSP 액션

프로그래밍/Web 2007. 11. 27. 15:13 Posted by galad

★ jsp:useBean... 등에 관하여



<!--
/******************************************************************************
*   파일      : contact2.html
*   용도      : jsp:bean 사용 예제 html
*   작성자   : 성홍제
*   작성일   : 2006. 08. 31
*   Version : 1.0
******************************************************************************/
 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
    <title>Insert title here</title>
</head>
<body>
<h3>연락처</h3>
<form method=post action=contact2.jsp>
  이름<input type=text name=name><br>  <!-- name 속성의 값이 contact2.java의 메소드 -->
  메일<input type=text name=mail><br><!--input 태그를 닫아버리면 null 값이 전송된다.-->
    <p>
    <input type=submit value="전송">
    <input type=reset value="취소">
</form>
</body>
</html>


이 html에서 contact2.jsp에 정보를 넘겨서, contact2.jsp에서 contact2 클래스를 사용하여

개체를 생성, 정보를 저장, 불러오는 예제.


<%--
/******************************************************************************
*   파일      : contact2.jsp
*   용도      : contact2 클래스를 사용해 jsp:bean으로 활용해보는 page
*   작성자   : 성홍제
*   작성일   : 2006. 08. 31
*   Version : 1.0
******************************************************************************/
--%>

<%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>
<% request.setCharacterEncoding("euc-kr"); %>
   
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
    <title>Insert title here</title>
</head>
<body>
<%
    String name = request.getParameter("name");
    String mail = request.getParameter("mail");
%>
<%-- 선언, 생성 Contact2 contact = new Contact2() 와 같다. --%>
<jsp:useBean id="contact" class="contact.contact2" scope="page"/>


<jsp:setProperty name="contact" property="*"/>

<%-- contact 개체에 값을 넣어준다. - 위의 "*" 대신 이렇게 써도 된다.
<jsp:setProperty name="contact" property="name"/>
<jsp:setProperty name="contact" property="mail"/>
 --%>
<%-- 출력해본다. --%>
이름은 : <%= contact.getName() %>
<br>
메일주소는 : <%= contact.getMail() %>

</body>
</html>




/******************************************************************************
*   파일      : contact2.java
*   용도      : contact2.html 에서 넘겨주는 정보를 위한 클래스
*   작성자   : 성홍제
*   작성일   : 2006. 08. 31
*   Version : 1.0
******************************************************************************/

package contact;

public class contact2
{
    // Fields
    private String name;
    private String mail;
   
    // Constructor
    public contact2()
    {}
   
    // Methods
    public void setName(String name)    // contact2.html 의 폼 내의 <input>의 이름과 같아야함
    {                                                  // 밑의 메소드들도 모두 마찬가지. get, set 뒤에 붙는
        this.name = name;                      // 이름이 같아야한다. 첫글자는 html에서는 소문자.
    }
   
    public String getName()
    {
        return this.name;
    }
   
    public void setMail(String mail)
    {
        this.mail = mail;
    }
   
    public String getMail()
    {
        return this.mail;
    }
   
    // Main
}


★ html에서 체크박스이 데이터를 jsp:bean으로 받을 경우

html.....


<input type=checkbox name=sw value="jdk1.5">JDK1.5 <br>
<input type=checkbox name=sw value="JBuilder">JBuilder <br>
<input type=checkbox name=sw value="Eclipse">Eclipse<br>
<input type=checkbox name=sw value="Visual age">Visual age <br>
<input type=checkbox name=sw value="NetBean">NetBean<br><br>


jsp.....


<jsp:setProperty name="data" property="sw"/>  // 받을 때


<%  // 사용하는 경우 - 스트링 배열로 사용한다.
    String[] sw = data.getSw();

    if(sw != null)
    {
        for(int i = 0; i < sw.length; i++)
        {
            out.print(sw[i] + " ");
        }
    }
    else
    {
        out.println("선택한 것이 없습니다.");
    }
%>


데이터를 저장하는 class....


private String[] sw = null;


public void setSw(String[] sw)
{
    this.sw = sw;
}
   
public String[] getSw()
{
    return sw;
}


// sw는 바로 html에서의 체크박스의 이름

'프로그래밍 > Web' 카테고리의 다른 글

에러 페이지 처리  (0) 2007.11.27
열혈강의 6장 실습하기  (0) 2007.11.27
03 JSP 시작  (0) 2007.11.27
02 HelloWorld!!!  (0) 2007.11.27
01 시작~  (0) 2007.11.27

03 JSP 시작

프로그래밍/Web 2007. 11. 27. 15:12 Posted by galad

★ 프리젠테이션 로직에 들어간다.


★ 디폴트 객체의 스코프

1. page : 한 JSP페이지에서만 사용가능

  : response, out, config, page, exception


2. request : 다른 페이지로 전달(이동, forward) 되는 경우에 이동된 페이지에서도 사용 가능

   setAttribute() 메소드를 이용해서 어떤 정보를 저장해 놓으면 다른 페이지에서도 사용 가능

  : request


3. session : 객체 세션이 사용되는 한, 여러 페이지에서 사용할 수 있다.

   1번 페이지에서 필요한 정보들을 session 개체에 저장하면, 다른 페이지들에서도 활용 가능

   로그인 정보 등..

  : session


4. application : 웹 응용 프로그램에 소속된 모든 페이지들이 사용할 수 있다.

  : application


★ 변수 선언

스크립트렛(<% ~ %>) 에서 정의한 변수는 나중에 _japService() 메소드의 지역 변수로

선언(<%! ~ %>) 에서 정의한 변수는 나중에 서블릿 클래스의 멤버 필드로 바뀐다.


즉, 하나의 jsp 문서에서 여러 개의 <% ~ %> 안에 있는 변수는 _japService() 메소드 안에 있는

것이므로 위의 스크립트렛에서 정의한 변수를 아래의 스크립트렛에서 사용할 수 있다.


변수를 선언해서 사용하는 경우는 멤버 메소드에서 그 변수를 사용하는 경우를 빼고는 별로 없다.


★ 폼에서 한글 데이터를 전송 받아서 사용할 때 한글이 깨지는 경우

jsp문서에서 한글 데이터를 처리하기 전 - 가능하면 최상위에 - 에 다음과 같이 추가


request.setCharacterEncoding("euc-kr");


들어오는 정보를 한글 처리해 달라는 것.


예제)))))


<!--
/******************************************************************************
*   파일      : select-items.html
*   용도      : 폼에서 jsp로의 데이터 전송 테스트
*   작성자   : 성홍제
*   작성일   : 2006. 08. 29
*   Version : 1.0
******************************************************************************/
-->

<html>
<head>
    <title>JSP POST TEST</title>
</head>

<body>
<center>
    <h2>JSP POST 테스트</h2>
</center>

<form method=POST action=select-items.jsp>
    이름 <input type=input name=name><br>
    주소 <input type=input name=addr> <br><br>
 
    다음 사항을 선택해주세요.<br>
    사용중인 운영 체제는 ? <br>
    <select name=os size=3 multiple>
        <option value="win32">윈도우즈
        <option value="linux">리눅스
        <option value="solaris">솔라리스
        <option value="misc">기타
    </select>

    <br><br>사용중인 컴퓨터 하드웨어는 ? <br>
    <select name=hw>
        <option value="pentium">펜티엄
        <option value="misc">기타
    </select>

    <br><br>사용중인 통신회사는 ? <br>
    <select name="통신회사"  multiple>
        <option> 하이텔
        <option> 천리안
        <option>기타
    </select>

    <br>
    <input type=submit value=전송>
    <input type=reset value=취소>
</form>
</body>
</html>


<%--
/******************************************************************************
*   파일      : select-items.jsp
*   용도      : select-items.html에서 넘겨받은 데이터를 보여준다.
*   작성자   : 성홍제
*   작성일   : 2006. 08. 29
*   Version : 1.0
******************************************************************************/
--%>
<%@ page contentType="text/html;charset=KSC5601" %>

<html>
<head>
    <title>Select Items</title>
</head>

<body>
<center>
    <h2>Select Items 테스트</h2>
</center>

HTML에서 선택한 내용은 다음과 같습니다. <hr>

<%
    request.setCharacterEncoding("euc-kr");

    java.util.Enumeration en = request.getParameterNames();

    while(en.hasMoreElements())
    {
        String name = (String)en.nextElement();
        String values[] = request.getParameterValues(name);

        for(int i=0; i < values.length; i++)
        {
            out.print("<li>");
            out.print(name);
            out.print(":");
            out.println(values[i]);
        }
    }
%>

</body>
</html>



결과가 순서대로 나오지는 않지만, Enumeration이 원래 그렇단다....

'프로그래밍 > Web' 카테고리의 다른 글

에러 페이지 처리  (0) 2007.11.27
열혈강의 6장 실습하기  (0) 2007.11.27
04 JSP 액션  (0) 2007.11.27
02 HelloWorld!!!  (0) 2007.11.27
01 시작~  (0) 2007.11.27

02 HelloWorld!!!

프로그래밍/Web 2007. 11. 27. 15:10 Posted by galad


/******************************************************************************
*   파일      : HelloServlet.java
*   용도      : 초간단 서블릿 프로그램
*   작성자   : 성홍제
*   작성일   : 2006. 08. 24
*   Version : 1.0
******************************************************************************/

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloServlet extends HttpServlet
{
    // 서버가 입력받은 정보는 req에 - 클라이언트가 request했으므로, 서버가 보낼 정보는 res에 - 서버가 response하므로.
    public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
    {
        // 현재 클라이언트에 보낼 문서는 text/html이고 euc-kr로 인코딩되어있다고 알림
        res.setContentType("text/html;charset=euc-kr");
       
        PrintWriter out = res.getWriter();  // 출력 스트림을 얻는다.
       
        // html body 작성
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Hello, World</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("Hello, World!!!");
        out.println("</body>");
        out.println("</html>");
       
        out.close();
    }
}


익스플로러에서 실행 시

1. http://localhost:8080/ITEA/servlet/HelloServlet 

  localhost:8080 으로 들어갔으므로, 아파치를 통하지 않고 바로 톰캣으로 들어간다.

  /ITEA/ 는 톰캣에 deploy한 context를 말한다.

  /servlet/ 은 class 파일이 있는 위치를 말한다.

  HelloServlet 은 만들어서 D:\www\Tomcat 5.5\webapps\ITEA\WEB-INF\classes

에 넣어놓은 class파일명.

  여기서 제대로 보이지 않으면 톰캣 설정에서 문제


D:\www\Tomcat 5.5\webapps\ITEA\WEB-INF\web.xml 파일을 찾아보자


<servlet>
   <servlet-name>invoker</servlet-name>
   <servlet-class>org.apache.catalina.servlets.InvokerServlet</servlet-class>
</servlet>


<servlet-mapping>
   <servlet-name>invoker</servlet-name>
   <url-pattern>/servlet/*</url-pattern>
</servlet-mapping>


  오타는 없는가?


2. http://localhost/ITEA/servlet/HelloServlet

  localhost 로 들어갔으므로 아파치를 통해 톰캣으로 연동된 것.

  위의 경우에는 제대로 되는데, 2번의 경우 되지 않는다면 연동에서 실패한 것.

  관련 문서들을 찾아보자.


D:\www\Apache2\conf\httpd.conf 파일을 제대로 설정했는가

특히 이 부분

JkMount /*servlet/* ajp13
JkMount /*.jsp  ajp13
JkMount /*.do  ajp13
JkMount /Mail  ajp13


/*servlet/*  을 확인해 볼 것. 요청한 주소에 servlet/ 이 있다면 톰캣에서 처리하게 하겠다는 의미

'프로그래밍 > Web' 카테고리의 다른 글

에러 페이지 처리  (0) 2007.11.27
열혈강의 6장 실습하기  (0) 2007.11.27
04 JSP 액션  (0) 2007.11.27
03 JSP 시작  (0) 2007.11.27
01 시작~  (0) 2007.11.27

01 시작~

프로그래밍/Web 2007. 11. 27. 15:09 Posted by galad

1. Apache 설치하기

- Network Domain : IP

- Server Name : IP

- E-main : any


2. Tomcat 설치하기

- 딱히 없다.

- 디렉토리만 설정



★ 아파치, 톰캣 연동하기

1. 아파치 사이트에서 아파치와 톰캣 버젼에 맞는 자카르타를 받는다.


2. 받은 자카르타 파일명을 mod_jk.so 로 바꾸어서 D:\www\Apache2\modules 에 넣는다.

 당연히 디렉토리는 자신이 설치한 곳에


3. 아파치 설정 파일 httpd.conf 변경


파일 중간에 LoadModule 하는 곳에 추가

LoadModule    jk_module     modules/mod_jk.so


마지막에 추가

#For Jakarta
JkWorkersFile     "D:/www/Tomcat 5.5/conf/workers.properties"
JkLogFile      "D:/www/Tomcat 5.5/logs/mod_jk.log"
#JkLogLevel    debug

JkMount /*servlet/* ajp13
JkMount /*.jsp  ajp13
JkMount /*.do  ajp13
JkMount /Mail  ajp13


4. workers.properties 파일을 위에서 설정한 디렉토리에 생성해준다.

위의 디렉토리는 꼭 톰캣일 필요는 없고 아파치에 넣어도 상관없다.

worker.list=ajp13
worker.testWorker.port=8009
worker.testWorker.host=localhost
worker.testWorker.type=ajp13


5. 톰캣의 설정파일 server.xml 을 변경

굵은 글씨를 위치를 잘 찾아서 추가할 것

.

.

<Server port="8005" shutdown="SHUTDOWN">

  <!-- Comment these entries out to disable JMX MBeans support used for the
       administration web application -->
  <Listener className="org.apache.jk.config.ApacheConfig" modJk="D:/www/Apache2/modules/mod_jk.so"/>
  <Listener className="org.apache.catalina.core.AprLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>

.

.

<Host name="localhost" appBase="webapps"
       unpackWARs="true" autoDeploy="true"
       xmlValidation="false" xmlNamespaceAware="false">

    <Listener className="org.apache.jk.config.ApacheConfig" append="true" forwardAll="false" modJk="D:/www/Apache2/modules/mod_jk.so"/>

.

.



6. 톰캣과 아파치를 멈춘 후, 톰캣 - 아파치의 순서로 실행시킨다.



★ 연동 후, 디렉토리 문제.

연동 후, 루트는 기본적으로 아파치에서 설정한 디렉토리가 된다 - htdocs. 따라서 위에서

설정한 jsp, do, servlet 등이 아닌 css나 img 등은 모두 기본적으로 아파치 쪽에서 찾게 되므로

path에 주의할 것.

주로 css, img 등은 아파치 디렉토리에 놓고 쓰던가, 아니면 아파치와 톰캣의 디렉토리를

일치시키기도 한다. 아니면 css나 img를 문서에서 사용할 때 절대경로를 설정하던가..


★ 톰캣의 D:\www\Tomcat 5.5\webapps 에 원하는 디렉토리 - 예를 들어 ITEA - 를 만들고

그 밑에 WEB-INF와 WEB-INF\classes, WEB-INF\lib, WEB-INF\web.xml 파일을 만들어주면

웹브라우져에서 접속가능.

하나의 또다른 서버처럼 작동. http://localhost:8080/ITEA/ 이런 식으로 접속 가능하다.

ROOT에 있는거 복사해다가 수정해서 사용하면 된다.


★ 톰캣 매니져에서 deploy 해주기

Context Path (optional):
XML Configuration file URL:
WAR or Directory URL:


★ 개인용 컴퓨터의 경우 8080 포트가 방화벽에 막혀있어서 접속이 불가능하기도 하므로

예외에 추가해줄 것


★ 톰캣에서 컴파일된 서블릿을 자동 로드하게 만들기

context.xml 파일을 변경

<Context> -> <Context reloadable="true">

'프로그래밍 > Web' 카테고리의 다른 글

에러 페이지 처리  (0) 2007.11.27
열혈강의 6장 실습하기  (0) 2007.11.27
04 JSP 액션  (0) 2007.11.27
03 JSP 시작  (0) 2007.11.27
02 HelloWorld!!!  (0) 2007.11.27

[펌] mysql start & shutdown

프로그래밍/DB 2007. 11. 27. 15:08 Posted by galad

먼저 데이터베이스의 시작과은 다음과같은 방법으로 할 수가 있습니다.

MySQL이 설치되는 위치는 일반적으로 /usr/local/mysql/입니다.

그리고 MySQL관련 명령어들이 들어있는 디렉토리는 /usr/local/mysql/bin입니다.

이 디렉토리의 내용을 보면 다음과 같습니다.

여기서 Mysql데이터베이스를 기동하기 방법에는 여러 가지가 있지만 가장 일반적으로 사용하는 것은 "safe_mysql"입니다.

다음과 같은 방법으로 데이터베이스를 기동할 수 있습니다.

그리고 정상적으로 기동이 되어서 mysqld라는 데몬이 뜨있는지를 유닉스명령어인 ps로 확인해 본 것입니다.

mysql이 기동이 되고나면 보시는 바와 같이 4개의 데몬이 뜨있어야만 정상적으로 작동하게 됩니다.

 

 

Mysql 데이터베이스의 종료

이 디렉토리에 존재하는 mysqladmin이라는 명령어를 사용하여 데이터베이스를 다음과 같이 종료할 수 있습니다.

 

그리고 다음과 같이 다시한번 ps로 확인을 해보면 mysql관련 데몬들이 모두 종료된 것을 알 수 있습니다.

 

 

Mysql 데이터베이스의 재시작

다음과 같이 데이터베이스를 재시작 하기위해서는 mysqladmin이라는 데이터베이스 관리자명령어로 할 수가 있습니다.

아무런 메시지 없이 쉘프롬프트가 떨어지면 정상적으로 재시작이 되었다는 것을 의미합니다.

[펌] 계정 생성 및 권한부여

프로그래밍/DB 2007. 11. 27. 15:08 Posted by galad
계정 생성 및 권한부여
-출처 : 근사모
## MySQL 계정 생성하기

MySQL 의 계정을 생성하는 방법에 대해서 알아 보도록 하겠습니다.

일단 MySQL 콘솔로 접속해야 겠죠 ?
콘솔로 접속하기 위해서 MySQL 의 bin 디렉토리로 이동합니다.

리눅스 라면 기본적으로 /usr/local/mysql/bin 디렉토리이고
윈도우의 APM_Setup 이라면 APM_Setup\Server\MySQL\bin 디렉토리 일 것 입니다.

이젠 MySQL 에 접속해 볼까요 ?

mysql -uroot -p


의 명령으로 MySQL 콘솔 모드로 접속합니다.
Password 를 물어 보면 root 패스워드를 입력해야 겠죠 ?

그럼..

이제 생성할 계정이 사용할 데이터베이스를 추가해야 겠죠 ?
데이터 베이스 추가 명령은

CREATE DATABASE [IF NOT EXISTS] db_name


이런식의 SQL 문 입니다.

그럼 많은 사람들이 제로보드를 사용하니 zboard 를 만들어 보겠습니다. 그러면

CREATE DATABASE IF NOT EXISTS zboard;


이렇게 입력합니다.
그럼 zboard 디비가 추가 되겠죠!

이제 MySQL 계정을 만들어 볼까요 ?

먼저 계정 생성 SQL 문 먼저 알아 볼까요 ?

GRANT USAGE ON *.* TO 사용자ID@접속호스트 IDENTIFIED BY "패스워드"


이렇게 구성되어 있습니다.

그럼 호스트는 localhost 사용자 ID 는 zboard 패스워드는 password
추가 하시려면..

GRANT USAGE ON *.* TO zboard@localhost IDENTIFIED
BY "password";


위와 같은 SQL 문이되겠죠 ?

이젠.. 위에서 생성한 데이터 베이스의 사용권한을 부여해야 겠죠..

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON
db_name TO 사용자ID@접속호스트


이런 명령으로 이루어져 있습니다.

그럼 호스트는 localhost 사용자 ID 는 zboard 데이터 베이스 이름은
zboard 라고 한다면..

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON
zboard.* TO zboard@localhost;


이렇게 되겠네욤..

이제 설정을 다시 했으니 권한을 다시 로드 해야 하므로

FLUSH PRIVILEGES;


SQL 문을 입력해 주면.. 되겠죵..

이제 종료 하시고...

만든 계정으로 MySQL 에 접속해 볼까욤

mysql -uzboard -p zboard


이런 명령으로 접속하시면 됩니다.
패스워드를 물어 보면 계정의 패스워드를 입력하시면 됩니다.

객체직렬화를 통해 직렬화된 객체를 Oracle BLOB에 저장하기


자바의 객체직렬화를 이용하면 직렬화된 객체를 파일, 데이터베이스 또는 원격으로 전송 하는 것이 가능 합니다.


물론 객체직렬화가 되기 위해선 Object는 자바의 Seriablizable 이라는 Interface를 구현해야 합니다. 그래서 이 Object는 Byte Stream 형태로 저장 되어 파일이나 DB에 저장 된 후 나중에 Load되어서 복원이 가능 하게 되는 것입니다.


아래의 예제는 ObjectSerTest 라는 클래스를 직렬화 가능하게 만든 후 오라클의 BLOB에  입력 한 후 읽어내는 예제 입니다.



=====================================================


SQL>conn scott/tiger
SQL> create sequence object_ser_seq increment by 1 start with 1;


주문번호가 생성되었습니다.


SQL> create table object_table (
  2  no number,
  3  obj_name varchar2(2000),
  4  obj_value blob default empty_blob()
  5  );


테이블이 생성되었습니다.


=================================================



/*
* Created on 2005. 2. 11
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package jdbc;


import java.io.*;
import java.sql.*;
import oracle.sql.*;


class ObjectSerTest implements java.io.Serializable{


  static final String driver_class = "oracle.jdbc.driver.OracleDriver";
  static final String connectionURL = "jdbc:oracle:thin:@localhost:1521:wink";
  static final String userID = "scott";
  static final String userPassword = "tiger";
  static final String getSequenceSQL = "SELECT object_ser_seq.nextval FROM dual";
  static final String writeObjSQL    = "BEGIN " +
                                       "  INSERT INTO object_table(no, obj_name, obj_value) " +
                                       "  VALUES (?, ?, empty_blob()) " +
                                       "  RETURN obj_value INTO ?; " +
                                       "END;";
  static final String readObjSQL     = "SELECT obj_value FROM object_table WHERE no = ?";


  /*
   ** +--------------------------------------------------+
   ** | METHOD: writeObj                                 |
   ** +--------------------------------------------------+
  */
  public static long writeObj(Connection conn, Object obj) throws Exception {


    long id = getNextSeqVal(conn);
   
    String className = obj.getClass().getName();
    CallableStatement stmt = conn.prepareCall(writeObjSQL);
   
    stmt.setLong(1, id);
    stmt.setString(2, className);   
    stmt.registerOutParameter(3, java.sql.Types.BLOB);
    stmt.executeUpdate();
   
    BLOB blob = (BLOB) stmt.getBlob(3);
    OutputStream os = blob.getBinaryOutputStream();
    ObjectOutputStream oop = new ObjectOutputStream(os);
    oop.writeObject(obj);
    oop.flush();
    oop.close();
    os.close();
    stmt.close();
    System.out.println("Done serializing: " + className);
    return id;


  } // END: writeObj



  /*
   ** +--------------------------------------------------+
   ** | METHOD: readObj                                  |
   ** +--------------------------------------------------+
  */
  public static Object readObj(Connection conn, long id) throws Exception {


    PreparedStatement stmt = conn.prepareStatement(readObjSQL);
    stmt.setLong(1, id);
    ResultSet rs = stmt.executeQuery();
    rs.next();
    InputStream is = rs.getBlob(1).getBinaryStream();
    ObjectInputStream oip = new ObjectInputStream(is);
    Object obj = oip.readObject();
    String className = obj.getClass().getName();
    oip.close();
    is.close();
    stmt.close();
    System.out.println("Done de-serializing: " + className);
    return obj;


  } // END: readObj


  /*
   ** +--------------------------------------------------+
   ** | METHOD: getNextSeqVal                            |
   ** +--------------------------------------------------+
  */
  private static long getNextSeqVal (Connection conn) throws SQLException {


    Statement stmt = conn.createStatement();
    ResultSet rs   = stmt.executeQuery(getSequenceSQL);
    rs.next();
    long id = rs.getLong(1);
    rs.close();
    stmt.close();
    return id;


  } // END: getNextSeqVal


  /*
   ** +--------------------------------------------------+
   ** | METHOD: main                                     |
   ** +--------------------------------------------------+
  */
  public static void main (String args[]) throws SQLException {


    Connection conn = null;
    Statement stmt = null;
    ResultSet rset = null;
    int insertResults;
    int deleteResults;


    try {
    
      System.out.print("\n");
      System.out.print("Loading JDBC Driver  -> " + driver_class + "\n");
      Class.forName (driver_class).newInstance();


      /*
      ** CONNECT TO THE DATABASE
      */
      System.out.print("Connecting to        -> " + connectionURL + "\n");
      conn = DriverManager.getConnection(connectionURL, userID, userPassword);
      System.out.print("Connected as         -> " + userID + "\n\n");


      /*
      ** TURN OFF AutoCommit
      */
      conn.setAutoCommit(false);


      ObjectSerTest obj = new ObjectSerTest();     


      long no = writeObj(conn, obj);
      conn.commit();


      System.out.print("Serialized OBJECT_ID => " + no + "\n\n");


      System.out.print("OBJECT VALUES  => " + readObj(conn, no) + "\n\n");
      conn.close();


    }  // TRY:


    catch (Exception e) {
      e.printStackTrace();
    }


    finally {
      if (conn != null) {
        try {
          System.out.print("Closing down all connections...\n\n");
          conn.close();
객체직렬화를 통해 직렬화된 객체를 Oracle BLOB에 저장하기



자바와 오라클 개발자 전문가과정





자바의 객체직렬화를 이용하면 직렬화된 객체를 파일, 데이터베이스 또는 원격으로 전송 하는 것이 가능 합니다.


물론 객체직렬화가 되기 위해선 Object는 자바의 Seriablizable 이라는 Interface를 구현해야 합니다. 그래서 이 Object는 Byte Stream 형태로 저장 되어 파일이나 DB에 저장 된 후 나중에 Load되어서 복원이 가능 하게 되는 것입니다.


아래의 예제는 ObjectSerTest 라는 클래스를 직렬화 가능하게 만든 후 오라클의 BLOB에  입력 한 후 읽어내는 예제 입니다.



=====================================================


SQL>conn scott/tiger
SQL> create sequence object_ser_seq increment by 1 start with 1;


주문번호가 생성되었습니다.


SQL> create table object_table (
  2  no number,
  3  obj_name varchar2(2000),
  4  obj_value blob default empty_blob()
  5  );


테이블이 생성되었습니다.


=================================================



/*
* Created on 2005. 2. 11
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package jdbc;


import java.io.*;
import java.sql.*;
import oracle.sql.*;


class ObjectSerTest implements java.io.Serializable{


  static final String driver_class = "oracle.jdbc.driver.OracleDriver";
  static final String connectionURL = "jdbc:oracle:thin:@localhost:1521:wink";
  static final String userID = "scott";
  static final String userPassword = "tiger";
  static final String getSequenceSQL = "SELECT object_ser_seq.nextval FROM dual";
  static final String writeObjSQL    = "BEGIN " +
                                       "  INSERT INTO object_table(no, obj_name, obj_value) " +
                                       "  VALUES (?, ?, empty_blob()) " +
                                       "  RETURN obj_value INTO ?; " +
                                       "END;";
  static final String readObjSQL     = "SELECT obj_value FROM object_table WHERE no = ?";


  /*
   ** +--------------------------------------------------+
   ** | METHOD: writeObj                                 |
   ** +--------------------------------------------------+
  */
  public static long writeObj(Connection conn, Object obj) throws Exception {


    long id = getNextSeqVal(conn);
   
    String className = obj.getClass().getName();
    CallableStatement stmt = conn.prepareCall(writeObjSQL);
   
    stmt.setLong(1, id);
    stmt.setString(2, className);   
    stmt.registerOutParameter(3, java.sql.Types.BLOB);
    stmt.executeUpdate();
   
    BLOB blob = (BLOB) stmt.getBlob(3);
    OutputStream os = blob.getBinaryOutputStream();
    ObjectOutputStream oop = new ObjectOutputStream(os);
    oop.writeObject(obj);
    oop.flush();
    oop.close();
    os.close();
    stmt.close();
    System.out.println("Done serializing: " + className);
    return id;


  } // END: writeObj



  /*
   ** +--------------------------------------------------+
   ** | METHOD: readObj                                  |
   ** +--------------------------------------------------+
  */
  public static Object readObj(Connection conn, long id) throws Exception {


    PreparedStatement stmt = conn.prepareStatement(readObjSQL);
    stmt.setLong(1, id);
    ResultSet rs = stmt.executeQuery();
    rs.next();
    InputStream is = rs.getBlob(1).getBinaryStream();
    ObjectInputStream oip = new ObjectInputStream(is);
    Object obj = oip.readObject();
    String className = obj.getClass().getName();
    oip.close();
    is.close();
    stmt.close();
    System.out.println("Done de-serializing: " + className);
    return obj;


  } // END: readObj


  /*
   ** +--------------------------------------------------+
   ** | METHOD: getNextSeqVal                            |
   ** +--------------------------------------------------+
  */
  private static long getNextSeqVal (Connection conn) throws SQLException {


    Statement stmt = conn.createStatement();
    ResultSet rs   = stmt.executeQuery(getSequenceSQL);
    rs.next();
    long id = rs.getLong(1);
    rs.close();
    stmt.close();
    return id;


  } // END: getNextSeqVal


  /*
   ** +--------------------------------------------------+
   ** | METHOD: main                                     |
   ** +--------------------------------------------------+
  */
  public static void main (String args[]) throws SQLException {


    Connection conn = null;
    Statement stmt = null;
    ResultSet rset = null;
    int insertResults;
    int deleteResults;


    try {
    
      System.out.print("\n");
      System.out.print("Loading JDBC Driver  -> " + driver_class + "\n");
      Class.forName (driver_class).newInstance();


      /*
      ** CONNECT TO THE DATABASE
      */
      System.out.print("Connecting to        -> " + connectionURL + "\n");
      conn = DriverManager.getConnection(connectionURL, userID, userPassword);
      System.out.print("Connected as         -> " + userID + "\n\n");


      /*
      ** TURN OFF AutoCommit
      */
      conn.setAutoCommit(false);


      ObjectSerTest obj = new ObjectSerTest();     


      long no = writeObj(conn, obj);
      conn.commit();


      System.out.print("Serialized OBJECT_ID => " + no + "\n\n");


      System.out.print("OBJECT VALUES  => " + readObj(conn, no) + "\n\n");
      conn.close();


    }  // TRY:


    catch (Exception e) {
      e.printStackTrace();
    }


    finally {
      if (conn != null) {
        try {
          System.out.print("Closing down all connections...\n\n");
          conn.close();
        }
        catch (SQLException e) {
          e.printStackTrace();
        }
      }
    } // FINALLY:


  } // METHOD: main


} // CLASS: ObjectSerTest




[결과]



Loading JDBC Driver  -> oracle.jdbc.driver.OracleDriver
Connecting to        -> jdbc:oracle:thin:@localhost:1521:wink
Connected as         -> scott


Done serializing: jdbc.ObjectSerTest
Serialized OBJECT_ID => 2


Done de-serializing: jdbc.ObjectSerTest
OBJECT VALUES  => jdbc.ObjectSerTest@601bb1


Closing down all connections...
        }
        catch (SQLException e) {
          e.printStackTrace();
        }
      }
    } // FINALLY:


  } // METHOD: main


} // CLASS: ObjectSerTest




[결과]



Loading JDBC Driver  -> oracle.jdbc.driver.OracleDriver
Connecting to        -> jdbc:oracle:thin:@localhost:1521:wink
Connected as         -> scott


Done serializing: jdbc.ObjectSerTest
Serialized OBJECT_ID => 2


Done de-serializing: jdbc.ObjectSerTest
OBJECT VALUES  => jdbc.ObjectSerTest@601bb1


Closing down all connections...

'프로그래밍 > DB' 카테고리의 다른 글

[펌] mysql start & shutdown  (0) 2007.11.27
[펌] 계정 생성 및 권한부여  (0) 2007.11.27
[펌] Oracle - PL/SQL  (0) 2007.11.27
[펌] PL/SQL 조건문 만들기  (0) 2007.11.27
[펌] 오라클자료 - PL/SQL  (0) 2007.11.27

[펌] Oracle - PL/SQL

프로그래밍/DB 2007. 11. 27. 14:34 Posted by galad
출처 블로그 > 과거,현재 그리고 미래
원본 http://blog.naver.com/geerark/100005573550
Oracle - PL/SQL


PLSQL 이란?


PL/SQL 이란 ?

 
- PL/SQL 은 Oracle's Procedural Language extension to SQL. 의 약자 입니다.

 - SQL문장에서 변수정의, 조건처리(IF), 반복처리(LOOP, WHILE, FOR)등을 지원하며,
   오라클 자체에 내장되어 있는 Procedure Language입니다

 - DECLARE문을 이용하여 정의되며, 선언문의 사용은 선택 사항입니다.  

 - PL/SQL 문은 블록 구조로 되어 있고 PL/SQL 자신이 컴파일 엔진을 가지고 있습니다.



PL/SQL의 장점

 - PL/SQL 문은 BLOCK 구조다수의 SQL 문을 한번에 ORACLE DB 로 보내서 처리하므로
   수행속도를 향상 시킬수 있습니다.

 - PL/SQL 의 모든 요소는 하나 또는 두개이상의 블록으로 구성하여 모듈화가 가능하다.

 - 보다 강력한 프로그램을 작성하기 위해서 큰 블록안에 소블럭을 위치시킬 수 있습니다.

 - Variable, Constant, Cursor, Exception을 정의하고, SQL문장과 Procedural 문장에서
   사용합니다. .

 - 단순, 복잡한 데이터형태의 변수를 선언합니다.

 - 테이블의 데이터 구조와 DataBase의 컬럼럼에 준하여 동적으로 변수를 선언 할 수 있습니다.

 - Exception 처리 루틴을 이용하여 Oracle Server Error를 처리합니다.

 - 사용자 정의 에러를 선언하고 Exception 처리 루틴으로 처리 가능 합니다.


PL/SQL Block 구조


PL/SQL Block Structure

 - PL/SQL은 프로그램을 논리적인 블록으로 나누는 구조화된 블록 언어 입니다.

 - PL/SQL 블록은 선언부(선택적), 실행부(필수적),예외 처리부(선택적)로 구성되어 있고,  
   BEGIN과 END 키워드는 반드시 기술해 주어야 합니다.

 - PL/SQL 블록에서 사용하는 변수는 블록에 대해 논리적으로 선언할 수 있고 사용할 수 있습니다.

 

● DECLARE
    - Optional
    - Variables, cursors, user-defined exceptions

● BEGIN
    - Mandatory
    - SQL Statements
    - PL/SQL Statements

● EXCEPTION
    - Actions to perform when errors occur

● END;
    - Mandatory



  ◈ Declarative Section(선언부)

   -  변수, 상수, CURSOR, USER_DEFINE Exception선언


  ◈ Executable Section(실행부)

   -  SQL, 반복분, 조건문실행
   -  실행부는 BEGIN으로 시작하고 END 로 끝납니다.
   -  실행문은 프로그램 내용이 들어가는 부분으로서 필수적으로 사용되어야 합니다.


  ◈ Exception Handling Section(예외처리)

    - 예외에 대한 처리.
    - 일반적으로 오류를 정의하고 처리하는 부분으로 선택 사항입니다.



PL/SQL 프로그램의 작성 요령

 
 - PL/SQL 블록내에서는 한 문장이 종료할 때마다 세미콜론(;)을 사용합니다. .

  - END뒤에 ;을 사용하여 하나의 블록이 끝났다는 것을 명시 합니다.

  - PL/SQL 블록의 작성은 편집기를 통해 파일로 작성할 수도 있고,
    SQL프롬프트에서 바로 작성할 수도 있습니다.

  - SLQ*PLUS환경에서는 DELCLARE나 BEGIN이라는 키워드로 PL/SQL블럭이 시작하는 것을
    알 수 있습니다.

 - 단일행 주석 : --

 - 여러행 주석 : /* */

 - PL/SQL 블록은 행에 / 가있으면 종결 됩니다.
 


PL/SQL 블럭의 유형


Block Type(PL/SQL 블럭의 유형)

 
[ Anonymous ]

 
[ Procedure ]

 
[ Function ]



 ◈ Anonymous Block(익명 블록)
 
    이름이 없는 블록을 의미 합니다.
    실행하기 위해 프로그램 안에서 선언되고 실행 시에 실행을 위해 PL/SQL 엔진으로 전달됩니다.
    선행 컴파일러 프로그램과 SQL*Plus 또는 서버 관리자에서 익명의 블록을 내장할 수 있습니다.
 
   
 ◈ Procedure(프로시저)
   
    특정 작업을 수행할수 있는 이름이 있는 PL/SQL 블록으로서.
    매개 변수를 받을수 있고.. 반복적으로 사용할수 있는거죠..
    보통 연속 실행 또는 구현이 복잡한 트랜잭션을 수행하는 PL/SQL블록을
    데이터 베이스에 저장하기 위해 생성합니다.
 
 
 ◈ Function(함수)
 
    보통 값을 계산하고 결과값을 반환하기 위해서 함수를 많이 사용 합니다.
    대부분 구성이 프로시저와 유사하지만 IN 파라미터만 사용 할 수 있고,
    반드시 반환될 값의 데이터 타입을 RETURN문에 선언해야 합니다.
    또한 PL/SQL블록 내에서 RETURN문을 통해서 반드시 값을 반환해야 합니다.


프로시저(PROCEDURE)


프로시져란..


특정 작업을 수행할수 있고, 이름이 있는 PL/SQL 블록으로서. 매개 변수를 받을수
있고.. 반복적으로 사용
할수 있는거죠.. 보통 연속 실행 또는 구현이 복잡한 트랜잭션을 수행하는
PL/SQL블록을 데이터 베이스에 저장하기 위해 생성합니다.

CREATE OR REPLACE 구문을 사용하여 생성합니다.
IS 로 PL/SQL의 블록을 시작합니다.
LOCAL 변수는 IS 와 BEGIN 사이에 선언합니다.
 

    [Syntax]

    CREATE OR REPLACE procedure name
       IN argument
       OUT argument
       IN OUT argument

    IS

       [변수의 선언]

    BEGIN  
    --> 필수

       [PL/SQL Block]
       -- SQL문장, PL/SQL제어 문장

       [EXCEPTION]  --> 선택
      -- error가 발생할 때 수행하는 문장

    END;   --> 필수


프로시저 작성 예제

SQL>CREATE OR REPLACE PROCEDURE update_sal
        /* IN  Parameter */
        (v_empno         IN    NUMBER)
        
       IS

       BEGIN

       UPDATE emp
       SET sal = sal  * 1.1
       WHERE empno = v_empno;

       COMMIT;

       END update_sal;
       /

 프로시져가 생성되었습니다.


설명..
프로시저의 이름은 update_sal이고..
프로시저 update_sal은 사번(v_empno)를 입력받아서 급여를 update시켜주는 sql문입니다.
프로시저를 끝마칠때에는 항상 "/"를 지정 합니다.

프로시저의 실행
EXECUTE 문을 이용해 프로시저를 실행합니다.

SQL> execute update_sal(7369);
 
PL/SQL 처리가 정상적으로 완료되었습니다.

7369번 사원의 급여가 10% 인상됐습니다.
SELECT 문을 실행시켜보면 데이터가 수정된 것을 확인할수 있습니다.



Parameter란
 
실행 환경과 program사이에 값을 주고 받는 역할을 합니다.

 
블록 안에서의 변수와 똑같이 일시적으로 값을 저장하는 역할을 합니다.

 
function에서는 IN만 있고, OUT과, INOUT는 사용하지 않습니다.

 
Parameter의 타입
    - IN :  실행환경에서 program으로 값을 전달
    - OUT : program에서 실행환경으로 값을 전달
    - INOUT : 실행환경에서 program으로 값을 전달하고,
                  다시 program에서 실행환경으로 변경된 값을 전달
.
 


함수(FUNCTION)


 ◈ 함수(Function)

 - 보통 값을 계산하고 결과값을 반환하기 위해서 함수를 많이 사용 합니다.

 - 대부분 구성이 프로시저와 유사 하지만 IN 파라미터만 사용 할 수 있습니다.

 - 반드시 반환될 값의 데이터 타입을 RETURN문에 선언해야 합니다.

 - 또한 PL/SQL블록 내에서 RETURN문을 통해서 반드시 값을 반환해야 합니다.
 


[Syntax]

CREATE OR REPLACE FUNCTION function name
  [(argument...)]
  RETURN  datatype
    -- Datatype은 반환되는 값의 datatype입니다.

IS

   [변수 선언 부분]

BEGIN

  [PL/SQL Block]

    -- PL/SQL 블록에는 적어도 한 개의 RETURN 문이 있어야 합니다.
    -- PL/SQL Block은 함수가 수행할 내용을 정의한 몸체부분입니다.

END;
 



SQL> CREATE OR REPLACE FUNCTION FC_update_sal
         (v_empno         IN    NUMBER)

          -- 리턴되는 변수의 데이터타입을 꼭 정의해야 합니다
          RETURN NUMBER  .

        IS

        v_sal  emp.sal%type;

        BEGIN

        UPDATE emp
        SET sal  = sal  * 1.1
        WHERE empno  = v_empno;
   
        COMMIT;
 
        SELECT sal
        INTO v_sal
        FROM emp
        WHERE empno = v_empno;

        -- 리턴문이 꼭 존재해야 합니다
        RETURN v_sal;

       END;

함수가 생성되었습니다.
 



설명..

이 함수에는 v_sal이라는 %type 변수가 사용되고 있습니다.
스칼라 데이터 타입을 참고하세요.
프로지저와 마찬가지로 세미콜론(;)으로 블록을 종료한 뒤 "/"를 붙여 코드를 끝마칩니다.


함수의 실행

먼저 함수의 반환값을 저장할 변수를 선언합니다.

SQL> VAR salary NUMBER;


EXECUTE 문을 이용해 함수를 실행합니다.
SQL>EXECUTE :salary := FC_update_sal(7900);

PL/SQL 처리가 정상적으로 완료되었습니다.


오라클 SQL에서 선언된 변수의 출력은 PRINT문을 사용합니다.
PRINT문으로 함수의 반환값을 저장한 salary의 값을 확인하면 됩니다.

SQL>PRINT salary;
 
    SALARY
----------
      1045

결과가 이렇게 나옵니다.
 


스칼라 데이터 타입

변수 선언 방법






Identifier의 이름은 sql의 object명과 동일한 규칙을 따릅니다.

Identifier를 상수로 지정하고 싶은 경우는 CONSTANT라는 KEYWORD를 명시하고
    반드시 초기화를 할당합니다.

NOT NULL이 정의되어 있으면 초기값을 반드시 지정하고,
    정의되어 있지 않을 때는 생략 가능합니다.

초기값은 할당 연산자(:=)를 사용하여 정의 합니다.

초기값을 정의하지 않으면 Identifier는 NULL값을 가지게 됩니다.

일반적으로 한줄에 한 개의 Identifier를 정의 합니다.
 


스칼라 데이터 타입은 단수 데이터형으로 한가지의 데이터 값만 가집니다.
 

BINARY_INTEGER

-2147483647에서 2147483647 사이의 정수

NUMBER[(P, S)]

고정 및 부동 소숫점 수에 대한 기본 유형

CHAR[(최대길이)]

32767바이트까지의 고정길이 문자 데이터에 대한 기본 유형으로 최대길이를 명시하지 않으면 기본적으로 길이는 1로 설정

LONG

32760바이트까지의 가변길이 문자 데이타

VARCHAR2(최대길이)

32767바이트까지의 가변길이 문자 데이타

DATE

날짜와 시각에 대한 기본 유형

BOOLEAN

논리연산에 사용되는 세 가지 값(TRUE, FALSE, NULL) 중 하나를 저장 하는 기본 유형


선언 예제
v_price CONTANT NUMBER(4,2) := 12.34 ;     -- 상수 숫자 선언(변할 수 없다)

v_name VARCHAR22(20) ;

v_Bir_Type   CHAR(1) ;

v_flag   BOOLEAN  NOT NULL := TRUE ;      -- NOT NULL 값 TRUE로 초기화

v_birthday DATE;



%TYPE 데이터형


%TYPE 데이터형은 기술한 데이터베이스 테이블의 컬럼 데이터 타입을 모를 경우 사용할 수 있고,

또. 코딩이후 데이터베이스 컬럼의 데이터 타입이 변경될 경우 다시 수정할 필요가 없습니다.

이미 선언된 다른 변수나 데이터베이스 컬럼의 데이터 타입을 이용하여 선언합니다.

 데이터 베이스 테이블과 컬럼 그리고 이미 선언한 변수명이 %TYPE앞에 올수 있습니다.


%TYPE 속성을 이용하여 얻을 수 있는 장점
   - 기술한 DB column definition을 정확히 알지 못하는 경우에 사용할 수 있습니다.
   - 기술한 DB column definition이 변경 되어도 다시 PL/SQL을 고칠 필요가 없습니다.
 

예제
v_empno  emp.empno%TYPE := 7900 ;
v_ename emp.ename%TYPE;
 

예제 프로시져..

SQL>CREATE OR REPLACE PROCEDURE Emp_Info
      -- IN Parameter
      ( p_empno IN emp.empno%TYPE )

        IS

        -- %TYPE 데이터형 변수 선언
        v_empno emp.empno%TYPE;
        v_ename emp.ename%TYPE;
        v_sal   emp.sal%TYPE;

        BEGIN

        DBMS_OUTPUT.ENABLE;

        -- %TYPE 데이터형 변수 사용
        SELECT empno, ename, sal
        INTO v_empno, v_ename, v_sal  
        FROM emp
        WHERE empno = p_empno ;

        -- 결과값 출력
        DBMS_OUTPUT.PUT_LINE( '사원번호 : ' || v_empno );
        DBMS_OUTPUT.PUT_LINE( '사원이름 : ' || v_ename );
        DBMS_OUTPUT.PUT_LINE( '사원급여 : ' || v_sal );

        END;
       /


프로시져가 생성되었습니다.

SQL>SET SERVEROUTPUT ON;     --  DBMS_OUTPUT 결과값을 화면에 출력 하기위해


실행 결과
SQL> EXECUTE Emp_Info(7369);

사원번호 : 7369
사원이름 : SMITH
사원급여 : 880
 
PL/SQL 처리가 정상적으로 완료되었습니다.
 


%ROWTYPE


하나 이상의 데이터값을 갖는 데이터 타입으로 배열과 비슷한 역할을 하고 재사용이 가능합니다.
%ROWTYPE데이터 형과, PL/SQL테이블과 레코드가 복합 데이터 타입에 속합니다.


%ROWTYPE


 테이블이나 뷰 내부의 컬럼 데이터형, 크기, 속석등을 그대로 사용할수 있습니다.

 %ROWTYPE 앞에 오는 것은 데이터 베이스 테이블 이름입니다.

 지정된 테이블의 구조와 동일한 구조를 갖는 변수를 선언할수 있습니다.

 데이터베이스 컬럼들의 수나 DATATYPE을 알지 못할 때 편리 합니다.

 테이블의 데이터 컬럼의 DATATYPE이 변경될 경우 프로그램을 재수정할 필요가 없습니다.  
 
 


%ROWTYPE 예제 프로시져..

SQL>CREATE OR REPLACE PROCEDURE RowType_Test
        ( p_empno IN emp.empno%TYPE )

    IS

        -- %ROWTYPE 변수 선언
        v_emp   emp%ROWTYPE ;

   BEGIN

        DBMS_OUTPUT.ENABLE;

        -- %ROWTYPE 변수 사용
        SELECT empno, ename, hiredate
        INTO v_emp.empno, v_emp.ename, v_emp.hiredate
        FROM emp
        WHERE empno = p_empno;

       DBMS_OUTPUT.PUT_LINE( '사원번호 : ' || v_emp.empno );
       DBMS_OUTPUT.PUT_LINE( '사원이름 : ' || v_emp.ename );
       DBMS_OUTPUT.PUT_LINE( '입 사 일 : ' || v_emp.hiredate );

   END;
        /

   프로시져가 생성되었습니다.



실행 결과

SQL> SET SERVEROUTPUT ON ;  -- DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용

SQL> EXECUTE RowType_Test(7900);

사원번호 : 7900
사원이름 : JAMES
입 사 일 : 81/12/03

PL/SQL 처리가 정상적으로 완료되었습니다.


PL/SQL 테이블


 
PL/SQL 에서의 테이블은 오라클 SQL에서의 테이블과는 다릅니다. PL/SQL에서의 테이블은
일종의 일차원 배열이라고 생각하시면 이해하기 쉬울겁니다.


테이블은 크기에 제한이 없으면 그 ROW의 수는 데이터가 들어옴에 따라 자동 증가 합니다.

BINARY_INTEGER 타입의인덱스 번호로 순서가 정해집니다.

하나의 테이블에 한 개의 컬럼 데이터를 저장 합니다.  
 




예제


TYPE prdname_table IS TABLE OF VARCHAR2(30)
INDEX BY BINARY_INTEGER;

--
prdname_table 테이블타입으로 prdname_tab변수를 선언해서 사용
prdname_tab   prdname_table ;
 



PL/SQL 테이블 예제 프로시져..

SQL>CREATE OR REPLACE PROCEDURE Table_Test
    (v_deptno IN emp.deptno%TYPE)

    IS

         -- 각 컬럼에서 사용할 테이블의 선언
         TYPE empno_table IS TABLE OF emp.empno%TYPE
         INDEX BY BINARY_INTEGER;

         TYPE ename_table IS TABLE OF emp.ename%TYPE
         INDEX BY BINARY_INTEGER;

         TYPE sal_table IS TABLE OF emp.sal%TYPE
         INDEX BY BINARY_INTEGER;

         -- 테이블타입으로 변수를 선언해서 사용
         empno_tab  empno_table ;
         
ename_tab  ename_table ;
         
sal_tab    sal_table;

         i BINARY_INTEGER := 0;

   BEGIN

         DBMS_OUTPUT.ENABLE;

         FOR emp_list IN(SELECT empno, ename, sal FROM emp WHERE deptno = v_deptno) LOOP

          /* emp_list는 자동선언되는 BINARY_INTEGER형 변수로 1씩 증가합니다.
           
emp_list대신 다른 문자열 사용가능 */

                i := i + 1;

               -- 테이블 변수에 검색된 결과를 넣습니다
                empno_tab(i) := emp_list.empno ;    
                ename_tab(i) := emp_list.ename ;
                sal_tab(i)   := emp_list.sal ;

          END LOOP;

          -- 1부터 i까지 FOR 문을 실행
          FOR cnt IN 1..i LOOP

             -- TABLE변수에 넣은 값을 뿌려줌
             DBMS_OUTPUT.PUT_LINE( '사원번호 : ' || empno_tab(cnt) );
             DBMS_OUTPUT.PUT_LINE( '사원이름 : ' || ename_tab(cnt) );
             DBMS_OUTPUT.PUT_LINE( '사원급여 : ' || sal_tab(cnt) );

          END LOOP;

  END;
  /

프로시져가 생성되었습니다.

실행 결과

SQL> SET SERVEROUTPUT ON ; -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)
SQL> EXECUTE Table_Test(10);

사원번호 : 7782
사원이름 : CLARK
사원급여 : 2450
사원번호 : 7839
사원이름 : KING
사원급여 : 5000
사원번호 : 7934
사원이름 : MILLER
사원급여 : 1300

PL/SQL 처리가 정상적으로 완료되었습니다.

 emp 테이블에 있는 데이터의 입력한 부서에 해당하는 사원번호, 사원이름, 사원급여를
 뿌려주는 프로시져 입니다


PLSQL 레코드

여러개의 데이터 타입을 갖는 변수들의 집합입니다.

스칼라, RECORD, 또는 PL/SQL TABLE datatype중 하나 이상의 요소로 구성됩니다.

논리적 단위로서 필드 집합을 처리할 수 있도록 해 줍니다.

PL/SQL 테이블과 다르게 개별 필드의 이름을 부여할 수 있고, 선언시 초기화가 가능합니다.
 

예제

  TYPE record_test IS RECORD
    ( record_empno   NUMBER,
      record_ename   VARCHAR2(30),
      record_sal        NUMBER);

      prd_record    record_test;


PL/SQL RECORD 예제 프로시져..

SQL> CREATE OR REPLACE PROCEDURE Record_Test
      ( p_empno IN emp.empno%TYPE )

     IS

         -- 하나의 레코드의 세가지의 변수타입 선언

         TYPE emp_record IS RECORD
         (v_empno    NUMBER,
          v_ename    VARCHAR2(30),
          v_hiredate  DATE );

         emp_rec   emp_record ;

   BEGIN

         DBMS_OUTPUT.ENABLE;

         -- 레코드의 사용
         SELECT empno, ename, hiredate
         INTO emp_rec.v_empno, emp_rec.v_ename, emp_rec.v_hiredate
         FROM emp
         WHERE empno = p_empno;

        DBMS_OUTPUT.PUT_LINE( '사원번호 : ' || emp_rec.v_empno );
        DBMS_OUTPUT.PUT_LINE( '사원이름 : ' || emp_rec.v_ename );
        DBMS_OUTPUT.PUT_LINE( '입 사 일 : ' || emp_rec.v_hiredate );

   END;
 /


프로시져가 생성되었습니다.


실행 결과
SQL> SET SERVEROUTPUT ON ;  
-- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

SQL> EXECUTE Record_Test(7369);

사원번호 : 7369
사원이름 : SMITH
입 사 일 : 80/12/17

PL/SQL 처리가 정상적으로 완료되었습니다.

 %ROWTYPE예제와 비교해 보세요


PL/SQL Table of Record

⊙ PL/SQL TABLE변수 선언과 비슷하며 데이터타입을 %ROWTYPE으로 선언하면 됩니다.
PL/SQL TABLE과 RECORD의 복합 기능을 합니다.

 



DECLARE

TYPE dept_table_type IS TABLE OF dept%ROWTYPE
INDEX BY BINARY_INTEGER;

-- Each element of dept_table  is a record
dept_table   dept_table_type ;
 



PL/SQL TABLE OF RECORD 예제 프로시져..

CREATE OR REPLACE PROCEDURE Table_Test
IS
        i BINARY_INTEGER := 0;
 
     -- PL/SQL Table of Record의 선언
    TYPE dept_table_type IS TABLE OF dept%ROWTYPE
     INDEX BY BINARY_INTEGER;
 
     dept_table dept_table_type;
 
BEGIN
 
 
    FOR dept_list IN (SELECT * FROM dept) LOOP
 
                i:= i+1;
 
        -- TABLE OF RECORD에 데이터 보관
        dept_table(i).deptno := dept_list.deptno ;    
        dept_table(i).dname := dept_list.dname ;
        dept_table(i).loc   := dept_list.loc ;
 
    END LOOP;
 
 
    FOR cnt IN 1..i LOOP
 
     -- 데이터 출력
     DBMS_OUTPUT.PUT_LINE( '부서번호 : ' || dept_table(cnt).deptno ||
                                          '부서명 : ' ||  dept_table(cnt).dname ||
                                          '위치 : ' || dept_table(cnt).loc );
 
    END LOOP;
 
 END;
/
 
 
SQL>set serveroutput on;
SQL>exec Table_test;
부서번호 : 10부서명 : ACCOUNTING위치 : NEW_YORK
부서번호 : 20부서명 : RESEARCH위치 : DALLAS
부서번호 : 30부서명 : 인사과위치 : CHICAGO
부서번호 : 40부서명 : OPERATIONS위치 : BOS%TON
 
PL/SQL 처리가 정상적으로 완료되었습니다.
 


INSERT

PL/SQL에서의 INSERT 문은 SQL과 비슷합니다.
 

사원 등록 예제 프로시져..

SQL> CREATE OR REPLACE PROCEDURE Insert_Test
        ( v_empno  IN emp.empno%TYPE,
          v_ename  IN emp.ename%TYPE,
          v_deptno IN emp.deptno%TYPE )

        IS

      BEGIN

          DBMS_OUTPUT.ENABLE;
   
          INSERT INTO emp(empno, ename, hiredate, deptno)
          VALUES(v_empno, v_ename, sysdate, v_deptno);

          DBMS_OUTPUT.PUT_LINE( '사원번호 : ' || v_empno );
          DBMS_OUTPUT.PUT_LINE( '사원이름 : ' || v_ename );
          DBMS_OUTPUT.PUT_LINE( '사원부서 : ' || v_deptno );
          DBMS_OUTPUT.PUT_LINE( '데이터 입력 성공 ' );

       END ;
      /           

프로시져가 생성되었습니다.


실행 결과
SQL> SET SERVEROUTPUT ON ;  
-- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

SQL>  EXECUTE Insert_Test(1000, 'brave', 20);

사원번호 : 1000
사원이름 : brave
사원부서 : 20
데이터 입력 성공

PL/SQL 처리가 정상적으로 완료되었습니다.
 


UPDATE

상품 수정 예제 프로시저..
※ 특정 사원의 급여를 일정%센트 인상/인하하는 프로시져


SQL>CREATE OR REPLACE PROCEDURE Update_Test
       ( v_empno IN    emp.empno%TYPE,       -- 급여를 수정한 사원의 사번
         v_rate    IN    NUMBER )                     -- 급여의 인상/인하율

         IS

         -- 수정 데이터를 확인하기 위한 변수 선언
         v_emp  emp%ROWTYPE ;

         BEGIN

         DBMS_OUTPUT.ENABLE;

         UPDATE emp
         SET sal = sal+(sal * (v_rate/100))   -- 급여를 계산
         WHERE empno = v_empno ;

         DBMS_OUTPUT.PUT_LINE( '데이터 수정 성공 ' );

         -- 수정된 데이터 확인하기 위해 검색
         SELECT empno, ename, sal
         INTO v_emp.empno, v_emp.ename, v_emp.sal
         FROM emp
         WHERE empno = v_empno ;

         DBMS_OUTPUT.PUT_LINE( ' **** 수 정 확 인 **** ');
         DBMS_OUTPUT.PUT_LINE( '사원번호 : ' || v_emp.empno );
         DBMS_OUTPUT.PUT_LINE( '사원이름 : ' || v_emp.ename );
         DBMS_OUTPUT.PUT_LINE( '사원급여 : ' || v_emp.sal );

         END ;
         /

프로시저가 생성되었습니다.

프로시저 실행
SQL> SET SERVEROUTPUT ON ;  -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

SQL> EXECUTE Update_Test(7900, -10);

데이터 수정 성공
**** 수 정 확 인 ****
사원번호 : 7900
사원이름 : JAMES
사원급여 : 855

PL/SQL 처리가 정상적으로 완료되었습니다.

7900번 사원의 급여를 10% 인하했습니다.


DELETE

사원 삭제 예제 프로시저..

SQL> CREATE OR REPLACE PROCEDURE Delete_Test
    ( p_empno IN  emp.empno%TYPE )

        IS

        -- 삭제 데이터를 확인하기 레코드 선언
        TYPE del_record IS  RECORD
        ( v_empno      emp.empno%TYPE,
          v_ename      emp.ename%TYPE,
          v_hiredate    emp.hiredate%TYPE) ;

          v_emp  del_record ;

        BEGIN

        DBMS_OUTPUT.ENABLE;

         -- 삭제된 데이터 확인용 쿼리
         SELECT empno, ename, hiredate
         INTO v_emp.v_empno, v_emp.v_ename, v_emp.v_hiredate
         FROM emp
         WHERE empno = p_empno ;

        DBMS_OUTPUT.PUT_LINE( '사원번호 : ' || v_emp.v_empno );
        DBMS_OUTPUT.PUT_LINE( '사원이름 : ' || v_emp.v_ename );
        DBMS_OUTPUT.PUT_LINE( '입 사 일 : ' || v_emp.v_hiredate );

        -- 삭제 쿼리
        DELETE
        FROM emp
        WHERE empno = p_empno ;

        DBMS_OUTPUT.PUT_LINE( '데이터 삭제 성공 ' );

       END;
 /

프로시저가 생성되었습니다.


프로시저 실행 (결과화면)
SQL> SET SERVEROUTPUT ON ;  
-- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

SQL> EXECUTE Delete_Test(7900);
사원번호 : 7900
사원이름 : JAMES
입 사 일 : 81/12/03
데이터 삭제 성공

 
PL/SQL 처리가 정상적으로 완료되었습니다.

※ 7900사원을 삭제했습니다.


FOR LOOP

FOR LOOP문



  -  index 는 자동 선언되는 binary_integer 형 변수이고. 1씩 증가합니다.
  -  reverse 옵션이 사용될 경우 index 는 upper_bound에서 lower_bound로 1씩 감소합니다.
  -  IN 다음에는 coursor나 select 문이 올수 있습니다.



    FOR문 예제


    DECLARE

    -- 사원 이름을 출력하기 위한 PL/SQL 테이블 선언
    TYPE ename_table IS TABLE OF emp.ename%TYPE
    INDEX BY BINARY_INTEGER;

    -- 사원 급여를 출력하기 위한 PL/SQL 테이블 선언
    TYPE sal_table IS TABLE OF emp.sal%TYPE
    INDEX BY BINARY_INTEGER;

    ename_tab    ename_table;
    sal_tab      sal_table;

    i BINARY_INTEGER := 0;

    BEGIN

    DBMS_OUTPUT.ENABLE;

    FOR emp_list IN  (SELECT ename, sal FROM emp WHERE deptno = 10) LOOP

       i := i +1 ;

       ename_tab(i) := emp_list.ename;     -- 테이블에 상품 이름을 저장
       sal_tab(i)      := emp_list.sal;          -- 테이블에 상품 가격을 저장

    END LOOP;


    FOR cnt IN   1..i   LOOP         --  화면에 출력

       DBMS_OUTPUT.PUT_LINE('사원이름 : ' || ename_tab(cnt));
       DBMS_OUTPUT.PUT_LINE('사원급여 : ' || sal_tab(cnt));

    END LOOP;

    END;
    /



    사원이름 : CLARK
    사원급여 : 2450
    사원이름 : KING
    사원급여 : 5000
    사원이름 : MILLER
    사원급여 : 1300

    PL/SQL 처리가 정상적으로 완료되었습니다.


LOOP문, WHILE문


EXIT 문이 사용되었을 경우, 무조건 LOOP문을 빠져나갑니다,

EXITH WHEN 이 사용될 경우  WHEN 절에 LOOP를 빠져 나가는 조건을 제어할수 있습니다.


LOOP 문 예제

SQL> SET SERVEROUTPUT ON ;  -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

SQL>  DECLARE

          v_cnt number(3) := 100;

          BEGIN

          DBMS_OUTPUT.ENABLE ;

          LOOP

              INSERT INTO emp(empno, ename , hiredate)
              VALUES(v_cnt, 'test'||to_char(v_cnt),  sysdate);

              v_cnt := v_cnt+1;

              EXIT WHEN v_cnt > 110;

          END LOOP;

          DBMS_OUTPUT.PUT_LINE('데이터 입력 완료');
          DBMS_OUTPUT.PUT_LINE(v_cnt-100 || '개의 데이터가 입력되었습니다');

          END;          
         /

데이터 입력 완료
11개의 데이터가 입력되었습니다

PL/SQL 처리가 정상적으로 완료되었습니다
.


WHILE LOOP 문

    WHILE LOOP문은 FOR 문과 비슷하며 조건이 TRUE일 경우만 반복되는 LOOP문 입니다.

    예제

    WHILE cnt < 10 LOOP

       INSERT INTO emp(empno, ename , hiredate)
       VALUES(emp_seq.nextval, 'test',  sysdate);

    cnt := cnt + 1 ;

    END LOOP ;

    cnt가 10이면 반복 While Loop를 탈출

    EXIT WHEN
    조건 => 조건이 만족할 때 반복 loop를 탈출합니다. .


조건제어(IF)




IF문 예제 프로시저..

SQL>CREATE OR REPLACE PROCEDURE Dept_Search
(p_empno IN emp.empno%TYPE )

IS

v_deptno emp.deptno%type ;

BEGIN

DBMS_OUTPUT.ENABLE;

SELECT deptno
INTO v_deptno
FROM emp
WHERE empno = p_empno ;

IF v_deptno = 10 THEN

DBMS_OUTPUT.PUT_LINE( ' ACCOUNTING 부서 사원입니다. ' );

ELSIF v_deptno = 20 THEN

DBMS_OUTPUT.PUT_LINE( ' RESEARCH 부서 사원입니다. ' );

ELSIF v_deptno = 20 THEN

DBMS_OUTPUT.PUT_LINE( ' SALES 부서 사원입니다. ' );

ELSIF v_deptno = 20 THEN

DBMS_OUTPUT.PUT_LINE( ' OPERATIONS 부서 사원입니다. ' );

ELSE

DBMS_OUTPUT.PUT_LINE( ' 부서가 없네요... ' );

END IF ;

END ;
/


프로시저가 생성되었습니다.

SQL> SET SERVEROUTPUT ON ; -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

프로시저 실행

SQL> EXECUTE Dept_Search(7900);

부서가 없네요...
PL/SQL 처리가 정상적으로 완료되었습니다.


SQL> EXECUTE Dept_Search(7369);

RESEARCH 부서 사원입니다.
PL/SQL 처리가 정상적으로 완료되었습니다.


암시적 커서(Implicit Cursor)


  암시적인 커서는 오라클이나 PL/SQL실행 메커니즘에 의해 처리되는 SQL문장이 처리되는 곳에 대한
  익명의 에드레스입니다. 오라클 데이터 베이스에서 실행되는 모든 SQL문장은 암시적인 커서이며
  그것들과 함께 모든 암시적인 커서 속성이 사용될 수 있습니다.

     -암시적 커서의 속성

    SQL%ROWCOUNT : 해당 SQL 문에 영향을 받는 행의 수

    SQL%FOUND : 해당 SQL 영향을 받는 행의 수가 1개 이상일 경우 TRUE

    SQL%NOTFOUND : 해당 SQL 문에 영향을 받는 행의 수가 없을 경우 TRUE

    SQL%ISOPEN : 항상 FALSE, 암시적 커서가 열려 있는지의 여부 검색

    (암시적 커서는 SQL 문이 실행되는 순간 자동으로 열림과 닫힘 실행)


    암시적 커서 예제

    CREATE OR REPLACE PROCEDURE Implicit_Cursor
    (p_empno emp.empno%TYPE)

    is

    v_sal  emp.sal%TYPE;
    v_update_row NUMBER;

    BEGIN

    SELECT sal
    INTO v_sal
    FROM emp
    WHERE empno = p_empno ;

    -- 검색된 데이터가 있을경우
    IF  SQL%FOUND THEN    

        DBMS_OUTPUT.PUT_LINE('검색한 데이터가 존재합니다 : '||v_sal);

    END IF;

    UPDATE emp
    SET sal = sal*1.1
    WHERE empno = p_empno;

    -- 수정한 데이터의 카운트를 변수에 저장
    v_update_row := SQL%ROWCOUNT;

    DBMS_OUTPUT.PUT_LINE('급여가 인상된 사원 수 : '|| v_update_row);

    END;

    프로시저가 생성되었습니다.


    SQL> SET SERVEROUTPUT ON ;  -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)
    SQL> EXECUTE Implicit_Cursor(7369);

    검색한 데이터가 존재합니다 : 880
    급여가 인상된 사원 수 : 1

    PL/SQL 처리가 정상적으로 완료되었습니다.
     


Explicit Cursor


▣ 커서란 무엇인가?

커서는 Private SQL의 작업영역 입니다.
오라클 서버에 의해 실행되는 모든 SQL문은 연관된 각각의 커서를 소유하고 있습니다.
커서의 종류
   - 암시적 커서 : 모든 DML과 PL/SQL SELECT문에 대해 선언됩니다.
   - 명시적 커서 : 프로그래머에 의해 선언되며 이름이 있는 커서입니다.
 

▣ Explicit Cursor의 흐름도?

▣ 문법(Syntax)




▣ 커서 열기(OPEN)

커서의 열기는 OPEN문을 사용합니다.
커서안의 검색이 실행되며 아무런 데이터행을 추출하지 못해도 에러가 발생하지 않습니다.

    OPEN   cursor_name;


▣ 커서 패치(FETCH)

커서의 FETCH는 현재 데이터 행을 OUTPUT변수에 반환합니다.
커서의 SELECT문의 컬럼의 수와 OUTPUT변수의 수가 동일해야 합니다.
커서 컬럼의 변수의 타입과 OUTPUT변수의 데이터 타입도 동일해야 합니다.
커서는 한 라인씩 데이터를 패치 합니다.

    FETCH   cursor_name INTO variable1, variable2 ;


▣ 커서 닫기(CLOSE)

사용을 맞친 커서는 반드시 닫아 주어야 합니다.
필요하다면 커서를 다시 열 수 있습니다.
커서를 닫은 상태에서 FETCH를 할 수 없습니다.

    CLOSE   cursor_name;
 


Explicit Cursor 예제
특정 부서의 평균급여와 사원수를 출력..


FOR문에서 커서 사용(Cursor FOR Loops)


FOR문을 사용하면 커서의 OPEN, FETCH, CLOSE가 자동 발생하므로 따로 기술할
    필요가 없습니다
레코드 이름도 자동 선언되므로 따로 선언할 필요가 없습니다.


 

FOR문에서 커서 사용 예제
부서별 사원수와 급여 합계를 구하는 프로시저입니다.

SQL> CREATE OR REPLACE PROCEDURE ForCursor_Test
        IS

        CURSOR dept_sum IS
        SELECT b.dname, COUNT(a.empno) cnt, SUM(a.sal) salary
        FROM emp a, dept b
        WHERE a.deptno = b.deptno
        GROUP BY b.dname;

     BEGIN

       -- Cursor를 FOR문에서 실행시킨다
       FOR emp_list IN dept_sum LOOP

          DBMS_OUTPUT.PUT_LINE('부서명 : ' || emp_list.dname);
          DBMS_OUTPUT.PUT_LINE('사원수 : ' || emp_list.cnt);
          DBMS_OUTPUT.PUT_LINE('급여합계 : ' || emp_list.salary);

       END LOOP;

   EXCEPTION

       WHEN OTHERS THEN
          DBMS_OUTPUT.PUT_LINE(SQLERRM||'에러 발생 ');

   END;
   /

프로시져가 생성되었습니다.

실행 결과

SQL> SET SERVEROUTPUT ON ; -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

SQL> EXECUTE ForCursor_Test;
부서명 : ACCOUNTING
사원수 : 3
급여합계 : 8750
부서명 : RESEARCH
사원수 : 6
급여합계 : 10875
부서명 : SALES
사원수 : 6
급여합계 : 9305
 
PL/SQL 처리가 정상적으로 완료되었습니다.
 


명시적 커서의 속성(Explicit Cursor Attributes)

▣ Explicit Cursor 속성
 
%ISOPEN
      - 커서가 OPEN되어 있으면 TRUE
      -  %ISOPEN속성을 이용하여 커서가 열려있는지 알 수 있습니다.

%NOTFOUND
      - 패치한 데이터가 행을 반환하지 않으면 TRUE
      -  %NOTFOUND속성을 이용하여 루프를 종료할 시점을 찾습니다.

%FOUND
      - 패치한 데이터가 행을 반환하면 TRUE

%ROWCOUNT
     -
현재까지 반환된 모든 데이터 행의 수
      - %ROWCOUNT속성을 이용하여 정확한 숫자만큼의 행을 추출합니다.

 

커서의 속성 예제

SQL>CREATE OR REPLACE PROCEDURE AttrCursor_Test
       IS
 
       v_empno     emp.empno%TYPE;
       v_ename     emp.ename%TYPE;
       v_sal          emp.sal%TYPE;

      CURSOR emp_list IS
         SELECT empno, ename, sal
         FROM emp;    

 
    BEGIN


      DBMS_OUTPUT.ENABLE;

      OPEN emp_list;   

      LOOP    

        FETCH emp_list INTO v_empno, v_ename, v_sal;

           -- 데이터를 찾지 못하면 빠져 나갑니다
           EXIT WHEN emp_list%NOTFOUND;      
     
      END LOOP;    


       DBMS_OUTPUT.PUT_LINE('전체데이터 수 ' || emp_list%ROWCOUNT);
   

     CLOSE emp_list;
   
     EXCEPTION
   
       WHEN OTHERS THEN

         DBMS_OUTPUT.PUT_LINE('ERR MESSAGE : ' || SQLERRM);
       
    END;
   /



프로시져가 생성되었습니다.

실행 결과

SQL> SET SERVEROUTPUT ON ; -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

SQL> EXECUTE AttrCursor_Test;
전체데이터 수 15

PL/SQL 처리가 정상적으로 완료되었습니다.
 


파라미터가 있는 커서(Cursors with Parameters)

커서가 열리고 질의가 실행되면 매개 변수 값을 커서에 전달한다.
다른 active set을 원할때 마다 explicit커서를 따로 선언해야 한다


▣ 문법(Syntax)

 


파라미터가 있는 커서 예제

SQL> CREATE OR REPLACE PROCEDURE ParamCursor_Test
        (param_deptno   emp.deptno%TYPE)
        IS

         v_ename     emp.ename%TYPE;

       -- Parameter가 있는 커서의 선언
        CURSOR emp_list(v_deptno emp.deptno%TYPE) IS
        SELECT ename
        FROM emp
        WHERE deptno = v_deptno;

       BEGIN

        DBMS_OUTPUT.ENABLE;
        DBMS_OUTPUT.PUT_LINE(' ****** 입력한 부서에 해당하는 사람들 ****** ');              

       -- Parameter변수의 값을 전달(OPEN될 때 값을 전달한다)
        FOR emplst IN emp_list(param_deptno) LOOP    

          DBMS_OUTPUT.PUT_LINE('이름 : ' || emplst.ename);

        END LOOP;    

        EXCEPTION    

          WHEN OTHERS THEN

             DBMS_OUTPUT.PUT_LINE('ERR MESSAGE : ' || SQLERRM);        

        END;
        /

프로시져가 생성되었습니다.

실행 결과

SQL> SET SERVEROUTPUT ON ; -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

SQL> EXECUTE ParamCursor_Test(10);
****** 입력한 부서에 해당하는 사람들 ******
이름 : CLARK
이름 : KING
이름 : MILLER

PL/SQL 처리가 정상적으로 완료되었습니다.
 


The WHERE CURRENT OF Clause

WHERE CURRENT OF

   - ROWID를 이용하지 않고도 현재 참조하는 행을 갱신하고 삭제할 수 있게 합니다.
   - 추가적으로 FETCH문에 의해 가장 최근에 처리된 행을 참조하기 위해서
      "W
HERE CURRENT OF 커서이름 "    절로 DELETE나 UPDATE문 작성이 가능합니다..
   - 이 절을 사용할 때 참조하는 커서가 있어야 하며,  
     
FOR UPDATE절이 커서 선언 query문장 안에 있어야 합니다.
      그렇지 않으면 error가 발생합니다..

 

WHERE CURRENT OF 예제

SQL> SET SERVEROUTPUT ON ;  -- DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용

SQL>CREATE OR REPLACE PROCEDURE where_current
         IS

        CURSOR
emp_list IS
             SELECT empno
             FROM emp
             WHERE empno = 7934
            
FOR UPDATE;

      BEGIN

       
--DBMS_OUTPUT.PUT_LINE명령을 사용하기 위해서
        DBMS_OUTPUT.ENABLE;    

        FOR emplst IN emp_list LOOP
             
 --emp_list커서에 해당하는 사람의 직업을  SALESMAN으로 업데이트 시킵니다.
              UPDATE emp
              SET job = 'SALESMAN'
            
WHERE CURRENT OF emp_list;

            DBMS_OUTPUT.PUT_LINE('수정 성공');

        END LOOP;
 
        EXCEPTION
           WHEN OTHERS THEN
               
-- 에러 발생시 에러 메시지 출력
                DBMS_OUTPUT.PUT_LINE('ERR MESSAGE : ' || SQLERRM);
END;  
 

--먼저 데이터를 확인해 보세용
SQL> SELECT job FROM emp WHERE empno = 7934;

JOB
---------
CLERK

 --PLSQL을 실행시키고..
SQL> EXECUTE where_current;
수정 성공  
--DBMS_OUTPUT.PUT_LINE명령으로 출력한거..

PL/SQL 처리가 정상적으로 완료되었습니다.
 

-- 다시 데이터를 확인하면 변경된 것을 볼 수 있습니다.
SQL>  SELECT job FROM emp WHERE empno = 7934;
 
JOB
---------
SALESMAN


예외(Exception)



예외(Exception)란?

오라클 PL/SQL의 오류를 예외라고 부릅니다.

오류는 PL/SQL을 컴파일 할때 문법적인 오류로 발생하는 컴파일 타임 오류와,
    프로그램을 실행할때 발생하는 실행타임 오류로 구분할수 있습니다.
 
 



PL/SQL오류의 종류

 예  외

 설  명

 처  리


   미리 정의된 오라클 서버 오류
(Predefined Oracle Server)
 

  PL/SQL에서 자주 발생하는
  약20개의 오류

  선언할 필요도 없고, 발생시에
예외 절로 자동 트랩(Trap)
된다.


  미리 정의되지 않은 오라클
  서버 오류

  (Non-Predefined Oracle   Server)
 

  미리 정의된 오라클 서버
오류를 제외한
모든 오류

  선언부에서 선언해야 하고 발생시
  자동 트랩된다.


  사용자 정의 오류
  (User-Defined)
 

  개발자가 정한 조건에
만족하지 않을경우
발생하는 오류

   선언부에서 선언하고 실행부에서
   RAISE문을 사용하여 발생시켜야
   한다



Execption 문법(Syntax)
WHEN OTHERS절은 맨 마지막에 옵니다.

예외 처리절은 EXCEPTION부터 시작합니다.

허용합니다.

예외가 발생하면 여러 개의 예외 처리부 중에 하나의 예외 처리부에 트랩(Trap)됩니다.


 


미리 정의된 예외(Predefined Exceptions)

  오라클 PL/SQL은 자주 일어나는 몇가지 예외를 미리 정의해 놓았으며,
      이러한 예외는 개발자가 따로 선언할 필요가 없습니다
 

미리 정의된 예외의 종류?

NO_DATA_FOUND : SELECT문이 아무런 데이터 행을 반환하지 못할때

TOO_MANY_ROWS : 하나만 리턴해야하는 SELECT문이 하나 이상의 행을 반환할 때

INVALID_CURSOR : 잘못된 커서 연산

ZERO_DIVIDE : 0으로 나눌때

DUP_VAL_ON_INDEX : UNIQUE 제약을 갖는 컬럼에 중복되는 데이터가 INSERT될때

   이 외에도 몇 개가 더 있습니다.

미리 정의된 예외 예제

SQL> CREATE OR REPLACE PROCEDURE PreException_test
         (v_deptno  IN emp.empno%TYPE)  
   
   IS

       v_emp   emp%ROWTYPE;

   BEGIN

      DBMS_OUTPUT.ENABLE;

      SELECT empno, ename, deptno
      INTO v_emp.empno, v_emp.ename, v_emp.deptno
      FROM emp
      WHERE deptno = v_deptno ;

      DBMS_OUTPUT.PUT_LINE('사번 : ' || v_emp.empno);
      DBMS_OUTPUT.PUT_LINE('이름 : ' || v_emp.ename);
      DBMS_OUTPUT.PUT_LINE('부서번호 : ' || v_emp.deptno);

   EXCEPTION

      WHEN   DUP_VAL_ON_INDEX   THEN
   
          DBMS_OUTPUT.PUT_LINE('데이터가 존재 합니다.');
          DBMS_OUTPUT.PUT_LINE('DUP_VAL_ON_INDEX 에러 발생');

      WHEN   TOO_MANY_ROWS   THEN  

        DBMS_OUTPUT.PUT_LINE('TOO_MANY_ROWS에러 발생');

      WHEN   NO_DATA_FOUND   THEN  

        DBMS_OUTPUT.PUT_LINE('NO_DATA_FOUND에러 발생');

      WHEN   OTHERS   THEN  

        DBMS_OUTPUT.PUT_LINE('기타 에러 발생');

  END;
  /

프로시저가 생성되었습니다.




프로시저 실행

SQL> SET SERVEROUTPUT ON ;  -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

SQL> EXECUTE PreException_Test(20);
TOO_MANY_ROWS에러 발생

PL/SQL 처리가 정상적으로 완료되었습니다.


 TOO_MANY_ROWS에러를 타는 이유?

 -
SELECT문의 결과가 1개 이상의 행을 리턴하기 때문이다..
 - TOO_MANY_ROWS를 피하기 위해서는 FOR문이나 LOOP문으로 SELECT문을 처리해야 합니다.

아래와 같이 바꾸면 에러가 발생하지 않습니다.


   
 FOR  emp_list  IN
         
(SELECT empno, ename, deptno
         FROM emp
         WHERE deptno = v_deptno)
  LOOP

         DBMS_OUTPUT.PUT_LINE('사번 : ' || emp_list.empno);
         DBMS_OUTPUT.PUT_LINE('이름 : ' || emp_list.ename);
         DBMS_OUTPUT.PUT_LINE('부서번호 : ' || emp_list.deptno);
 
     END LOOP;
 


미리 정의되지 않은 예외(Non-Predefined Exception)


 

STEP 1 : 예외의 이름을 선언(선언절)

STEP 2 : PRAGMA EXCEPTION_INIT문장으로 예외의 이름과 오라클 서버
                  오류 번호를 결합(선언절)

STEP 3 : 예외가 발생할 경우 해당 예외를 참조한다(예외절)
 

리 정의되지 않은 예외 예제

SQL> CREATE OR REPLACE PROCEDURE NonPreException_Test
       IS

          not_null_test EXCEPTION;    -- STEP 1

          /* not_null_test는 선언된 예외 이름
             -1400
Error 처리번호는 표준 Oracle7 Server Error 번호 */
          PRAGMA EXCEPTION_INIT(not_null_test, -1400);       -- STEP 2

        BEGIN

          DBMS_OUTPUT.ENABLE;

        -- empno를 입력하지 않아서 NOT NULL 에러 발생
        INSERT INTO emp(ename, deptno)
        VALUES('tiger', 30);

        EXCEPTION

        WHEN not_null_test THEN    -- STEP 3

            DBMS_OUTPUT.PUT_LINE('not null 에러 발생 ');

       END;
        /

프로시져가 생성되었습니다.

실행 결과

SQL> SET SERVEROUTPUT ON ;    -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

SQL> EXECUTE NonPreException_Test;
not null 에러 발생

PL/SQL 처리가 정상적으로 완료되었습니다.
 


사용자 정의 예외(User-Defined Exceptions)


 오라클 저장함수 RAISE_APPLICATION_ERROR를 사용하여 오류코드 -20000부터
   -20999의 범위 내에서 사용자 정의 예외를 만들수 있습니다.


 

STEP 1 : 예외의 이름을 선언(선언절)

STEP 2 : RAISE문을 사용하여 직접적으로 예외를 발생시킨다(실행절)

STEP 3 : 예외가 발생할 경우 해당 예외를 참조한다(예외절)
 

사용자 정의 예외 예제 Procedure

입력한 부서의 사원이 5명보다 적으면 사용자 정의 예외가 발생하는 예제 입니다.

SQL>CREATE OR REPLACE PROCEDURE User_Exception
        (v_deptno IN emp.deptno%type )
      IS

       -- 예외의 이름을 선언
       user_define_error EXCEPTION;     -- STEP 1
       cnt     NUMBER;

     BEGIN

       DBMS_OUTPUT.ENABLE;  

       SELECT COUNT(empno)
       INTO cnt
       FROM emp
       WHERE deptno = v_deptno;

       IF cnt < 5 THEN
         -- RAISE문을 사용하여 직접적으로 예외를 발생시킨다
          RAISE user_define_error;         -- STEP 2
       END IF;

      EXCEPTION
        -- 예외가 발생할 경우 해당 예외를 참조한다.
       WHEN user_define_error THEN      -- STEP 3
           RAISE_APPLICATION_ERROR(-20001, '부서에 사원이 몇명 안되네요..');

   END;
  /


프로시져가 생성되었습니다.

실행 결과
SQL> SET SERVEROUTPUT ON ; -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

SQL> EXECUTE user_exception(10);
BEGIN user_exception(10); END;
 *
1행에 오류:
ORA-20001: 부서에 사원이 몇명 안되네요..
ORA-06512: "SCOTT.USER_EXCEPTION", 줄 17에서
ORA-06512: 줄 1에서

 10부서의 사원이 5보다 적기 때문에 사용자 정의 예외가 발생했습니다.

SQL> EXECUTE user_exception(20);
PL/SQL 처리가 정상적으로 완료되었습니다. 

20부서로 실행을 하면 에러가 발생하지 않는 것 을 알 수 있습니다..


사용자 정의 예외(User-Defined Exceptions)


 오라클 저장함수 RAISE_APPLICATION_ERROR를 사용하여 오류코드 -20000부터
   -20999의 범위 내에서 사용자 정의 예외를 만들수 있습니다.


 

STEP 1 : 예외의 이름을 선언(선언절)

STEP 2 : RAISE문을 사용하여 직접적으로 예외를 발생시킨다(실행절)

STEP 3 : 예외가 발생할 경우 해당 예외를 참조한다(예외절)
 

사용자 정의 예외 예제 Procedure

입력한 부서의 사원이 5명보다 적으면 사용자 정의 예외가 발생하는 예제 입니다.

SQL>CREATE OR REPLACE PROCEDURE User_Exception
        (v_deptno IN emp.deptno%type )
      IS

       -- 예외의 이름을 선언
       user_define_error EXCEPTION;     -- STEP 1
       cnt     NUMBER;

     BEGIN

       DBMS_OUTPUT.ENABLE;  

       SELECT COUNT(empno)
       INTO cnt
       FROM emp
       WHERE deptno = v_deptno;

       IF cnt < 5 THEN
         -- RAISE문을 사용하여 직접적으로 예외를 발생시킨다
          RAISE user_define_error;         -- STEP 2
       END IF;

      EXCEPTION
        -- 예외가 발생할 경우 해당 예외를 참조한다.
       WHEN user_define_error THEN      -- STEP 3
           RAISE_APPLICATION_ERROR(-20001, '부서에 사원이 몇명 안되네요..');

   END;
  /


프로시져가 생성되었습니다.

실행 결과
SQL> SET SERVEROUTPUT ON ; -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

SQL> EXECUTE user_exception(10);
BEGIN user_exception(10); END;
 *
1행에 오류:
ORA-20001: 부서에 사원이 몇명 안되네요..
ORA-06512: "SCOTT.USER_EXCEPTION", 줄 17에서
ORA-06512: 줄 1에서

 10부서의 사원이 5보다 적기 때문에 사용자 정의 예외가 발생했습니다.

SQL> EXECUTE user_exception(20);
PL/SQL 처리가 정상적으로 완료되었습니다. 

20부서로 실행을 하면 에러가 발생하지 않는 것 을 알 수 있습니다..


Package(패키지)

package?

   패키지(package)는 오라클 데이터베이스에 저장되어 있는 서로 관련있는 PL/SQL
      프로지져와 함수들의 집합 입니다

   패키지는 선언부와 본문 두 부분으로 나누어 집니다.


패키지 선언부

- 선언절은 패키지에 포함될 PL/SQL 프로시저나, 함수, 커서, 변수, 예외절을 선언 합니다.
- 패키지 선언부에서 선언한 모든 요소들은 패키지 전체에 적용됩니다.
- 즉 선언부에서 선언한 변수는 PUBLIC 변수로 사용 됩니다.



 


패키지 본문

- 패키지 본문은 패키지에서 선언된 부분의 실행을 정의 합니다.
- 즉 실재 프로시져나 함수의 내용에 해당하는 부분이 옵니다.



 


아주 간단한 패키지 예제입니다.

4개의 프로시저가 존재하고 있습니다.

프로시저명

프로시저 기능

all_emp_info

  모든 사원의  사원 정보 (사번, 성명, 입사일)

all_sal_info

  모든 사원의  급여 정보 (평균급여, 최고급여, 최소급여)

dept_emp_info

  특정 부서의  사원 정보 (사번, 성명, 입사일)

dept_sql_info

  특정 부서의  급여 정보 (평균급여, 최고급여, 최소급여)

위 4개의 프로시저를 가지고 패키지를 생성하겠습니다.


all_sal_info

  1. 모든 사원의  사원 정보(사번, 성명, 입사일)를 보여 주는 프로시져

SQL> CREATE OR REPLACE PROCEDURE all_emp_info
          IS
       
            CURSOR emp_cursor IS
            SELECT empno, ename, to_char(hiredate, 'RRRR/MM/DD') hiredate
            FROM emp
            ORDER BY hiredate;
       
          BEGIN
       
            FOR  aa  IN emp_cursor LOOP
       
                DBMS_OUTPUT.PUT_LINE('사번 : ' || aa.empno);
                DBMS_OUTPUT.PUT_LINE('성명 : ' || aa.ename);
                DBMS_OUTPUT.PUT_LINE('입사일 : ' || aa.hiredate);
       
            END LOOP;
       
          EXCEPTION
                WHEN OTHERS THEN
                        DBMS_OUTPUT.PUT_LINE(SQLERRM||'에러 발생 ');
       
          END;

Procedure created.

all_sal_info

  2. 모든 사원의  급여 정보 (평균급여, 최고급여, 최소급여)

SQL>CREATE OR REPLACE PROCEDURE all_sal_info
        IS
               
            CURSOR emp_cursor IS
            SELECT round(avg(sal),3) avg_sal, max(sal) max_sal, min(sal) min_sal
            FROM emp;
               
        BEGIN
       
            FOR  aa  IN emp_cursor LOOP
               
                DBMS_OUTPUT.PUT_LINE('전체급여평균 : ' || aa.avg_sal);
                DBMS_OUTPUT.PUT_LINE('최대급여금액 : ' || aa.max_sal);
                DBMS_OUTPUT.PUT_LINE('최소급여금액 : ' || aa.min_sal);
                       
            END LOOP;
       
       
        EXCEPTION
            WHEN OTHERS THEN
                DBMS_OUTPUT.PUT_LINE(SQLERRM||'에러 발생 ');
        END;
/

Procedure created.    

dept_emp_info

  3. 특정 부서의  사원 정보 (사번, 성명, 입사일)

SQL> CREATE OR REPLACE PROCEDURE dept_emp_info
          (v_deptno IN  NUMBER)
          IS
       
                CURSOR emp_cursor IS
                SELECT empno, ename, to_char(hiredate, 'RRRR/MM/DD') hiredate
                FROM emp
                WHERE deptno = v_deptno
                ORDER BY hiredate;
       
          BEGIN
       
            FOR  aa  IN emp_cursor LOOP
       
                DBMS_OUTPUT.PUT_LINE('사번 : ' || aa.empno);
                DBMS_OUTPUT.PUT_LINE('성명 : ' || aa.ename);
                DBMS_OUTPUT.PUT_LINE('입사일 : ' || aa.hiredate);
       
            END LOOP;
       
          EXCEPTION
            WHEN OTHERS THEN
                DBMS_OUTPUT.PUT_LINE(SQLERRM||'에러 발생 ');

          END;

dept_sql_info

  4. 특정 부서의  급여 정보 (평균급여, 최고급여, 최소급여)  

SQL>CREATE OR REPLACE PROCEDURE dept_sal_info
          (v_deptno IN  NUMBER)
        IS
               
            CURSOR emp_cursor IS
            SELECT round(avg(sal),3) avg_sal, max(sal) max_sal, min(sal) min_sal
            FROM emp
            WHERE deptno = v_deptno;
               
               
        BEGIN
       
            FOR  aa  IN emp_cursor LOOP
               
                DBMS_OUTPUT.PUT_LINE('전체급여평균 : ' || aa.avg_sal);
                DBMS_OUTPUT.PUT_LINE('최대급여금액 : ' || aa.max_sal);
                DBMS_OUTPUT.PUT_LINE('최소급여금액 : ' || aa.min_sal);
                       
            END LOOP;
       
       
        EXCEPTION
            WHEN OTHERS THEN
                DBMS_OUTPUT.PUT_LINE(SQLERRM||'에러 발생 ');
        END;      


선언부를 먼저 생성 합니다.

package 예제
(선언부)

SQL>CREATE OR REPLACE PACKAGE emp_info AS

            PROCEDURE all_emp_info;                                           -- 모든 사원의  사원 정보

            PROCEDURE all_sal_info;                                             -- 모든 사원의  급여 정보

            PROCEDURE dept_emp_info (v_deptno IN  NUMBER) ;     -- 특정 부서의  사원 정보

            PROCEDURE dept_sal_info (v_deptno IN  NUMBER) ;       -- 특정 부서의  급여 정보       

        END emp_info;

Package created.


선언부를 생성 하고 나서 본문 부분을 생성 합니다.

package 예제
(본문)

SQL>
CREATE OR REPLACE PACKAGE BODY emp_info AS

               
-- 모든 사원의  사원 정보
               
PROCEDURE all_emp_info
                IS        

                        CURSOR emp_cursor IS
                        SELECT empno, ename, to_char(hiredate, 'RRRR/MM/DD') hiredate
                        FROM emp
                        ORDER BY hiredate;
       
                BEGIN
       
                        FOR  aa  IN emp_cursor LOOP
       
                                DBMS_OUTPUT.PUT_LINE('사번 : ' || aa.empno);
                                DBMS_OUTPUT.PUT_LINE('성명 : ' || aa.ename);
                                DBMS_OUTPUT.PUT_LINE('입사일 : ' || aa.hiredate);
       
                        END LOOP;
       
                EXCEPTION
                        WHEN OTHERS THEN
                                DBMS_OUTPUT.PUT_LINE(SQLERRM||'에러 발생 ');
       
                
END all_emp_info;
 

 
               
 -- 모든 사원의  급여 정보
               
PROCEDURE all_sal_info
                IS
               
                        CURSOR emp_cursor IS
                        SELECT round(avg(sal),3) avg_sal, max(sal) max_sal, min(sal) min_sal
                        FROM emp;
               
                BEGIN
       
                        FOR  aa  IN emp_cursor LOOP
               
                                DBMS_OUTPUT.PUT_LINE('전체급여평균 : ' || aa.avg_sal);
                                DBMS_OUTPUT.PUT_LINE('최대급여금액 : ' || aa.max_sal);
                                DBMS_OUTPUT.PUT_LINE('최소급여금액 : ' || aa.min_sal);
                       
                        END LOOP;
       
       
                EXCEPTION
                        WHEN OTHERS THEN
                                DBMS_OUTPUT.PUT_LINE(SQLERRM||'에러 발생 ');
               
END all_sal_info;
 

 
               
--특정 부서의  사원 정보
               
PROCEDURE dept_emp_info (v_deptno IN  NUMBER)
                IS
       
                        CURSOR emp_cursor IS
                        SELECT empno, ename, to_char(hiredate, 'RRRR/MM/DD') hiredate
                        FROM emp
                        WHERE deptno = v_deptno
                        ORDER BY hiredate;
       
                BEGIN
       
                        FOR  aa  IN emp_cursor LOOP
       
                                DBMS_OUTPUT.PUT_LINE('사번 : ' || aa.empno);
                                DBMS_OUTPUT.PUT_LINE('성명 : ' || aa.ename);
                                DBMS_OUTPUT.PUT_LINE('입사일 : ' || aa.hiredate);
       
                        END LOOP;
       
                EXCEPTION
                        WHEN OTHERS THEN
                                DBMS_OUTPUT.PUT_LINE(SQLERRM||'에러 발생 ');
 
              
 END dept_emp_info;
 
 
               
--특정 부서의  급여 정보
               
PROCEDURE dept_sal_info (v_deptno IN  NUMBER)
                IS
               
                        CURSOR emp_cursor IS
                        SELECT round(avg(sal),3) avg_sal, max(sal) max_sal, min(sal) min_sal
                        FROM emp
                        WHERE deptno = v_deptno;
               
               
                BEGIN

                        FOR  aa  IN emp_cursor LOOP
               
                                DBMS_OUTPUT.PUT_LINE('전체급여평균 : ' || aa.avg_sal);
                                DBMS_OUTPUT.PUT_LINE('최대급여금액 : ' || aa.max_sal);
                                DBMS_OUTPUT.PUT_LINE('최소급여금액 : ' || aa.min_sal);
                       
                        END LOOP;
       
       
                EXCEPTION
                        WHEN OTHERS THEN
                                DBMS_OUTPUT.PUT_LINE(SQLERRM||'에러 발생 ');

               
END dept_sal_info;        
               
       
END emp_info;
         /
 
 Package body created.

 



패키지의 실행

패키지의 실행은 패키지 명 다음에 .을 찍고 프로시저냐 함수 명을 써 줍니다.


먼저 set serveroutput on을 실행한후..
SQL> SET SERVEROUTPUT ON ; -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)


다음 명령들을 실행해 보세요..
SQL> exec emp_info.all_emp_info;

SQL> exec emp_info.all_sal_info;

SQL> exec emp_info.dept_emp_info(10);

SQL> exec emp_info.dept_sal_info(10);


Trigger(트리거)

트리거란?

INSERT, UPDATE, DELETE문이 TABLE에 대해 행해질 때
묵시적으로 수행되는 PROCEDURE 입니다.

Trigger는 TABLE과는 별도로 DATABASE에 저장됩니다.
Trigger는 VIEW에 대해서가 아니라 TABLE에 관해서만 정의될 수 있습니다.





- BEFORE : INSERT, UPDATE, DELETE문이 실행되기 전에 트리거가 실행됩니다.
- AFTER : INSERT, UPDATE, DELETE문이 실행된 후 트리거가 실행됩니다.
- trigger_event : INSERT, UPDATE, DELETE 중에서 한 개 이상 올 수 있습니다.
- FOR EACH ROW : 이 옵션이 있으면 행 트리거가 됩니다.

-- 행 트리거 : 컬럼의 각각의 행의 데이터 행 변화가 생길때마다 실행되며,
그 데이터 행의 실제값을 제어할수 있습니다.
-- 문장 트리거 : 트리거 사건에 의해 단 한번 실행되며, 컬럼의 각 데이터 행을 제어할수 없습니다.

간단한 행 트리거 예제

SQL>CREATE OR REPLACE TRIGGER triger_test
BEFORE
UPDATE ON dept
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('변경 전 컬럼 값 : ' || : old.dname);
DBMS_OUTPUT.PUT_LINE('변경 후 컬럼 값 : ' || : new.dname);
END;
/


SQL> SET SERVEROUTPUT ON ; -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

-- UPDATE문을 실행시키면..
SQL>UPDATE dept
SET dname = '총무부'
WHERE deptno = 30

-- 트리거가 자동 실행되어 결과가 출력됩니당.
변경 전 컬럼 값 : 인사과
변경 후 컬럼 값 : 총무부

1 행이 갱신되었습니다.

간단한 행 트리거 예제2 (PLSQL BLOCK이 있는 트리거)

SQL>CREATE OR REPLACE trigger sum_trigger
BEFORE
INSERT OR UPDATE ON emp
FOR EACH ROW

DECLARE

-- 변수를 선언할 때는 DECLARE문을 사용해야 합니다
avg_sal NUMBER;

BEGIN

SELECT ROUND(AVG(sal),3)
INTO avg_sal
FROM emp;

DBMS_OUTPUT.PUT_LINE('급여 평균 : ' || avg_sal);

END;
/

트리거가 생성되었습니다.

SQL> SET SERVEROUTPUT ON ; -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)

-- INSERT문을 실행합니다..

SQL> INSERT INTO EMP(EMPNO, ENAME, JOB, HIREDATE, SAL)
VALUES(1000, 'LION', 'SALES', SYSDATE, 5000);

-- INSERT문을 실행되기 전까지의 급여 평균이 출력됩니다.
급여 평균 : 2073.214

1 개의 행이 만들어졌습니다.

출처 : http://www.oracleclub.com/

'프로그래밍 > DB' 카테고리의 다른 글

[펌] 계정 생성 및 권한부여  (0) 2007.11.27
직렬화된 객체를 Oracle BLOB에 저장하기  (0) 2007.11.27
[펌] PL/SQL 조건문 만들기  (0) 2007.11.27
[펌] 오라클자료 - PL/SQL  (0) 2007.11.27
[펌] PL-SQL 정리  (0) 2007.11.27

[펌] PL/SQL 조건문 만들기

프로그래밍/DB 2007. 11. 27. 14:33 Posted by galad
출처 블로그 > 나의 컴 메모
원본 http://blog.naver.com/nukiboy/40007931468

CREATE OR REPLACE
FUNCTION CF_TO_HEXA
(
    DECI NUMBER
) RETURN CHAR IS

V_RET CHAR;

BEGIN
    IF DECI = 10 THEN
        V_RET := 'A';
    ELSIF DECI = 11 THEN
        V_RET := 'B';
    ELSIF DECI = 12 THEN
        V_RET := 'C';
    ELSIF DECI = 13 THEN
        V_RET := 'D';
    ELSIF DECI = 14 THEN
        V_RET := 'E';
    ELSIF DECI = 15 THEN
        V_RET := 'F';
    ELSE
        V_RET := TO_CHAR(DECI);
    END IF;
    RETURN V_RET;
END;

'프로그래밍 > DB' 카테고리의 다른 글

직렬화된 객체를 Oracle BLOB에 저장하기  (0) 2007.11.27
[펌] Oracle - PL/SQL  (0) 2007.11.27
[펌] 오라클자료 - PL/SQL  (0) 2007.11.27
[펌] PL-SQL 정리  (0) 2007.11.27
select * from user_catalog;  (0) 2007.11.27

[펌] 오라클자료 - PL/SQL

프로그래밍/DB 2007. 11. 27. 14:32 Posted by galad
출처 블로그 > 하루...
원본 http://blog.naver.com/dewlast/140001355787

PL/SQL REFERENCE MANUAL  (출처 : 오라클)

제 13장 PL/SQL

SQL은 국제표준화 기구들에 의해서 최소한의 표준 문법이 정의되어 있고 DBMS를 제공하는 각 벤더들은 이 표준을 따르고 있으며 부가적인 명령을 추가하여 SQL 제품을 출시하고 있다. 이러한 SQL은 절차적인(procedural) 언어라고 하는 BASIC, COBOL, C, Visual BASIC 등과 달리 비절차적인 구조로 구성이 되어 있다. 절차적인 언어들은 if, for, while 등과 같은 일련의 명령어들을 조합해서 데이터들을 가공하고 제어할 수 있는 반면, 비절차적인 언어인 SQL은 하나의 명령어 단위로 데이터를 관리하고 있는 DBMS에게 데이터를 요청하고, 변경 의뢰하는 방식으로 운영되기 때문에 여러개의 SQL 명령을 조합해서 하나의 프로그램으로 구성할 수 없다는 제한사항이 있다.

이와 같은 SQL의 제한사항을 해소하는 일반적인 방법으로 Visual BASIC으로 작성된 프로그램 내에서 SQL 명령어로 DBMS에게 데이터를 요청해서 읽혀진 데이터들을 Visual BASIC 명령어로 가공하여 사용하는 Client/Server 방식을 사용하게 된다. 이러한 방법은 비절차적인 언어인 Visual BASIC으로 작성된 프로그램 내에서 비절차적인 SQL 명령을 사용하여 데이터를 읽어들인 다음 Visual BASIC 명령어로 데이터를 표현하거나 가공함으로서 Client는 데이터를 요청, 가공하는 역할을 하게되고, Server는 데이터를 제공하고 유지하는 역할을 하게 된다.

하지만, 경우에 따라서 일련의 SQL 명령어들을 if, for, while 등과 같은 절차적인 언어에서 사용하는 명령어와 결합하여 함수나 프로그램을 구성해서 이것을 DBMS가 처리해 줄 수 있다면 SQL의 효율성이 높일 수 있을 것이다.

PL/SQL(Procedural Language/SQL)은 SQL의 명령어들을 대부분 그대로 사용하면서 if, for, while 등과 같은 비절차적인 언어 등을 추가하여 절차적인 프로그래밍이 가능하도록 SQL을 확장시킨 오라클사의 고유 제품이다.


13.1 PL/SQL 개요

PL/SQL로 작성된 프로그램에는 비절차적인 SQL 명령어와 절차적인 명령어들이 함께 존재하게 됨으로 PL/SQL 엔진은 그림 13-1과 같이 SQL 명령어와 Non-SQL 명령어를 따로 분리되어 SQL 명령어는 SQL 엔진으로 처리되고 Non-SQL 명령어는 PL/SQL 엔진에서 처리된다.


PL/SQL로 작성된 프로그램이 이름 없이 스크립트(script) 형태로 작성되었다면 오라클 DBMS에 의해 실행만 가능한 반면, 특정한 이름으로 저장하게 되면 하나의 오라클 개체로서 DBMS에 의해서 관리되므로 언제든지 DBMS에게 요청하여 실행시킬 수 있다.

PL/SQL은 명령어를 사용하면서 절차적인 프로그램이 가능하도록 지원함으로서 다음과 같은 몇 가지 장점을 제공한다.

◈ 모듈화된 프로그램 개발

º 자주 사용되는 기능을 함수로 구성하여 다른 프로그램에서 실행

º 블록 내에서 논리적으로 관련된 문장들의 그룹화

º 강력한 프로그램을 작성하기 위해 서브 블록들을 큰 블록에 포함

º 복잡한 문제에 대한 프로그래밍이 적절히 나뉘어진 모듈들의 집합으로 구성

◈ 절차적 언어 구조로 된 프로그램 작성

º 조건에 따라 일련의 문장을 실행 (IF)

º 루프에서 반복적으로 일련의 문장을 실행 (LOOP)

◈ CURSOR

º Cursor를 이용한 Multi-row 질의와 개별 row에 대한 처리

º 데이터베이스의 테이블과 Record를 기반으로 하는 dynamic한 변수 선언이 가능

◈ EXCEPTION, ERROR 처리

º Exception 처리 루틴을 이용하여 오라클 서버 에러를 처리

º 사용자 정의 에러를 선언하고 Exception 처리 루틴으로 처리

◈ TRIGGER 처리

º 특정 사건(event) 이전 또는 이후에 지정한 일련의 특정 명령이 자동 실행

PL/SQL의 주요한 장점 중에 하나는 함수 프로그램을 작성하여 오라클 개체로 저장시켜 놓고 다른 프로그램에서 명령어처럼 실행할 수 있어서 프로그램을 단순화시킬 수 있고 Client/Server 환경에서는 Client에서는 Server에 PL/SQL로 작성된 개체명만 호출하면 됨으로 네트워크의 통신량을 줄일 수 있다. 또한, DBMS에 의해서 개별적인 개체로 관리되기 때문에 사용 권한에 대한 제어가 용이하다. 그리고, 커서(cursor) 기능을 사용하여 복수개의 행을 읽은 후에 하나씩 패치(fetch)하여 처리할 수 있으며, 예외(Exception) 기능을 이용하여 프로그램 내에서 예외적인 상황이 발생하면 프로그램이 비정상적으로 종료되지 않고 착오 사항을 인지하여 지정한 일련을 명령을 실행시킬 수 있다. Trigger 기능은 테이블에 대해서 변경이 이루어지는 이전 또는 이후를 자동적으로 인지하여 지정한 일련의 명령어들을 처리할 수 있게 한다.

13.2 PL/SQL 블록

PL/SQL 블록 구조는 3개 부분으로 나누어 정의된다. 첫 번째가 선언(declare) 부로 실행부에서 사용할 모든 변수와 상수 등을 선언하는 부분이다. 선언부는 정의하지 않아도 되는 부분이다. 두 번째는 블록의 핵심 부분인 실행부로서 데이터 처리를 위한 SQL 명령문과 PL/SQL 제어문이 포함되는 부분이다. 실행부는 반드시 명시되어야 하는 부분이다. 끝으로 예외(exception)부로 실행부분에서 Error나 비정상적인 조건이 발생했을 때 처리할 내용을 명시하는 부분이다.

부 분

기술 내용

DECLARE

(선언부)

⼘선택적으로 명시

⼘변수, 상수 선언

⼘Cursor, 사용자가 선언할 Exception

BEGIN

(실행부)

⼘반드시 명시

⼘SQL과 PL/SQL 제어문

EXCEPTION

(예외 처리부)

⼘선택적으로 명시

⼘Error 또는 비정상조건 발생시 실행할 내용

END

⼘반드시 명시

표 13- 1 PL/SQL 블록 구성


13.2.1 변수 선언

DECLARE 절에서의 변수 선언은 기본적으로 변수명과 데이터형을 정의하고 문장 끝에 세미콜론(;)으로 종료시켜 주면 된다. 기타 선택적으로 변수에 대한 초기 값을 지정하기 위해서는 데이터형 뒤에 " := 10" 형태로 값을 지정하거나 산술식을 명시하면 된다. 만약 초기 값을 상수로 사용하길 원한다면 변수명 뒤에 CONSTANT라고 기술해주면 된다.

PL/SQL에서 사용하는 데이터형은 기본적으로 테이블 생성시 선언하는 데이터형을 똑같이 사용하고 있으며, 추가적으로 %TYPE 속성, %ROWTYPE 속성을 사용한다. 기본적인 데이터형을 사용하는 예는 표 13-2와 같고 %TYPE 속성, %ROWTYPE 속성을 사용하는 예는 표 13-3과 같다.

DECLARE 절의 변수 선언에 대한 문법은 다음과 같다.

구문법

Identifier [CONSTANT] Datatype [NOT NULL]

[:= Value| DEFAULT 수식];

Identifier

변수나 상수 명

CONSTANT

상수로 사용할 경우 명시

Datatype

데이터 형식

Value

초기 값

DECLARE

h_name CHAR(10) NOT NULL;

rec_count NUMBER(3) := 0;

score_average NUMBER(4,1);

tax_rate CONSTANT NUMBER(3,1) := 10.0;

in_date DATE := SYSDATE + 7;

val_valid BOOLEAN NOT NULL := TRUE;

표 13-2 변수 선언 예

PL/SQL에서는 변수를 선언할 때 이미 선언된 변수나 특정 테이블의 칼럼이 갖는 데이터형을 상속받아 선언할 수 있다. 이렇게 하기 위해 %TYPE 속성을 이용한다.

표 13-3 예에서와 같이 %TYPE 속성은 상속받을 변수나 칼럼명 바로 뒤에 %TYPE라고 명시하게되면 해당 변수나 칼럼의 데이터형을 상속받게 된다. 테이블의 칼럼으로부터 상속을 받을 경우는 컬럼명 앞에 테이블명을 명시하여야 한다. 여기에서 데이터형을 상속받는다는 말은 상속한 변수나 칼럼의 데이터형이 바뀔 경우 상속받은 변수도 함께 바뀐다는 의미이다.

DECLARE

e_name emp.ename%TYPE;

v_name e_name%TYPE;

row_emp emp%ROWTYPE;

표 13-3 %TYPE 속성 사용 예


PL/SQL에서는 변수를 선언할 때 레코드(record) 형태로 선언할 수 있다. 이때 사용하는 속성이 %ROWTYPE 속성으로서 특정 테이블의 row로부터 모든 칼럼명과 데이터형을 상속받는다. 상속받은 레코드 변수는 실행절에서 레코드 변수 전체로 사용하던지 특정 칼럼만을 사용할 수 있다. 특정 칼럼명만을 사용할 때는 표 13-4의 예에서와 같이 변수명.칼럼명 형태로 사용한다.

DECLARE

row_emp emp%ROWTYPE;

BEGIN

SELECT * INTO row_emp FROM emp WHERE empno = 7369;

row_emp.deptno := 10;

표 13-4 %ROWTYPE 속성 사용 예


13.2.2 제어 구조

PL/SQL에서 사용하는 제어 명령어는 IF 문과 LOOP 문이다. LOOP 문은 다시 LOOP 문을 빠져나가는 형태에 따라 기본 LOOP 문과 WHILE LOOP 문, FOR LOOP 문이 각각 존재한다.

LOOP

LOOP 문은 LOOP와 END LOOP 사이에 반복되는 문장을 배치하는 구조로 구성된다. LOOP와 END LOOP 사이에 EXIT 문 또는 [EXIT WHEN 조건]을 삽입함으로서 LOOP 문을 빠져나갈 수 있게 된다.

구문법

LOOP

Statement-1;

Statement-2;

......

EXIT [WHEN Condition];

END LOOP;


실습을 위해 다음과 같이 test_loop 테이블을 생성하자.

SQL> CREATE TABLE test_table (

record_number INT NOT NULL,

current_date DATE,

CONSTRAINT pk_recnum PRIMARY KEY (record_number));

⼧실습예제: 위에서 생성한 test_table 테이블에 LOOP 문을 사용하여 10개의 행을 생성(insert) 해보자.

SQL

DECLARE

max_records CONSTANT INT := 10;

i INT := 0;

BEGIN

LOOP

i := i + 1;

INSERT INTO test_table (record_number, current_date)

VALUES(i, sysdate);

EXIT WHEN i >= max_records;

END LOOP;

COMMIT;

END;

/

PL/SQL 처리가 정상적으로 완료되었습니다.


PL/SQL 블록은 SQL*Plus에서 SQL과 같이 입력하고 편집, 실행이 가능하다.

위의 실습문제를 입력하고 실행할 때는 맨 끝에 /를 해주면 SQL*Plus의 버퍼에 저장되면서 실행이 된다.

실습을 해보면 알겠지만 위 실습문제를 실행시켰을 때 "PL/SQL 처리가 정상적으로 완료되었습니다." 라고 메시지가 뿌려짐을 알 수 있다. 따라서 실행 결과를 확인하기 위해서는 test_table 테이블을 직접 select해 보아야 한다.

⼆ WHILE ... LOOP

WHILE LOOP 문은 LOOP 문에서 loop를 빠져나가는 조건을 LOOP 절 안에 EXIT 문을 쓰는 것 대신에 LOOP 문을 "WHILE 조건 LOOP"문으로 명시하는 점이 다르다. 그러므로 WHILE LOOP을 진입하기 전에 조건을 비교하여 조건이 맞으면 LOOP절 안에 있는 문장들을 수행한다.

구문법

WHILE Exit_Condition LOOP

Statement-1;

Statement-2;

......

END LOOP;


아래 실습예제의 결과를 보기 위해서는 다음 SQL*Plus 명령문을 먼저 실행시켜야 한다.

SQL> SET SERVEROUTPUT ON

위에서 SQL*Plus의 SERVEROUTPUT 환경변수를 활성화시키게 되면 오라클 서버가 실행한 결과를 모니터를 통해서 볼 수 있게 된다.

⼧실습예제: WHILE LOOP 문을 사용하여 다음 실습을 하여보자.

SQL

DECLARE

i INT := 0;

sel_row test_table%ROWTYPE;

output_line VARCHAR2(80);

BEGIN

DBMS_OUTPUT.ENABLE;

WHILE i < 10 LOOP

i := i + 1;

SELECT * INTO sel_row FROM test_table

WHERE record_number = i;

output_line := to_char(sel_row.record_number, '99')

|| ' ' || to_char(sel_row.current_date,'yy/mm/dd');

DBMS_OUTPUT.PUT_LINE(output_line);

END LOOP;

END;

/

1 00/08/19

2 00/08/19

3 00/08/19

4 00/08/19

5 00/08/19

6 00/08/19

7 00/08/19

8 00/08/19

9 00/08/19

10 00/08/19

PL/SQL 처리가 정상적으로 완료되었습니다.

위의 실습 예제에서 DBMS_OUTPUT.PUT_LINE(output_line); 문장은 output_line 변수에 저장된 내용을 모니터를 통해 출력하라는 명령이고, 그 이전에 DBMS_OUTPUT.ENABLE; 문장은 DBMS_OUTPUT명령을 사용할 수 있도록 활성화시키는 명령이다.

⼆ FOR ... LOOP

FOR LOOP 문은 LOOP 실행 조건을 변수와 함께 하한 값과 상한 값을 지정해주는 방법이다. FOR LOOP 문을 사용할 때는 다른 LOOP 문과 달리 선언부에 조건문에서 사용할 변수를 선언할 필요가 없다. 조건문에 REVERSE라고 선언하면 Index 값은 End_value 값을 Start_value 값이 될 때까지 1씩 감소시키면서 실행된다.

구문법

FOR Index IN [REVERSE] Start_value .. End_value LOOP

Statement-1;

Statement-2;

......

END LOOP;



⼧실습예제: 이전에 WHILE LOOP로 실습한 내용을 FOR LOOP 문으로 바꾸어 실습하여 보자.

SQL

DECLARE

sel_row test_table%rowtype;

output_line varchar2(80);

BEGIN

DBMS_OUTPUT.ENABLE;

FOR i IN 1..10 LOOP

SELECT * INTO sel_row FROM test_table

WHERE record_number = i;

output_line := to_char(sel_row.record_number, '99')

|| ' ' || to_char(sel_row.current_date,'yy/mm/dd');

DBMS_OUTPUT.PUT_LINE(output_line);

END LOOP;

END;

/


⼆ IF

PL/SQL에서의 IF 문은 절차적인 언어에서의 IF 문과 유사하다.

구문법

IF Condition THEN

Statement-1;

......

[ELSIF Condition THEN

Statement-2;

......]

[ELSE

Statement-3;

......]

END IF;

IF문 다음에 또 다른 조건을 사용하고자 할 때는 IF 대신에 ELSIF를 반복해서 사용하면 되고 마지막에는 ELSE를 사용하면 된다. 이때 주의할 점은 ELSEIF가 아니라 ELSIF란 점과 마지막에 ELSE는 단 한 번밖에 사용할 수 없다는 점이다.

13.2.3 예외사항 처리

문법적으로 이상이 없는 PL/SQL 블록을 실행하는 중에 착오가 발생하면 실행이 중단되는 경우가 있는데 이러한 경우에 상황별로 조치할 수 있는 예외처리부분을 작성해 넣을 수 가 있다.

예외처리부에서 사용할 수 있는 예외 상황은 크게 오라클 서버가 자동적으로 인지하는 미리 정의된 Oracle Server 예외와 사용자가 정의 해놓고 사용하는 사용자 정의 예외가 있다.

(1) 미리 정의된 Oracle Server 예외

미리 정의된 예외란 오라클 서버가 인지한 착오 상황으로서 우리가 자주 접하게 되는 오라클 착오 번호 ORA_00001과 같은 착오에 해당한다.

미리 정의된 Oracle Server 예외 유형은 표 13-5와 같다.

예외 이름

발생 상황

DUP_VAL_ON_INDEX

유일값 중복 Error

INVALID_NUMBER

Data type 불일치 Error

NO_DATA_FOUND

데이터를 반환하지 않은 SELECT 문

TOO_MANY_ROWS

두 행 이상을 반환한 SELECT 문

VALUE_ERROR

대입되는 값이 길이 초과

ZERO_DEVIDE

0으로 나누기 시도

표 13-5 미리 정의된 Oracle Server 예외

구문법

EXCEPTION

WHEN Exception_name_1 [OR Exception_name_2 ... ] THEN

Statement-1;

......

[WHEN Exception_name_3 [OR Exception_name_4 ... ] THEN

Statement-2;

......]

[WHEN OTHERS THEN

Statement-3;

......]


여기에서 Exception_name 부분에는 미리 정의된 오라클 서버 예외나 사용자가 정의한 예외 명을 써주면 된다.

WHEN OTHERS THEN 다음에는 명시적으로 선언되지 않은 모든 예외에 대한 처리 루틴을 포함시키면 된다.

만약, 예외가 발생하면 오라클 서버는 블록을 벗어나기 전에 하나의 예외 처리만 수행한다. 다시 말해 복수 개의 예외가 발생할 수 있는 블록이라면 가장 먼저 발생된 예외 상황에 대해서만 예외 처리가 된다는 의미이다.

⼧실습예제: 다음의 예외처리에 대한 예제를 실행시켰을 때 어떤 메시지가 출력될 지 예측하여 보시오.

Ⰱ, Ⰲ, Ⰳ를 차례로 활성화시키면서 실행시킨 결과를 예측하여 보시오

SQL

DECLARE

I int :=1;

sel_row test_table%rowtype;

BEGIN

--Ⰱ UPDATE test_table SET record_number = 'A'

-- WHERE record_number = 1;

--Ⰲ INSERT INTO test_table VALUES(1, SYSDATE);

--Ⰳ SELECT * INTO sel_row FROM test_table

-- WHERE record_number = 21;

SELECT * INTO sel_row FROM test_table;

EXCEPTION

when DUP_VAL_ON_INDEX then

dbms_output.put_line('유일성 중복!');

when INVALID_NUMBER then

dbms_output.put_line('Data type 불일치!');

when NO_DATA_FOUND then

dbms_output.put_line('일치 자료 없음!');

when TOO_MANY_ROWS then

dbms_output.put_line('둘 이상 검색!');

when OTHERS then

dbms_output.put_line('!!!');

END;

/



(2) 사용자 정의 예외

사용자 정의 예외처리는 오라클 서버에 의해 발생될 수 없는 예외 상황에 대해서 사용자가 임의로 정의하여 강제로 발생되게 하는 방법이다.

예외명은 DECLARE절에서 선언하고, 예외가 발생해야할 조건은 실행부분에 정의하면 된다. 예외 상황 발생시 처리해야할 루틴은 미리 정의된 Oracle Server 예외에서와 같이 명시해주면 된다. 단지 사용자가 정의한 예외명을 적어주면 된다.

구문법

DECLARE

Exception_name EXCEPTION;

......

BEGIN

......

RAISE Exception_name;

......

EXCEPTION

WHEN Exception_name THEN

Statement-1;

......


⼧실습예제: test_table의 행(Row)의 수를 검사한 다음 행의 수가 5이상이면 예외 처리하는 블록을 작성하시오.

SQL

DECLARE

row_cnt int :=0;

output_line varchar2(80);

exception_row_over_5 EXCEPTION;

BEGIN

SELECT COUNT(*) INTO row_cnt FROM test_table;

IF row_cnt > 5 THEN

RAISE exception_row_over_5;

END IF;

EXCEPTION

WHEN exception_row_over_5 THEN

output_line := 'Row_Count= ' || row_cnt;

dbms_output.put_line(output_line);

END;

/

13.2.4 커서

위의 예외처리에서 보았듯이 PL/SQL에서는 복수개의 행을 SELECT할 경우에 TOO_MANY_ROWS 예외가 발생하므로 한 행씩 차례대로 읽어들여 처리하지 못하게 된다. PL/SQL에서 이와 같은 문제를 해결할 수 있는 기능을 갖는 것이 커서(cursor) 이다.

커서는 질의에 의해 반환된 행들을 한 행씩 차례대로 이동시켜 가며 처리할 수 있게 한다.

기본적으로 커서는 PL/SQL 블록 내에서 DECLARE절에서 커서를 선언하고, BEGIN절에서 커서를 열어서, 커서를 이용하여 데이터 행을 추출하여 처리하고, 마지막으로 커서 닫기 순으로 사용한다.

커서 선언

DECLARE

CURSOR Cursor_name IS;

Select_statement;

커서 선언은 DECLARE절에 CURSOR문 다음에 커서 명을 명시하고 그 뒤에 IS와 함께 SELECT절을 명시하면 된다. 이 때의 SELECT절은 WHERE절이나 BY절을 사용할 수 있다.

BEGIN절에서 커서를 사용할 때는 먼저 커서를 OPEN 하고, FETCH문을 이용하여 한 행씩 변수로 읽어들여 처리를 하면 된다. 이 때 계속해서 다음 행을 읽어들이기 위해서 LOOP절 안에 FETCH문을 위치시키게 된다.

FETCH 작업이 모두 끝나면 커서를 닫으면 된다.

커서 사용 (1)

BEGIN

......

OPEN Cursor_name;

LOOP

FETCH Cursor_name INTO variable1 [,variable2 ... ];

EXIT WHEN Cursor_name%NOTFOUND;

......

END LOOP

CLOSE Cursor_name;

......


⼧실습예제: test_table을 읽어서 "1 : yyyy/mm/dd" 형태로 출력되도록 PL/SQL 블록을 작성하시오.

SQL

DECLARE

row_test test_table%ROWTYPE;

output_line varchar2(80);

CURSOR test_cursor IS

SELECT * FROM test_table;

BEGIN

OPEN test_cursor;

LOOP

FETCH test_cursor INTO row_test;

EXIT WHEN test_cursor%NOTFOUND;

output_line := row_test.record_number || ' : '

|| TO_CHAR(row_test.current_date, 'yyyy/mm/dd');

dbms_output.put_line(output_line);

END LOOP;

CLOSE test_cursor;

END;

/


1 : 2000/08/19

2 : 2000/08/19

3 : 2000/08/19

4 : 2000/08/19

5 : 2000/08/19

6 : 2000/08/19

7 : 2000/08/19

8 : 2000/08/19

9 : 2000/08/19

10 : 2000/08/19

PL/SQL 처리가 정상적으로 완료되었습니다.

위 예제에서 test_cursor%NOTFOUND는 커서의 상태를 구하는 방법으로서 결과는 True 또는 False로 반환된다. 커서의 속성들은 표 13-6과 같다.

속 성

반환 유형

반환 내용

%ISOPEN

Boolean

커서가 open되어 있으면 True

%NOTFOUND

Boolean

더 이상 fetch할 레코드가 없으면 True

%FOUND

Boolean

더 이상 fetch할 레코드가 있으면 True

%ROWCOUNT

Number

현재까지 fetch한 행의 수

표 13-6 커서 속성

앞에 예제에서는 FETCH를 반복하기 위해서 LOOP문을 사용하였는데 이것을 다음과 같이 FOR LOOP 문으로 대치할 수 있다.

커서 사용 (2)

BEGIN

......

FOR variable IN Cursor_name LOOP

......

END LOOP;

......


이와 같이 FOR LOOP 문에 커서명을 명시하게 되면 Fetch하여 저장할 변수나 레코드 변수를 별도로 DECLARE절에서 선언할 필요가 없고, BEGIN절에서 커서를 OPEN하고 CLOSE할 필요가 없으므로 PL/SQL 블록이 아주 단순해진다.

⼧실습예제: 앞의 실습예제를 FOR LOOP를 사용하는 방법으로 PL/SQL 블록을 바꾸어보시오.

SQL

DECLARE

output_line varchar2(80);

CURSOR test_cursor IS

SELECT * FROM test_table;

BEGIN

FOR row_test IN test_cursor LOOP

output_line := row_test.record_number || ' : '

|| TO_CHAR(row_test.current_date, 'yyyy/mm/dd');

dbms_output.put_line(output_line);

END LOOP;

END;

/


⼆ WHERE절에서의 커서 사용

PL/SQL에서는 WHERE절에서도 커서를 사용할 수 있다.

WHERE절에서 커서를 사용하기 위해서는 커서를 선언할 때 SELECT절 뒤에 FOR UPDATE문을 추가하여야 한다.

WHERE절에서 커서 사용

DECLARE

CURSOR Cursor_name IS;

Select_statement

FOR UPDATE;

BEGIN

......

WHERE CURRENT OF Cursor_name;

......


WHERE절에서의 커서 사용은 현재 커서가 가리키고 있는 행에 대해 UPDATE나 DELETE 작업을 할 때 유용하다.

⼧실습예제: test_table에서 record_number가 5보다 큰 행의 current_date에 7일을 더하여 갱신하는 PL/SQL 블록을 커서를 이용하여 작성하시오.

SQL

DECLARE

output_line varchar2(80);

CURSOR test_cursor IS

SELECT * FROM test_table

WHERE record_number > 5

FOR UPDATE;

BEGIN

FOR row_test IN test_cursor LOOP

UPDATE test_table SET current_date = current_date + 7

WHERE CURRENT OF test_cursor;

END LOOP;

END;

/


⼆ Parameter가 있는 커서 사용

PL/SQL에서는 커서의 매개변수를 통해서 커서에 값을 전달할 수 있다.

Parameter가 있는 커서 사용

DECLARE

CURSOR Cursor_name (parameter_name Data_type) IS;

Select_statement;

BEGIN

......

OPEN Cursor_name(parameter_name);

......

CLOSE Cursor_name;

커서 parameter로의 값 전달은 커서를 OPEN할 때이다.

커서는 parameter를 통해 전달받은 값을 이용해서 SELECT절을 수행하게 되므로 커서를 융통성 있게 사용할 수 있는 효과가 있다.

⼧실습예제: test_table에서 parameter가 있는 커서를 이용해서 current_date가 SYSDATE보다 큰 행만을 출력하는 PL/SQL 블록을 작성하시오.

SQL

DECLARE

output_line varchar2(80);

CURSOR test_cursor(p_date DATE) IS

SELECT * FROM test_table

WHERE current_date > p_date;

BEGIN

FOR row_test IN test_cursor(SYSDATE) LOOP

output_line := row_test.record_number || ' : '

|| TO_CHAR(row_test.current_date, 'yyyy/mm/dd');

dbms_output.put_line(output_line);

END LOOP;

END;

/

6 : 2000/08/26

7 : 2000/08/26

8 : 2000/08/26

9 : 2000/08/26

10 : 2000/08/26

PL/SQL 처리가 정상적으로 완료되었습니다.







13.3 서브프로그램

PL/SQL에서는 프로시저(Procedure)나 함수(Function)를 선언하여 사용할 수 있다. 선언되는 함수나 프로시저는 PL/SQL 블록 내에 위치할 수도 있고, 별도의 이름을 부여하여 오라클 개체로 저장하여 관리 될 수도 있다.

다음은 프로시저를 오라클 개체로 저장하여 다른 프로그램에서 호출하여 실행하는 예를 소개한다.

⼆ Stored Procedure

Stored Procedure는 오라클 개체로 관리되므로 프로시저 생성시 CREATE 구문을 사용하고 한다. CREATE문 다음에 PL/SQL 블록이 위치하게 되고 프로시저 작성이 끝나면 컴파일 되어 프로시저 이름으로 저장된다. 이 때의 PL/SQL 블록은 DECLEAR 문을 생략하고 바로 변수만 하여야 한다.

Stored Procedure

CREATE [OR REPLACE] PROCEDURE Procedure_name

[(Parameter, ........)]

IS

PL/SQL_Block;


프로시저가 컴파일 될 때 에러가 발생하면 에러를 수정한 후 다시 컴파일 해야 하는데 이때 CREATE 문에 OR REPLACE를 명시하지 않으면 프로시저 이름 중복 에러가 발생한다. 이것은 컴파일 에러가 발생하더라도 프로시저가 등록되기 때문으로 다시 컴파일 할 때는 OR REPLACE문을 포함시켜야 한다. 그렇지 않으면 해당 프로시저를 삭제하고 다시 생성해야 한다.

프로시저를 삭제하는 명령은 다음과 같다.

DROP PROCEDURE Procedure_name

프로시저를 생성할 때 데이터를 전달받고 반환할 parameter를 선언할 수도 있고 선언하지 않아도 된다. parameter 선언 방법은 다음과 같다.

Parameter 선언

[(Parameter_name [IN | OUT | IN OUT] Datatype, ........)]

여기에서 IN은 실행 환경으로부터 프로시저로 값을 전달받는 parameter이고 OUT은 프로시저로부터 실행 환경으로 값을 전달하는 parameter이다. IN OUT은 IN과 OUT 기능을 모두 포함하는 parameter이다.

⼧실습예제: test_table의 행의 수를 출력해주는 proc_test_count 프로시저를 생성해보자.

SQL

CREATE OR REPLACE PROCEDURE proc_test_count IS

output_line varchar2(80);

rec_cnt int := 0;

BEGIN

SELECT COUNT(*) INTO rec_cnt FROM test_table;

output_line := 'Record Count = ' || rec_cnt;

dbms_output.put_line(output_line);

END;

/

프로시저가 생성되었습니다.

Procedure를 실행한 후에 컴파일시 발생한 착오사항을 확인하려면 다음과 같이 SQL*Plus 명령을 사용하면 된다.

SQL> SHOW ERRORS

프로시저가 정상적으로 컴파일 되었을 때 "프로시저가 생성되었습니다." 라는 메시지만 반환된다. 이것은 프로시저가 정상적으로 컴파일 되어 오라클 서버에 의해 Procedure_name으로 관리된다는 의미이다.

따라서 생성된 프로시저를 실행시키기 위해서는 다음과 같이 프로시저를 실행시켜야 한다.

SQL> EXECUTE proc_test_count

Record Count = 10

PL/SQL 처리가 정상적으로 완료되었습니다.

생성된 프로시저를 확인하는 명령은 다음과 같다.

SQL> SELECT text FROM user_source

WHERE name = 'PROC_TEST_COUNT';

이 飁 Procedure_name은 반드시 대문자로 명시해 주어야 한다.

⼧실습예제: 앞의 실습예제에서 생성된 proc_test_count 프로시저를 호출하는 PL/SQL 블록을 작성하시오.

SQL

DECLARE

BEGIN

proc_test_count;

END;

/

Record Count = 10

PL/SQL 처리가 정상적으로 완료되었습니다.



⼆ Stored Function

Function는 다음 두 가지 점에서 Procedure와 다르다.

⼘Function은 값을 반드시 반환하고 프로시저는 선택적이다.

⼘Function은 식의 일부로서 사용된다.

Function의 생성 방법은 Procedure와 유사하고 반드시 반환될 데이터형을 명시해야 한다는 점이 다르다.

Function은 한 가지 값만을 반환함으로 parameter 선언부에는 OUT, IN OUT은 사용하면 안되고 IN만을 선택적으로 사용해야 한다.

Stored Function

CREATE [OR REPLACE] FUNCTION Function_name

[(Parameter, ........)]

RETURN datatype

IS

PL/SQL_Block;


Function의 PL/SQL_Block문에는 값을 반환하기 위해서 다음과 같이 RETURN()문을 사용하여야 한다.

RETURN( {Variable | Expression});

RETURN되는 parameter는 변수나 수식 또는 상수 중에 하나를 사용할 수 있다.

⼧실습예제: 함수로 전달된 값과 test_table의 record_number 값을 비교하여 record_number가 큰 행의 수를 반환하는 func_test_count 함수를 작성하시오.

SQL

CREATE OR REPLACE FUNCTION func_test_count

(rec_num IN INT) RETURN INT

IS

rec_cnt int := 0;

BEGIN

SELECT COUNT(*) INTO rec_cnt FROM test_table

WHERE record_number > rec_num;

RETURN(rec_cnt);

END;

/

프로시저가 생성되었습니다.


⼧실습예제: func_test_count함수의 실행 결과를 출력하는 PL/SQL 블록을 작성하시오.

SQL

DECLARE

output_line varchar2(80);

check_num int := 5;

BEGIN

output_line := 'Check Count = '

|| func_test_count(check_num);

dbms_output.put_line(output_line);

END;

/

Check Count = 5

PL/SQL 처리가 정상적으로 완료되었습니다.


'프로그래밍 > DB' 카테고리의 다른 글

[펌] Oracle - PL/SQL  (0) 2007.11.27
[펌] PL/SQL 조건문 만들기  (0) 2007.11.27
[펌] PL-SQL 정리  (0) 2007.11.27
select * from user_catalog;  (0) 2007.11.27
[펌] SQL*Plus에서 꼭 알아두어야 할 활용 매뉴얼~!  (0) 2007.11.27

[펌] PL-SQL 정리

프로그래밍/DB 2007. 11. 27. 14:32 Posted by galad
출처 블로그 > 사랑 추억 행복 미움 아픔 미소 눈물 웃음 향기 넌??
원본 http://blog.naver.com/realkorz/40001933479

SQL

SELECT

DML(데이터 조작어)

INSERT, UPDATE, DELETE

DDL(데이터 정의어) IMPLICIT COMMIT

CREATE, ALTER, DROP, RENAME, TRUNCATE

TCL(트랜잭션 제어)

COMMIT, ROLLBACK, SAVEPOINT

DCL(데이터 제어어)IMPLICIT COMMIT

GRANT, REVOKE

 

[1] Writing Basic SQL Statements

1. SELECT 기본 문장(선택, 프로잭션, 조인)

SELECT [DISTINCT] { *, column [alias], ... }

  FROM table ;

 

2. SELECT 예제

SELECT * FROM dept ;

SELECT deptno, loc FROM dept ;

SELECT ename, sal, 12 * (sal + 100) FROM emp ;

* Null 값과 연산을 하면 Null이 나온다.

 

3. Column Alias 예제

SELECT ename AS nme, sal salary

FROM emp ;

SELECT ename "Name", sal*12 "Annual Salary"

FROM emp ;

* 대소문자를 구분하고 공백있는 컬럼 Alias를 만들고 싶을땐 " "로 막는다.

* AS는 안 써도 된다.

* WHERE, GROUP BY절에는 안된다. ORDER BY 절에는 사용 가능.

 

4. Concatenation 연산자 (|| : pipeline 2)

SELECT ename||job "Employees" FROM emp ;

--> ename 데이터와 job 데이터가 붙어서 출력된다.

 

5. 문자열을 데이터로 출력할때

SELECT ename||' '||'is a'||' '||job "Employee Details"

FROM emp ;

* 문자열은 ' '로 막고, 컬럼 Alias " "로 막는다.

 

6. DISTINCT keyword :

중복된 Row를 하나로 만들어 준다. 자동 SORTING[ASC]

SELECT DISTINCT deptno

FROM emp ;

* DISTINCT 대신 UNIQUE를 써도 된다.

 

7. SQL*Plus Log On 방법

* UserName, PassWord, HostString에 일일이 입력해도 되지만,

UserName username/password@HostString이라고 입력하면 된다.

* UNIX상에서 command로 들어 갈 때는 sqlplus username/password 만 입력하면된다.

 

8. 테이블 구조보는 SQL Command (DESC)

SQL> DESC dept : Column Name, Null?, Data Type display

 

9. SQL*Plus Editing Commands( 다음 행까지 계속하려면 -(하이픈)으로 연결한다.)

A[PPEND] text    : 현재 line의 마지막 문장 뒤에 text를 붙인다.

C[HANGE]/old/new : 현재 line old text new text로 바꾼다.

C[HANGE]/text/   : 현재 line text를 삭제한다.

CL[EAR] BUFF[ER] : buffer의 내용을 모두 지운다.

DEL              : 현재 line을 지운다.

DEL n            : n번째 line을 지운다.

DEL m n          : m ~ n번째 line을 지운다.

I[NPUT]          : 현재 line 다음에 line이 제한없이 추가된다.

I[NPUT] text     : 현재 line 다음에 line이 추가되면서 text가 들어간다.

L[IST]           : buffer전체를 보여준다.

L[IST] n         : n번째 line을 보여준다.

R[UN] or /       : SQL, PL/SQL문장을 실행하라!

n                : n번째 line display하면서 Editing 상태로 해준다.

n text           : n번째 line text로 바뀐다.

0 text           : 1번째 line이 추가되면서 text 1번째 line으로 들어간다.

* Bald로 표시된 명령어는 line번호를 먼저 수행한 후 실행해야 한다.

 

10. SQL*Plus File Commands

SAV[E] filename [REP[LACE]|APP[END]] : buffer의 내용을 filename.sql로 저장한다.

GET filename     : filename.sql buffer로 불러온다.

START filename   : filename.sql을 실행하라.

@filename        : START filename과 같다.

ED[IT]           : buffer의 내용을 edit program으로 실행한다.

ED[IT] filename  : filename.sql edit program으로 실행한다.

SPO[OL] filename : retrieve data filename.lst로 저장한다.

SPOOL OFF        : SPOOL을 끝내라.

SPOOL OUT        : retrieve data system printer로 출력하라.

EXIT             : SQL*Plus를 종료한다.

* SPOOL 사용법

SQL> spool filename

SQL> select ...

SQL> spool off

 

11. Special Tip

* 잠시 host상태로 나가고 싶을 때.

SQL> ! ( $)

-- host 상에서 다시 SQL로 들어가려면 exit(lo)

-- unix 상에서 env를 치면 오라클 환경을 볼 수 있다.

 

* SQL> define -editor

--> Editor vi인지..다른 edit프로그램인지를 보여준다.

 

* line size 바꾸기

SQL> SET PAGESIZE 20 -- page 20line으로 보여준다.

-- log off하면 사라진다.

 

* NLS값 보기

SQL> select * from V$NLS_PARAMETERS

 

* NLS값 바꾸기

SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'

-- SESSION : session동안만 YYYY-MM-DD 포맷으로 사용한다는 뜻.

sqlplus가 종료되면 원상태로 복구된다.

 

[2]Restricting and Sorting Data

1. 비교연산자

=  : Equal to

>  : Grater than

>= : Greater than or equal to

<  : Less than

<= : Less than or equal to

<> : Not equal to

) SELECT ename, sal, comm

FROM emp

WHERE sal <= comm ;

 

2. 비교연산자 2

BETWEEN A AND B , IN(list), LIKE, IS NULL

 

3. BETWEEN 연산자( NOT BETWEEN )

SELECT ename, sal

FROM emp

WHERE sal BETWEEN 1000 AND 1500 ; --> sal >= 1000 and sal <= 1500

 

4. IN 연산자( NOT IN )

SELECT emp, ename, sal, mgr

FROM emp

WHERE mgr IN (7902, 7566, 7788) ; --> mgr = 7902 or mgr = 7566 or mgr = 7788

 

5. LIKE 연산자( NOT LIKE )

1) SELECT ename

FROM emp

WHERE ename LIKE 'S%' ; --> ename S로 시작하는 모든 데이터를 찾는다.

2) SELECT ename

FROM emp

WHERE ename LIKE '_A%' ; --> 두 번째 글자가 A인 모든 데이터를 찾는다.

3) SELECT ename

FROM emp

WHERE ename LIKE '%A/_%B' ESCAPE '/' ;

--> '/' Escape문자로 정의되었기 때문에 '_'도 문자로 인식한다.

, ename A_로 포함하는 모든 데이터를 찾는다.

* ESCAPE는 모든 문자가 가능하다.

 

6. IS NULL 연산자

SELECT ename, mgr

FROM emp

WHERE mgr IS NULL ; --> mgr null인 데이터를 찾는다.

 

7. Logical 연산자

AND : 두 개의 조건이 모두 만족해야 OK

OR  : 한 개의 조건만 만족하면 OK

NOT

 

8. AND 연산자

SELECT empno, ename, job, sal

  FROM emp

 WHERE sal >= 1100

AND job = 'CLERK' ;

 

9. OR 연산자

SELECT empno, ename, job, sal

  FROM emp

 WHERE (sal >= 1100 OR job = 'CLERK') ;

 

10. NOT 연산자

SELECT ename, job

FROM emp

WHERE job NOT IN ('CLERK', 'MANAGER') ;

--> NOT (job = 'CLERK OR job = 'MANAGER')

 

11. 연산자 우선순위( 산술 > 문자 > 비교 > 논리 )

1 : 모든 비교 연산자

2 : NOT

3 : AND --> False > Null > True

4 : OR --> True > Null > False

) A AND B에서...

- A False이고 B Null이면... False 이다.

- A True이고 B Null이면.... Null이다.

 

12. SORT (ORDER BY)

* ASC default값이다.(작은 값부터..)

* 값이 Null일 때 가장 큰 값이 된다. (ASC일 때...맨 뒤에 붙는다.)

* column alias sorting이 된다.

1) SELECT ename, job, deptno, hiredate "Date"

       FROM emp

   ORDER BY hiredate["Date" or 4 ] ;

 

2) SELECT ename, job, deptno, hiredate

       FROM emp

      ORDER BY hiredate DESC ;

 

3) SELECT empno, ename, sal*12 annsal

       FROM emp

   ORDER BY empno, annsal ; * select 절에 없는 열을 기준으로 정렬 가능.

 

4) SELECT ename, deptno, sal

       FROM emp

   ORDER BY deptno, sal DESC

 

[3] Single-Row Functions

1. Character Functions

LOWER( column|expression )

LOWER('String') --> string : 소문자로 변환

UPPER( column|expression )

UPPER('String') --> STRING : 대문자로 변환

INITCAP( column|expression )

INITCAP('string') --> String : 첫글자만 대문자이고 나머지글자는 소문자로 변환

CONCAT( column1|expression1 ,column2|expression2 )

CONCAT('Good','String') --> GoodString : ||와 같은 역할을 한다.

SUBSTR(column|expression, m [,n]) : m값이 음수면 문자값의 끝부터..)

SUBSTR('String',1,3) --> Str : 1번째부터 3개의 문자를 리턴한다.

LENGTH( column|expression )

LENGTH('String') --> 6 : 문자열의 길이를 리턴한다.

INSTR( column|expression, )

INSTR('String','r') --> 3 : 문자열에 'r'이 몇번째 위치하고 있나를 리턴한다.

LPAD( column|expression,n,'string' ) : n 은 전체 길이

LPAD('String',10,'*') --> ****String

: 10자리수중에 모자란 자리수를 '*'로 왼쪽에 채운다.(문자,숫자 가능!!!)

RPAD('String',10,'*') --> String****

: 10자리수중에 모자란 자리수를 '*'로 오른쪽에 채운다.(문자,숫자 가능!!!)

LTRIM(' String') --> 'String' : 문자열의 왼쪽 공백을 버린다.

RTRIM('String ') --> 'String' : 문자령의 오른쪽 공백을 버린다.

* TRIM(leading/tailing/both, trim_character FROM trim_source )

TRIM( 'S' FROM 'SSMITH') --> MITH

 

2. Number Functions

ROUND(45.926, 2) --> 45.93 : 소수점 두자리수까지 보여주면서 반올림한다.

TRUNC(45.926, 2) --> 45.92 : 소수점 두자리까지만 보여주고 나머지는 버린다.

MOD(1600,300) --> 100 : 1600 300으로 나누고 나머지를 리턴한다.

* ROUND예제(WHOLE NUMBER:정수)

SELECT ROUND(45.923,2), ROUND(45.923,0), ROUND(45.923,-1) FROM DUAL

==> 45.92 46 50

* TRUNC예제

SELECT TRUNC(45.923,2), TRUNC(45.923), TRUNC(45.923,-1) FROM DUAL

==> 45.92 45(n이 생략된면 일의 자리까지 남기고 버린다.) 40

* SYSTEM 날짜를 갖고 오는 방법.

SELECT sysdate FROM dual

 

3. Date 계산( 날짜를 숫자로 저장)

date + number : date number만큼 후의 날자를 보여준다.

date - number : date number만큼 전의 날자를 보여준다.

date1 - date2 : date1에서 date2 까지의 총 일수를 보여준다.( date1+date2 X )

date1 + 숫자/24 : date1에서 시간을 더해 날짜를 보여준다.

4. Date Functions

MONTHS_BETWEEN('01-SEP-95','11-JAN-94') --> 19.6774194

; 두날짜 사이의 달수를 보여준다.

ADD_MONTHS('11-JAN-94', 6) --> 11-JUL-94

; 날짜에 6개월을 더한 날자를 보여준다.

NEXT_DAY('01-SEP-95','FRIDAY') --> '08-SEP-95'

; 해당일 다음에 오는 FRIDAY의 일자를 보여준다.

('SUNDAY' 1, 'MONDAY' 2...이런식으로 숫자를 써줘도 된다.)

LAST_DAY('01-SEP-95') --> '30-SEP-95'

; 해당월의 마지막날자를 보여준다.

ROUND('25-JUL-95','MONTH')--> 01-AUG-95 ROUND('25-JUL-95','YEAR')--> 01-JAN-96

TRUNC('25-JUL-95','MONTH') --> 01-JUL-95 TRUNC('25-JUL-95','YEAR') --> 01-JAN-95

 

5. Conversion Functions

nlsparams : 십진수, 그룹구분자, 지역 통화 기호, 국제 통화 기호

TO_CHAR(date,['format'],[nlsparams]) : date format에 맞게 문자열로 변환한다.

- Date Format Elements

YYYY --> 1999 (년출력) , YEAR --> nineteen ninety-nine (년출력)

MM --> 12 (월출력) , MONTH --> DECEMBER (월출력), MON --> DEC

D --> 요일을 숫자로 리턴한다.(일요일은 1, 월요일은 2...)

DD --> 07 (달의 일출력)

DDD --> 200 (연의 일출력)그 해의 총 몇 일째인가를 리턴한다.

DAY --> MONDAY (요일출력) DY-->MON

CC --> 20 (몇 세기인지를 보여준다.)

WW --> 그 해의 몇 번째 주인가를 리턴한다.

W --> 그 달의 몇 번째 주인가를 리턴한다.

 

* Element들을 소문자로 쓰면 소문자로 나오고 대문자로 쓰면 대문자로 출력된다.

HH or HH12 or HH24 / MI(0-59) / SS(0-59)

 

* 문자열은 " " 묶어 추가한다 DD " of " MONTH --> 12 of DECEMBER

*숫자 접미어는 숫자를 문자로 표기. TH(4->4TH)/ SP(4->FOUR)/ SPTH or THSP(4->FOURTH)

ddspth : 14-> fothteenth

* / . , : 구두점은 결과에 그대로 출력한다. * 공백, 선행제로를 제거하는 fm요소가 있다.

TO_CHAR(number,'format',[nlsparams]) : number format에 맞게 문자열로 변환한다.

- Number Format Elements

9 : 999,999 --> 1,234 $: 부동 달러 기호 $99999 -> $1234

0 : 099999 --> 001234 99.999EEEE -> 1.234E+03 B: 0값을 공백으로

L : L99,999 --> FF1,234 (NLS_CURRENCY에 설정되어있는 값이 L로 보여진다.)

 

TO_NUMBER(char,['format'],[nlsparams]) : 숫자형태의 문자열을 숫자로 변한한다.

TO_DATE(char,['format'],[nlsparams]):날자형태의 문자열을 format에 맞게 날자형식으로 변환 한다.

 

6. NVL Funcion : 값이 null일 때 설정값을 보여준다.

NVL(number_column, 0) : null일 때 0을 보여준다.

NVL(date_column, '01-JAN-95') : null일 때 '01-JAN-95'를 보여준다.

NVL(character_column, 'Empty') : null일 때 'Empty'를 보여준다.

* column Type과 표현식의 type이 반드시 일치해야 한다.

 

7. DECODE Function : CASE or IF-THEN-ELSE 형식과 비슷하다.

*DECODE(col/expression, search1, result1 [,search2,result2,…] [,default])

F1 (F2 (F3 (col,arg1),arg2),arg3)

 

[4] Displaying Data from Multiple Tables (JOIN)

1. EquiJoin : column1 column2 Primary Key Foreign Key관계인 경우

SELECT emp.empno, emp.ename, emp.deptno, dept.deptno, dept.loc

FROM emp, dept

WHERE emp.deptno = dept.deptno

 

2. Non-EquiJoin : Join하는 Table 사이에 서로 대응하는 Key가 없는 경우

where절의 Join조건에 '='을 제외한 비교연산자를 사용한다.

SELECT e.ename, e.sal, s.grade

FROM emp e, salgrade s

WHERE e.sal BETWEEN s.losal AND s.hisal

 

3. Outer Join : 서로 = 되지 않는 row 까지도 모두 보여준다.

정보가 없는쪽 컬럼 뒤에 (+)를 붙인다.( =, and 만 사용가능)

SELECT e.ename, d.deptno, d.dname

FROM emp e, dept d

WHERE e.deptno (+) = d.deptno

ORDER BY e.deptno

 

4. Self Join : 같은 Table을 그것이 마치 2개의 Table인 것처럼 Join해서 사용한다.

SELECT worker.ename, manager.ename

FROM emp worker, emp manager

WHERE worker.mgr = manager.empno

 

5. SET OPERATORS

UNION : 중복된 row는 제외하고 보여준다. UNION ALL : 중복된 row까지 모두 보여준다. INTERSECT : A,B의 중복된 row만 보여준다.MINUS : A,B의 중복된 row를 제외한 A row를 보여준다.

 

[5] Aggregating Data Using Group Functions(그룹함수를 사용한 데이터집계)

1. Group Function : 행집합에 적용하여 그룹당 하나의 결과를 생성한다.

AVG([DISTINCT|ALL] n) : 평균값

COUNT({*|[DISTINCT|ALL] expr}) : row

MAX([DISTINCT|ALL] expr) : 최대값

MIN([DISTINCT|ALL] expr) : 최소값

SUM([DISTINCT|ALL] n) :

STDDEV([DISTINCT|ALL] x) : 표준편차

VARIANCE([DISTINCT|ALL] x) : 분산

* count(*)를 제외한 모든 Group Function Null을 배제하고 수행한다.

Null을 포함하고 싶다면 NVL함수를 사용한다.

* DISTINCT ALL을 쓰지 않으면 Default ALL이다.

* AVG,SUM, STDDEV, VARIANCE는 반드시 숫자형이다.

 

2. 어떤 컬럼에 해당하는 데이터별 그룹함수를 사용할 때

SELECT [deptno,] COUNT(ename)

FROM emp --> 이문장은 성립되지 않는다. GROUP BY가 없다.

<추가>

GROUP BY deptno

*일반칼럼과 그룹함수를 같이 쓰면 group by절에 일반칼럼 명시(열 별칭 사용못함)

*GROUP BY 열을 SELECT 절에 포함시키지 않아도 된다

 

3. 그룹함수는 WHERE절에 올수가 없다.

SELECT deptno, AVG(sal)

FROM emp

WHERE AVG(sal) > 2000

GROUP BY deptno

--> 이문장은 성립되지 않는다. WHERE절에 그룹함수가 올 수 없다.

 

SELECT deptno, AVG(sal)

FROM emp

GROUP BY deptno

HAVING AVG(sal) > 2000

 

4. HAVING : 그룹함수를 조건절에 적용시키기 위해서 사용한다.

SELECT job, SUM(sal)

FROM emp

WHERE job NOT LIKE 'SALES%'

GROUP BY job

HAVING SUM(sal) > 5000

ORDER BY SUM(sal)

*절 평가 순서 : WHERE -> GROUP BY -> HAVING

*그룹함수는 두번까지 중첩될수 있습니다. MAX( AVG(SAL))

 

[6] Subqueries( WHERE , HAVING , FROM )

1. Subquery 규칙

- 반드시 ()로 묶어야 한다.

- 반드시 비교연산자 오른쪽에 위치해야 한다.

- ORDER BY 절에는 사용할 수 없다.

- 서브쿼리 결과가 한개일때는 Single-Row 비교연산자를 사용해야 한다.

( =, >, >=, <, <=, <> )

- 서브쿼리 결과가 여러개일때는 Multi-Row 연산자를 사용해햐 한다.

 

2. Subquery 사용예1

* 반드시 비교연산자 오른쪽에 써야한다.

SELECT ename FROM emp

WHERE sal > (SELECT sal FROM emp

WHERE empno = 7566)

 

3. Subquery 사용예2

SELECT ename, job

FROM emp

WHERE job = (SELECT job

FROM emp

WHERE empno = 7369)

AND

sal > (SELECT sal

FROM emp

WHERE empno = 7876)

 

4. Subquery 사용예3

SELECT job, AVG(sal)

FROM emp

GROUP BY job

HAVING AVG(sal) > (SELECT MIN(AVG(sal))

FROM emp

GROUP BY job)

 

5. Subquery 사용예4 (Subquery 결과가 여러개가 나올때 비교연산자 사용법)

SELECT empno, ename

FROM emp

WHERE sal IN (SELECT MIN(sal) ( =ANY 와 같음 )

FROM emp

GROUP BY deptno)

 

6. ANY(동의어:SOME)연산자를 사용한 Subquery : 조건중에 한개만 만족하면 OK

SELECT empno, ename, job

FROM emp

WHERE sal < ANY (SELECT sal --> OR

FROM emp

WHERE job = 'CLERK')

AND job <> 'CLERK'

 

7. ALL연산자를 사용한 Subquery : 모든 조건을 만족해야 OK

SELECT empno, ename, job

FROM emp

WHERE sal > ALL (SELECT avg(sal) --> AND

FROM emp

GROUP BY deptno

 

[7] Multiple-Column Subqueries

1. Multiple-Column Subquery (Pairwise Subquery)

: 서브쿼리의 결과가 두개 이상의 컬럼형식으로 나올 때 비교하는 컬럼도 서브쿼리 컬럼

갯수와 형식이 같아야한다.

SELECT ename, deptno, sal, comm

FROM emp

WHERE (sal, NVL(comm,-1)) IN

(SELECT sal, NVL(comm,-1)

FROM emp

WHERE deptno = 30)

 

2. NonPairwise Subquery

SELECT ename, deptno, sal, comm

FROM emp

WHERE sal IN (SELECT sal FROM emp

WHERE deptno = 30)

AND

NVL(comm,-1) IN (SELECT NVL(comm,-1) FROM emp

WHERE deptno = 30)

 

3. Subquery 안에 Null값이 있을 때...

* 매니저가 아닌 사원을 보여주기?

SELECT e.ename

FROM emp e

WHERE e.empno NOT IN

(SELECT m.mgr FROM emp m)

IN Null value가 나와도 한개의 조건만 만족하면 OK이지만,

NOT IN !=ALL과 같아서 모든조건이 TRUE여만 TRUE인 것이다.

* NOT IN !=ANY 로 바꿔주는게 정답에 가깝다.

 

4. FROM절에 사용되는 Subquery

SELECT a.ename, a.sal, a.deptno, b.salavg

FROM emp a,

(SELECT deptno, avg(sal) salavg

FROM emp

GROUP BY deptno) b

WHERE a.deptno = b.deptno

AND a.sal > b.salavg

 

5. EXISTS : EXISTS 뒤에 나오는 서브쿼리의 결과가 한건이 row라도 있다면 O.K

SELECT dname, deptno

FROM dept

WHERE EXISTS (SELECT * FROM emp

WHERE dept.deptno = emp.deptno)

: 행의 존재유무만 확인

 

[8] Producing Readable Output with SQL*Plus

1. Substitution Variable (치환변수)

& : 변수가 한 번 사용되고 메모리에서 사라진다.

&& : 한 번 입력한 변수는 CLEAR하기 전까지 계속 메모리에 남아있다.

DEFINE variable=value : CHAR 데이터 유형의 사용자 변수를 생성하여 값을 변수에 할당한다.

DEFINE : 현재 DEFINE 된 모든 것들을 보여준다.

DEFINE 변수명 : 지정한 변수명의 DEFINE 사항을 보여준다.

UNDEFINE 변수명 : 지정한 변수명의 DEFINE 상태를 CLEAR한다.

ACCEPT : 변수를 입력하라고 물어보는 Prompt Text를 변경할수 있다. USER

입력하는 값을 HIDE시킬수가 있다. DataType Format을 변경할수가 있다.

* SET VERIFY SQL*PLUS 가 치환변수를 값으로 바꾸기 전후의 명령 텍스트 표시를 토글한다.

2. & 치환변수 사용예

SELECT empno, ename, sal, deptno

FROM emp

WHERE empno = &employee_num

 

3. && 치환변수 사용 예 --> 한번만 물어보게 된다.

SELECT empno, ename, job, &&column_name

FROM emp

ORDER BY &column_name

 

4. 변수 값이 character or date value일때 꼭 single quotation mark로 묶어 줘야 한다.

SELECT ename, deptno, sal*12

FROM emp

WHERE job = '&job_title'

 

5. 종합적인 예제(실행중에 열이름, 표현식, 텍스트를 지정)

--> 어떤 절에나 사용해도 된다.

SELECT empno, ename, job, &column_name

FROM emp

WHERE &condition

ORDER BY &order_column

 

6. ACCEPT 사용예 (file로 만들어서 START시켜야 한다.)

*ACCEPT variable [datatype] [FORMAT format] [PROMPT text] [HIDE]

ACCEPT dept PROMPT 'Provide the department name: '

SELECT *

FROM dept

WHERE dname = UPPER('&dept')

/

Provide the department name: Sales

처리된 결과값...

 

7. 파일로 만들어서 치환변수를 여러개 처리할때 예제

test.sql

SELECT &1 FROM &2

SQL> @test empno emp

==> &1 empno, &2 emp가 들어간다.(define)

 

SELECT &2 FROM &4

SQL> @test e empno b emp

==> &1 e, &2 empno,&3 b, &4 emp가 들어간다.(define)

 

8. SET command 변수

ARRAY[SIZE] {20 | n} : 데이터 fatch size

COLSEP {_ | text} : column seperator

FEED[BACK] {6 | n | OFF | ON} : n 개이상의 레코드 반환시 레코드 수를 표시

HEA[DING] {OFF | ON} : column heading 출력

LIN[ESIZE] {80 | n} : 가로 80 으로 출력

PAGES[IZE] {50 | n} : 세로 50 으로 출력

LONG {80 | n} : long date type의 데이터를 출력할때 80byte까지만 보여주겠다.

PAU[SE] {OFF | ON | text} : text에 문자열을 넣으면 pause될 때마다 메시지를 보여준다.

TERM[OUT] {OFF | ON} : 결과를 화면에 보여주겠는가?

VERIFY {OFF | ON} : 치환변수의 old값과 new값을 보여주면서 결과가 처리된다.

* SHOW {SET command } : SET command명의 현재 상태를 보여준다. SQL> SHOW ECHO)

* SHOW ALL : 모든 SET command의 현재 상태를 보여준다.

* SET 상태를 바꿔 주려면... SQL> SET PAUSE ON <-- 이런식으로 하면 된다.

* DEFINE command SET command는 자신의 환경파일(login.sql)에 일괄적으로 처리 할수 있다.

* login.sql oracle superuser용 환경파일이다.

* SQL Plus command가 다음 줄로 이어질 때는 (-)으로 연결한다.

 

9. REPORT 출력 예

SET PAGESIZE 37 --> 세로 37로 출력

SET LINESIZE 60 --> 가로 60으로 출력

SET FEEDBACK OFF

TTITLE 'Employee|Report' --> Top Title Employee 다음 줄에 Report를 쓰겠다.

BTITLE 'Confidential' --> Bottom Title Confidential로 쓰겠다.

COLUMN job HEADING 'Job|Category' FORMAT A15 : | text를 두줄로 찍는다.

--> job column Heading Job 다음줄에 Category로쓰고 15byte의 자리수로

만들겠다.

형식 : COL[UMN] [{column | alias } [option]]

COL[UMN] [column], COL[UMN] column CLE[AR], CLE[AR] COL[UMN]

 

옵션 : CLE[AR], FOR[MAT] format, HEA[DING] text, JUS[TIFY] {align}, NUL[L] text,

NOPRI[NT]:열을 숨김니다 <> PRI[NT],

TRU[NCATED] : 첫 행 끝에 표시되는 문자열을 잘라버린다.

WRA[PPED] : 문자열의 끝을 다음 행으로 줄바꿈합니다.

REM ** Insert SELECT statement --> 주석문

*BREAKE 명령?

 

[9] Multipulating Data (DML)

*트랜젝션 : 논리 작업 단위를 형성하는 DML 문 모음으로 구성된다., DDL(한개),DCL(한개)

1. INSERT 예제1

: 모든 컬럼에 INSERT할 때는 컬럼명을 쓰지 않아도 되지만 테이블 CREATE

만들어진 순서대로 입력해야한다.

INSERT INTO dept

VALUES (50,'AAA','BBB')

* NULL 값을 갖는 행 삽입시 열목록에서 열을 생략(암시적)하는 방법과

NULL 키워드를 지정(명시적)하는 방법이 있다.

 

2. INSERT 예제2

INSERT INTO emp ( empno, ename, job, mgr, hiredate, sal, comm, deptno )

VALUES ( 7196, 'GREEN', 'SALESMAN', 7782, SYSDATE, 2000, NULL, 10 )

 

3. sql 파일로 만들어서 Argument를 받으면서 INSERT 실행하기.

* test.sql 파일

ACCEPT department_id PROMPT 'Please enter the department number: '

ACCEPT department_name PROMPT 'Please enter the department name: '

ACCEPT location PROMPT 'Please enter the location: '

INSERT INTO dept ( deptno, dname, loc )

VALUES (&department_id, '&department_name', '&location' )

 

SQL> @test = START test

Please enter the department number: 90

Please enter the department name: PAYROLL

Please enter the location: HOUSTON

 

1 row created

4. 다른 테이블의 row Copy하기(VALUES 절을 사용하지 않는다.)

INSERT INTO managers (id, name, salary, hiredate)

SELECT empno, ename, sal, hiredate

FROM emp

WHERE job = 'MANAGER'

 

5. UPDATE 예제1

UPDATE emp

SET deptno = 20,

sal = 2500,

comm = null

WHERE empno = 7782

 

6. UPDATE 예제2 (Multiple-Column Subquery를 사용한 예)

UPDATE emp

SET (job, deptno) = (SELECT job, deptno

FROM emp

WHERE empno = 7499)

WHERE empno = 7689

 

7. UPDATE 예제3 (다른 테이블에 있는 데이터를 SELECT해서 UPDATE하기)

UPDATE employee

SET deptno = (SELECT deptno FROM emp WHERE empno = 7788)

WHERE job = (SELECT job FROM emp WHERE empno = 7788)

 

8. DELETE 예제1 (조건에 맞는 데이터 지우기)

DELETE FROM dapartment

WHERE dname = 'DEVELOPMENT'

 

9. DELETE 예제2 (한 테이블의 전체 데이터 삭제)

DELETE FROM department

 

10. DELETE 규칙

* FROM은 옵션이므로 사용하지 않아도 된다.(: DELETE department)

* Primary Key, Forien Key 관계가 설정되어 있는 데이터를 DELETE할때는 문제가 발생 할 수 있다.

 

11. COMMIT

* 변경된 데이터를 Fix시킨다.

* 이전상태의 데이터는 모두 잃게 된다.

* 모든 User가 결과를 볼수 있다.

* LOCK이 풀린다.

* 모든 SavePoint들이 clear된다.

* 자동 커밋 : DDL, DCL, 정상 종료시

12. ROLLBACK

* 변경된 데이터를 undo 시킨다.

* Transaction 전단계의 데이터로 돌아간다.

* Lock이 풀린다.

* 자동 롤백 : 비정상 종료, 시스템 장애

13. SAVEPOINT 예제

* SAVEPOINT : Transaction이 일어난 곳에 Marking을 할 수가 있다.

* 오라클은 자동적으로 눈에 안보이는 savepoint를 찍어 놓는다.

SQL> UPDATE.....

SQL> SAVEPOINT update_done ;

Savepoint created.

SQL> INSERT.....

SQL> ROLLBACK TO update_done ;

Rollback complete.

 

14. TABLE LOCK 예제 (DBA가 임으로 TABLE LOCK을 걸 수가 있다.)

 

 

[10] Creating and Managing Tables (DDL)

1. Database Objects

TABLE, VIEW, SEQUENCE, INDEX, SYNONYM

 

2. Object Naming Rule

- 반드시 첫글자는 문자이어야 한다.

- 길이는 1 ~ 30 글자 이다.

- A-Z, a-z, 0-9, _, $, # 만을 사용할수 있다.

- 동일한 Object명이 존재해서는 안된다.(다른 user가 소유한 table과는 중복가능)

- 오라클 서버의 예약어는 사용할 수 없다.

 

3. CREATING TABLES( create 권한, 저장영역이 필요 )

CREATE [GLOBAL TEMPORARY] TABLE [schema.]table

( column datatype [DEFAULT expr] [,...] );

*GLOBAL TEMPORARY : 임시 table로 지정, 정의는 모든 세션에서 볼 수 있지만,

데이터는 데이터를 삽입하는 세션에서만 볼 수 있다.

* DEFAULT : 다른 열의 이름이나, 의사열은 잘못된 값이다.

* CREATE TABLE dept

( deptno NUMBER(2), dname VARCHAR2(14), loc VARCHAR2(13),

dymd DATE DEFAULT SYSDATE )

 

4. Data Dictionary

USER_ : 사용자가 소유하는 객체에 대한 정보

ALL_ : 사용자가 ACCESS 할 수 있는 모든 TABLE 에 대한 정보

DBA_ : DBA 롤을 할당 받은 사용자만 ACCESS 할 수 있다.

V$_ : 동적 성능(Performance) , DB SERVER 성능 및 잠금에 관한 정보.

 

* DICT 테이블 안에 모든 data dictionary 정보가 있다.

>> 유저가 소유한 개별 객체 유형을 봄.

SELECT * FROM USER_TABLES

>> 유저가 소유한 TABLE, VIEW, 동의어, 시퀀스를 봄.

SELECT DISTINCT object_type

FROM USER_OBJECTS ( USER ACCESS 할 수 있는 ALL_OBJECTS )

>> User가 소유한 TABLE을 설명.

SELECT * FROM USER_CATALOG

--> SELECT * FROM cat 이라고 써도 된다.

>> 모든 테이블 이름보기 SELECT * FROM TAB

>> 컬럼 정보 보기 USER_TAB_COLUMNS

 

5. Data Types

VARCHAR2(size) : Variable-length character data (1 ~ 4000 bytes)

CHAR(size) : Fixed-length character data (1 ~ 2000 bytes)

NUMBER(p,s) : p - precision, s - scale

DATE : B.C.4712-01-01 ~ A.D.9999.12.31

LONG : Variable-length character data (2GB)

- table 당 하나 - constraints 사용 못함

- order by, group by에서 사용못함 - 서브쿼리에서 사용할 때 not copy

LONG RAW : Raw binary data of variable length up to 2 gigabytes

RAW(size) : 2000 byte

CLOB : Single-byte character data up to 4 gigabytes

BLOB : Binary data up to 4 gigabytes

BFILE : binary data stored in an external file; up to 4 gigabytes

 

6. Subquery를 사용해서 테이블 복사하기(새로운 table datatype 정의는 필요없다)

CREATE TABLE dept30

AS

SELECT empno, ename, sal*12 ANNSAL, hiredate

FROM emp

WHERE deptno = 30

 

* computed field일때 반드시 컬럼 alias를 줘야 한다. (ANNSAL)

* computed 컬럼으로 만들어진 컬럼 타입 NUMBER일 때 기존의 자릿수는 사라지고

최대자리수로 잡힌다.

* column, type, data 모든것이 복사된다.(NOT NULL constraints 만 상속된다.)

* key constraint는 정의되지 않는다.

* WHERE조건을 false가 되게 만들면 데이터는 복사되지 않는다.

 

7. 테이블에 컬럼 추가 하기

ALTER TABLE dept30

ADD ( job VARCHAR2(9) )

-> 열을 추가할 때 모든 행은 초기에 null 값을 가진다.( not null 제약조건 X )

 

8. 테이블에 있는 기존 컬럼 수정하기

ALTER TABLE dept30

MODIFY ( ename VARCHAR2(15) )

 

* 제약사항.

- 숫자타입에서 자릿수를 늘리는건 가능하다.

- 숫자타입에서 자릿수를 줄일때는 모든 data null이거나 데이터가 한건도 없을 때만 가능하다.

- char <--> varchar2 로 바꿀때는 모든 data null이거나 데이터가 한건도 없을 때만 가능하다.

- default값도 바꿀 수 있다.(기존 default값은 유지된다.)

- column name modify 가 안된다.

=> 열을 추가(ADD), 수정(MODIFY)할 수 있지만 table에서 삭제할 수 없다.

 

<oracle 8i 가능>

1.> ALTER TABLE table SET UNUSED (column);

OR

ALTER TABLE table SET UNUSED COLUMN column;

2.>ALTER TABLE table DROP UNUSED COLUMNS;

 

9. DROP TABLE

DROP TABLE dept30

 

10. OBJECT 이름 바꾸기

RENAME dept TO department

 

11. TRUNCATE TABLE

TRUNCATE TABLE department

* ROLLBACK을 절대로 할 수 없다.

* 로그없이 테이블의 전체 데이터가 삭제되고 COMMIT이 된다.

* 저장공간을 해제( DELETE 문은 해제할 수 없다.)

 

12. 테이블에 주석문 추가하기

COMMENT ON TABLE emp

IS 'Employee Information'

 

13. 컬럼에 주석문 추가하기

COMMENT ON TABLE emp COLUMN emp.ename

IS 'Employee Name'

 

14. 주석문 삭제하기

COMMENT ON TABLE emp IS ' '

 

15. 주석문을 볼수있는 data dictionary

* Column

ALL_COL_COMMENTS

USER_COL_COMMENTS

* Table

ALL_TAB_COMMENTS

USER_TAB_COMMENTS

 

 

[11] Including Constraints

1. 오라클의 Constraint Type

NOT NULL : null value를 허용하지 않음.

UNIQUE : 유일한 값을 가지면서 null도 허용한다.

PRIMARY KEY : NOT NULL, UNIQUE, TABLE 1개 설정, 참조 당함

FOREIGN KEY : Primary에 연결되어 있어서 Primary에 있는 값들만 갖고 있다.(PK,UK 참조)

CHECK : 정해진 값 이외의 것이 들어오면 Error

 

2. Constraint 규칙

- Constraint을 생성할 때 이름을 주지 않으면 오라클서버는 SYS_Cn 이라고 이름을 자동 생성한다.

- Column level Table level Constraint를 정의한다.

- constraint를 볼 수 있는 Data Dictionary

USER_CONSTRAINTS,USER_CONS_COLUMNS 이다.

 

3. Constraint 정의

* Column Level

column [CONSTRAINT constraint_name] constraint_type,

* Table Level

column,...

[CONSTRAINT constraint_name] constraint_type (column, ...),

(column, ...),

* not null은 반드시 column level로 정의를 내려야 한다.

 

4. NOT NULL Constraint : column level

 

5. UNIQUE Constraint : index 자동 생성

CREATE TABLE dept (

deptno NUMBER(2),

dname VARCHAR2(14),

loc VARCHAR2(13),

CONSTRAINT dept_dname_uk UNIQUE (dname) )

 

6. PRIMARY KEY Constraint

CREATE TABLE dept (

deptno NUMBER(2),

dname VARCHAR2(14),

loc VARCHAR2(13),

CONSTRAINT dept_dname_uk UNIQUE (dname) ,

CONSTRAINT dept_deptno_pk PRIMARY KEY (deptno) )

 

7. FOREIGN KEY Constraint

CREATE TABLE emp (

empno NUMBER(4),

ename VARCHAR2(10) [CONSTRAINT epm_ename_nn] NOT NULL,

job VARCHAR2(9),

mgr NUMBER(4),

hiredate DATE,

sal NUMBER(7,2),

comm NUMBER(7,2),

deptno NUMBER(7,2) NOT NULL,

CONSTRAINT emp_deptno_fk FOREIGN KEY (deptno)

REFERENCES dept (deptno) )

--> dept.deptno emp.deptno Foreign key로 사용하겠다는 뜻.

* column level로 정의할 때는...(FOREIGN KEY 키워드는 생략)

deptno NUMBER(7,2) NOT NULL

CONSTRAINT emp_deptno_fk REFERENCES dept (deptno),

* ON DELETE CASCADE

Foreign key로 연결된 parent data가 삭제될 때 child data도 모두 삭제 되게 만든다.

 

8. CHECK Constraint

..., deptno NUMBER(2),

CONSTRAINT emp_deptno_ck

CHECK (deptno BETWEEN 10 AND 99), ...

--> deptno의 값은 10에서 99 사이에 있는 값들만 입력이 가능하다는 뜻.

* CURRVAL, NEXTVAL, LEVEL, ROWNUM Pseudocolumn엔 허용되지 않는다.

* SYSDATE, UID, USER, USERENV 함수들을 호출할수 없다.

 

* 제약조건을 추가(ADD), 삭제(DROP)할 수 있지만 수정할 수는 없다.

* 제약조건을 설정(ENABLE) 또는 해제(DISABLE)합니다.

* MODIFT 절을 사용하여 NOT NULL 제약조건을 추가합니다.

 

9. ADD Constraint

*ALTER TABLE table_name

ADD [CONSTRAINT constraint] type (column),

ALTER TABLE emp

ADD CONSTRAINT emp_mgr_fk

FOREIGN KEY(mgr) REFERENCES emp(empno)

* Constraint 수정은 할 수 없다.

* not null constraint일 경우 ADD로 하지 않고 MODIFY로 한다.

(기존 행에 null data 값이 없어야 한다.)

 

10. DROP Constraint

*ALTER TABLE table_name

DROP (PRIMARY KEY| UNIQUE (column) |

CONSTRAINT constraint) [CASCADE];

ALTER TABLE emp

DROP CONSTRAINT emp_mgr_fk

* Primary를 삭제할 때 Foreign Key관계(종속된 제약조건) Constraint까지 DROP 하고 싶으면...

ALTER TABLE dept

DROP PRIMARY KEY CASCADE

* CASCADE CONSTRAINTS 절은 DROP COLUMN 절과 함께 사용됩니다.

ALTER TABLE test1 DROP (pk) CASCADE CONSTRAINTS;

 

11. DISABLE CONSTRAINT(CREATE TABLE, ALTER TABLE 문에서 사용)

: ENABLE CONSTRAINT 하기 전까지 실행을 멈춘다.

ALTER TABLE emp

DISABLE CONSTRAINT emp_empno_pk CASCADE

 

12. ENABLE CONSTRAINT(CREATE TABLE, ALTER TABLE 문에서 사용)

ALTER TABLE emp

ENABLE CONSTRAINT emp_empno_pk

* ENABLE 할 때는... 모든 data를 체크하기 때문에 시간이 오래 걸린다.

 

*

13. USER_CONSTRAINTS Data Dictionary

SELECT constraint_name, constraint_type, search_condition

FROM user_constraints

WHERE table_name = 'EMP'

 

--------------------------------------------------------

CONSTRAINT_NAME C SEARCH_CONDITION

------------------------- - --------------------------

SYS_C00674 C EMPNO IS NOT NULL

SYS_C00675 C DEPTNO IS NOT NULL

EMP_EMPNO_PK P

--------------------------------------------------------

 

14. USER_CONS_COLUMNS Data Dictionary

SELECT constraint_name, column_name

FROM user_cons_columns

WHERE table_name = 'EMP'

--------------------------------------------------------

CONSTRAINT_NAME COLUMN_NAME

EMP_DEPTNO_FK DEPTNO

EMP_EMPNO_PK EMPNO

EMP_MGR_FK MGR

SYS_C00674 EMPNO

SYS_C00675 DEPTNO

--------------------------------------------------------

 

 

[12] Creating Views

* Oracle8부터는 View에도 Data를 갖고 있을 수 있다.

* View를 사용하는 이유?

- 데이터베이스 access를 제한한다.

- 복잡한 쿼리를 쉽게 만든다.

- 데이터의 독립을 허용하기 위해

- 동일한 데이터로부터 다양한 결과를 얻기 위해

* view를 만들 때 ORDER BY절을 사용할 수 없다.

* Simple View에는 DML 문장을 수행 할 수 있지만, 함수 또는 데이터 그룹을 포함하지 못한다.

(복합뷰<Complex VIEW> 함수 또는 데이터 그룹을 포함할 수 있다.)

* GROUP함수, GROUP BY, DISTINCT keyword등을 사용한 view에는 행을 delete 할 수 없다.

* 뷰를 사용한 데이터 엑세스

- USER_VIEWS에서 뷰 정의를 검색한다.(select 문의 텍스트는 LONG 열에 저장된다.)

- 뷰의 기본 테이블에 대한 액세스 권한을 확인한다.

- 데이터를 기본 테이블에서 검색 또는 갱신한다.

1. CREATE VIEW 문장

CREATE [OR REPLACE] [FORCE|NOFORCE] VIEW view

[ (alias[, alias]...) ]

AS subquery

[WITH CHECK OPTION [CONSTRAINT constraint]]

[WITH READ ONLY]

 

OR REPLACE : 만들려고 하는 view가 이미 존재할 때 recreate한다.

FORCE : base table이 존재하지 않아도 view를 강제로 만든다.

NOFORCE : base table이 반드시 존재해야만 view를 만들 수 있다.

WITH CHECK OPTION : view를 만들 때 where조건에 있는 value

View를 통해서 DML 문장으로 수정하는 것을 막는다.

WITH READ ONLY : view를 통해서 DML문장을 수행하는 것을 막는다.

 

2. Creating View 예제1

CREATE VIEW empvu10

AS SELECT empno, ename, job

FROM emp

WHERE deptno = 10 ;

--> 이렇게 만들어진 view column이름은 empno, ename, job이 된다.

 

3. Creating View 예제2

CREATE VIEW salvu30

AS SELECT empno employee_number, ename name, sal salary

FROM emp

WHERE deptno = 30 ;

--> column alias를 준 employee_number, name, salary view column이름이 된다.

 

4. VIEW 수정하기 (OR REPLACE)

CREATE OR REPLACE VIEW empvu10

(employee_number, employee_name, job_title)

AS SELECT empno, ename, job

FROM emp

WHERE deptno = 10 ;

 

5. Complex VIEW

CREATE VIEW detp_sum_vu

(naem, minsal, maxsa, avgsal)

AS SELECT d.dname, MIN(e.sal), MAX(e.sal), AVG(e.sal)

FROM emp e, dept d

WHERE e.deptno = d.deptno

GROUP BY d.dname ;

 

6. WITH CHECK OPTION 사용예

CREATE OR REPLACE VIEW empvu20

AS SELECT *

FROM emp

WHERE deptno = 20

WITH CHECK OPTION CONSTRAINT empvu20_ck ;(deptno 20만 작업 가능)

( constraint name을 주지 않으면 SYS_Cn으로 만들어 진다. )

* 예를들어 다음과 같은 update문장을 수행하면 error가 난다.

UPDATE empvu20

SET deptno = 10

WHERE empno = 7788 ;

--> ORA-01402: view WITH CHECK OPTION where-clause violation

 

7. WITH READ ONLY 사용예

CREATE OR REPLACE VIEW empvu10

(employee_number, employee_name, job_title)

AS SELECT empno, ename, job

FROM emp

WHERE deptno = 10

WITH READ ONLY ;

* 예를들어 다음과 같은 DELETE문장을 수행하면 error가 난다.

DELETE FROM empvu10

WHERE employee_number = 7782 ;

--> ORA-01752: Cannot delete from view without exactly one key-preserved table

 

8. View 없애기

DROP VIEW empvu10 ;

 

9. 만들어진 View를 볼때

SELECT * FROM salvu30 ;

* 인라인 view : FROM 절에 사용, 객체가 아님.

 

10. View를 통한 DML 작업 수행에 관한 규칙

*뷰가 다음을 포함한 경우 행을 제거할 수 없슴.

- 그룹함수 - GROUP BY - DISTINCT 키워드 - 의사열 ROWNUM 키워드

*뷰가 다음을 포함한 경우 데이터를 수정할 수 없슴.

- 위에서 언급된 모든 조건(제거할 수 없슴)

- ROWNUM 의사 열 : 하위 질의에서 반환되는 가 행에 1에서 시작하는 순차값을 할당.

*뷰가 다음과 같은 경우 데이터를 추가할 수 없슴.

- 뷰가 위에서 언급한 포함하는 경우.(제거, 수정)

- 기본 테이블에서 뷰에 의해 선택되지 않은 열에 NOT NULL 제약 조건이 있는 경우.

 

11. "TOP-N" 분석 수행

SELECT [column_list], ROWNUM

FROM (SELECT [column_list] FROM table

ORDER BY TOP-N_column)

WHERE ROWNUM <= N ( where 절은 < 또는 <= )

 

[13] Other Database Objects (Sequence, Index, Synonym)

1. Sequence?

- unique한 숫자를 자동으로 부여한다.

- 공유 가능하다.

- primary key 성격을 갖는다.

- cache 설정을 할 수 있기 때문에 빠른 속도를 낼 수 있다.

 

2. CREATE SEQUENCE 문장

CREATE SEQUENCE sequence

[INCREMENT BY n] : default 1

[START WITH n] : default 1

[{MAXVALUE n | NOMAXVALUE}]

[{MINVALUE n | NOMINVALEU}]

[{CYCLE | NOCYCLE}]

[{CACHE n | NOCACHE{] ; : default 20개의 cache

 

INCREMENT BY n : n만큼 증가 한다.

START WITH n : 처음 시작하는 숫자는 n이다.

MAXVALUE n : MAX값은 n이다.

NOMAXVALUE : MAX값은 무한대다. (10^27 OR -1) --> default

MINVALUE n : MIN값은 n이다.

NOMINVALUE : MIN값은 무한대다. (-(10^26) OR 1 ) --> default

CYCLE | NOCYCLE : MAX MIN값으로 갔을때 다시 처음부터 새로

시작할 건지를 설정한다. default NOCYCLE

CACHE n | NOCACHE : n만큼의 CACHE를 줄 것인지를 설정한다.

--> default cache 20으로 잡는다.

 

3. CREATE SEQUENCE 예제

CREATE SEQUENCE dept_deptno

INCREMENT BY 1

START WITH 91

MAXVALUE 100

NOCACHE

NOCYCLE ;

 

4. USER_SEQUENCES data dictionary

SELECT sequence_name, min_value, max_value, increment_by, last_number

FROM USER_SEQUENCES ;

* last_number는 다음에 sequence 가능 한 숫자를 보여준다.

 

5. NEXTVAL CURRVAL

NEXTVAL : Sequence 1개 증가된다.

CURRVAL : 현재 sequence 값을 보여준다.

 

* 사용가능

- SELECT문장에서 SELECT list

- INSERT문장에서 SELECT list, values list

- UPDATE문장에서 SET

 

* 사용불가

- View SELECT list

- SELECT문장에서 DISTINCT keyword

- SELECT문장에서 GROUP BY, HAVING, ORDER BY

- SELECT, DELETE, UPDATE문장 안에 있는 subquery

- CREATE TABLE, ALTER TABLE문장에서 DEFAULT expression

 

* CACHE 20으로 정의 했을 때...

INSERT INTO dept

VALUES (dept_deptno.NEXTVAL, ...) --> 1

SELECT last_number FROM user_squences --> 21

SELECT dept_deptno.CURRVAL FROM dual --> 1

SELECT dept_deptno.NEXTVAL FROM dual --> 2

6. SEQUENCE 사용예

INSERT INTO dept( deptno, dname, loc )

VALUES (dept_deptno.NEXTVAL, 'MARKETING', 'SAN DIEGO')

--> 증가된 sequence값이 deptno에 저장된다.

 

* 현재의 sequence값을 보려면...

SELECT dept_deptno.CURRVAL FROM dual ;

* SELECT에서 sequence값 증가시키기

SELECT dept_deptno.NEXTVAL FROM dual ;

 

7. SEQUENCE 수정하기

ALTER SEQUENCE dept_deptno

INCREMENT BY 1

MAXVALUE 999999

NOCACHE

NOCYCLE ;

* sequence에 대한 ALTER privilege를 갖고 있어야 한다.

* maxvalue current value보다 적을 땐 반드시 drop하고 re-create해야 한다.

* START WITH 문을 변경할 수 없습니다.( 삭제 후 다시 생성 )

8. SEQUENCE 제거하기

DROP SEQUENCE dept_deptno ;

 

9. INDEX ?

- Retrieve를 빨리 하기 위해서

- DISK I/O를 줄일수 있다.

- 테이블과는 독립적이다.

* PRIMARY KEY or UNIQUE constraint 생성시 오라클 서버에서 자동으로 생성되는것과, CREATE INDEX를 사용해서 만들어지는 index가 있다.

* INDEX는 많이 만든다고 좋은게 아니다.

* INDEX는 이렇때 만드는게 좋다.

- WHERE절이나 JOIN조건에 자주나오는 column

- column의 범위가 클때

- null value를 많이 갖고 있는 column

- 전체 row에서 2~4% 정도의 row를 찾을때

 

10. CREATE INDEX

CREATE INDEX index

ON table (column[, column]...) ;

CREATE INDEX emp_ename_idx

ON emp (ename) ;

 

11. USER_INDEXES and USER_IND_COLUMNS data dictionary

SELECT ic.index_name, ic.column_name, ic.column_position, ix.uniqueness

FROM user_indexes ix, user_ind_columns ic

WHERE ic.index_name = ix.index_name

AND ic.table_name = 'EMP' ;

 

12. INDEX 제거하기

DROP INDEX emp_ename_idx ;

 

13. SYNONYM ?

user synonym을 사용하면 스키마를 별도로 명시할 필요가 없어진다.

 

14. CREATE SYNONYM

CREATE [PUBLIC] SYNONYM synonym

FOR object ;

* PUBLIC은 모든 user에게 synonym권한을 주는 것이고, DBA권한이 있는 사람만

사용이 가능하다.

* PUBLIC을 안쓰면 만든 사람만 사용한다.

 

CREATE SYNONYM d_sum

FOR dept_sum_vu ;

--> dept_sum_vu라는 view테이블을 d_sum으로 사용 하겠다.

 

15. PUBLIC SYNONYM

CREATE PUBLIC SYNONYM dept

FOR alice.dept

--> alice가 만든 dept테이블을 dept로 모든 유저에게 명시 하겠다.

 

16. SYNONYM 제거

DROP SYNONYM d_sum ;

* public으로 정의된 SYNONYM DBA만 제거가 가능하다.

 

 

[14] Controlling User Access (GRANT, REVOKE)

* 시스템 권한(System Privilege): 데이터 베이스를 액세스할 수 있다.

* 객체 권한(Object Privilege) : 데이터 베이스 객체 내용을 조작할 수 있다.

1. System Privilege? --> DBA권한

- Create new users ( CREATE USER )

- Remove users ( DROP USER )

- Remove tables ( DROP ANY TABLE )

- Backup tables ( BACKUP ANY TABLE )

 

2. Creating User

CREATE USER scott

IDENTIFIED BY tiger ;

 

3. system privilege에서의 GRANT

GRANT privilege [, privilege...]

TO user [, user...]

[WITH ADMIN OPTION] ;

* WITH ADMIN OPTION : dba가 권한을 주는 user에게도 admin 권한을 줄 수 있다.

* user system privilege(DBA USER에게 할당 할 수 있는 권한)

CREATE SESSION : 테이터베이스에 connect하는 권한

CREATE TABLE : 테이블 만드는 권한

CREATE SEQUENCE : sequence 만드는 권한

CREATE VIEW : view 만드는 권한

CREATE PROCEDURE : stored prcedure, function 만드는 권한

GRANT create table, create sequence, create view

TO scott

--> scott에게 table, sequence, view만드는 권한을 준다.

 

4. ROLE : 사용자에게 부여할 수 있는 관련 권한을 하나로 묶어 명명한 그룹

Grant를 줄 role user를 만든후 그 role user grant를 주고,

role user의 권한을 각각의 user에게 넘겨준다.

SQL> CREATE ROLE manager ;

Role created.

SQL> GRANT create table, create view TO manager ;

Grant succeeded.

SQL> GRANT mananger TO brake, clock ;

Grant succeeded.

 

5. User Password 변경하기

ALTER USER user IDENITIFIED BY password ;

) ALTER USER scott IDENTIFIED BY lion ;

 

6. Object Privileges?

* 객체마다 다르다.

* 소유자는 객체에 대한 모든 권한을 갖는다.

* 소유자는 자신의 객체에 대한 특정 권한을 부여할 수 있다.

 

 

7. Object Privilege에서의 GRANT

GRANT object_priv [(columns)| ALL]

ON object

TO {user|role|PUBLIC}

[WITH GRANT OPTION] ;

* sue, rich 라는 user에게 emp 테이블을 select 권한을 준다.

GRANT select

ON emp

TO sue, rich ;

* scott, manager라는 user에게 dept 테이블의 dname,loc 컬럼을 update할 수 있게 권한을 준다.

GRANT update (dname, loc)

ON dept

TO scott, manager ;

 

* WITH GRANT OPTION

GRANT select, insert

ON dept

TO scott

WITH GRANT OPTION ;

--> scott에게 dept 테이블의 select, insert권한을 주면서 scott가 다른 유저에게도

이 권한을 줄 수 있게 한다.

 

* PUBLIC : 모든 유저에게 권한을 부여한다.

GRANT select

ON alice.dept

TO PUBLIC ;

--> 모든유저에게 alice가 만든 dept 테이블의 select권한을 준다.

 

* 모든 유저에게 모든 object권한을 주기

GRANT ALL

ON emp

TO PUBLIC ;

 

8. 권한 없애기 (REVOKE)

REVOKE {privilege [, privilege...] | ALL}

ON object

FROM {user[, user...]|role|PUBLIC}

[CASCADE CONSTRAINTS]

 

REVOKE select, insert

ON dept

FROM scott ; --> scott에게서 dept테이블의 select, insert권한을 없앤다.

* CASCADE CONSTRAINTS : 이 옵션을 않쓰면 revoke할 때 forien key

관계의 table revoke할 수 없다.

 

9. Privilege Grant를 볼 수 있는 Data Dictionary

ROLE_SYS_PRIVS : System privilege 권한에 대한 정보

ROLE_TAB_PRIVS : table(object) privilege 권한에 대한 정보

USER_ROLE_PRIVS : role정보

USER_TAB_PRIVS_MADE : 내가 다른 사람에게 준 TABLE 권한에 대한 정보

USER_TAB_PRIVS_RECD : 내가 다른 사람에게 받은 TABLE 권한에 대한 정보

USER_COL_PRIVS_MADE : 내가 다른 사람에게 준 COLUMN 권한에 대한 정보

USER_COL_PRIVS_RECD : 내가 다른 사람에게 준 COLUMN 권한에 대한 정보

 

*****************************************************************

TABLE <--> PROCEDURE

VIEW : DML 수행

SEQUENCE : ALTER, SELECT

******************************************************************

 

출처 : SQLER

select * from user_catalog;

프로그래밍/DB 2007. 11. 27. 14:31 Posted by galad

select * from user_catalog;

'프로그래밍 > DB' 카테고리의 다른 글

[펌] 오라클자료 - PL/SQL  (0) 2007.11.27
[펌] PL-SQL 정리  (0) 2007.11.27
[펌] SQL*Plus에서 꼭 알아두어야 할 활용 매뉴얼~!  (0) 2007.11.27
[펌] 인덱스 생성 [CREATE INDEX]  (0) 2007.11.27
Tablespace 정보보기  (0) 2007.11.27
SQL*Plus에서 꼭 알아두어야 할 활용 매뉴얼~!

● 제 1 장 데이터의 검색
• SQL 명령어는 다음과 같이 기술한다.
■ SQL 명령어는 한 줄 혹은 여러 줄에 기술한다.
■ 일반적으로 절들은 수정하기 쉽게 다른 줄에 기술한다.
■ TAB 을 사용할 수 있다.
■ SQL 명령어 단어는 생략하거나 분리할 수 없다.
■ SQL 명령어는 대소문자를 구분하지 않는다.
■ SQL 명령어는 ; 으로 종료한다.
■ SQL 명령어는 SQL BUFFER 에 저장된다.
■ SQL BUFFER 에 저장된 SQL 명령어는 / 혹은 RUN 으로 실행할 수 있다.
•SQL*PLUS 명령어는 다음과 같이 기술한다.
■ SQL*PLUS 명령어는 기본적으로 한 줄에 기술한다.
■ SQL*PLUS 명령어는 대소문자를 구별하지 않는다.
■ SQL*PLUS 명령어는 SQL BUFFER 에 저장되지 않는다.
■ SQL*PLUS 명령어는 다음과 같다.
? DESCRIBE table명 : TABLE 의 구조를 보여준다.
? SAVE file명 : SQL BUFFER 를 file 로 저장한다.
? START file명 : file 을 수행한다.
? @ file명 : file 을 수행한다.
? EDIT file명 : EDITOR 를 사용하여 file 을 편집한다.
? SPOOL file명 : QUERY 결과를 file 에 저장한다.
? SPOOL OFF : SPOOL FILE 을 닫는다.
? HOST : SQL*PLUS 를 떠나지 않고 HOST 상태로 간다.
? HELP 명령어 : SQL, SQL*PLUS, PL/SQL 에 대한 HELP 를 보내준다.
? EXIT : SQL*PLUS 를 종료한다.

• 전체 데이타의 검색
가장 간단한 SELECT 문장의 형식은 다음과 같다.
. SELECT 절에는 검색하고 싶은 COLUMN 명들을 기술한다.
. FROM 절에는 SELECT 절에서 기술된 COLUMN 명들이 포함된 TABLE 명을 기술한다.
TABLE 의 모든 ROW 와 모든 COLUMN 을 검색한다.
SELECT * - FROM table명 ;
[ 예제 ] S_DEPT TABLE 로부터 모든 ROW 와 COLUMN 을 검색하시오.
SELECT *
FROM S_DEPT ;

• 특정 column의 검색
SELECT 절에서 검색하고자 하는 COLUMN 명을 COMMA 를 사용하여 나열한다.
COLUMN 순서는 검색하고 싶은 순서대로 나열한다.
COLUMN HEADING 은 COLUMN 명이 대문자로 출력된다.
SELECT column명, column명, column명,.. - FROM table명 ;
[ 예제 ] S_EMP TABLE 로부터 ID, LAST_NAME, START_DATE 를 검색하시오.
SELECT ID, LAST_NAME, START_DATE
FROM S_EMP ;

- 계속(1) -


• 산술식을 사용한 검색
산술 연산자를 사용하여 검색되는 데이타 값을 변경할 수 있으며 산술 연산식은 COLUMN 명, 상수 값, 산술 연산자로 구성됨.
SELECT 산술연산식 - FROM table명 ;
[ 예제 ] S_EMP TABLE 로부터 ID, LAST_NAME, 연봉을 검색하시오. (연봉은 SALARY * 12 로 계산한다. (+,-,*,/,())
SELECT ID, LAST_NAME, SALARY * 12
FROM S_EMP ;

• Column alias
기본적으로 COLUMN HEADING 은 COLUMN 명이 대문자로 출력된다. 그러나 많은 경우 COLUMN 명이 이해하기 어렵거나
무의미하기 때문에 COLUMN ALIAS 를 사용하여 COLUMN HEADING 을 변경할 수 있다.
ANSI SQL 92 와 호환을 위해 ALIAS 앞에 AS 를 붙일 수 있다.
ALIAS 에 공백이나 특수문자가 포함되거나 대소문자를 구별하고 싶으면 " " 로 막아준다.
COLUMN ALIAS 를 사용하여 COLUMN HEADING 을 변경할 수 있다.
SELECT column명 alias, column명 "alias", column명 as alias - FROM table명 ;
[ 예제 ] S_EMP TABLE 에서 LAST_NAME, (SALARY + 100) * 12, DEPT_ID 를 검색하시오.
(단, COLUMN ALIAS 는 Employee, ANNUAL_SALARY, DEPARTMENT NO 로 정의하시오.)
SELECT LAST_NAME "Employee", (SALARY + 100) * 12 AS ANNUAL_SALARY,
DEPT_ID "DEPARTMENT NO"
FROM S_EMP ;

• Column의 결합
COLUMN 과 다른 COLUMN, 산술연산식, 상수 값과 결합하여 하나의 COLUMN 으로 결합할 수 있다.
SELECT column명|| column명 - FROM table명;
[ 예제 ] S_EMP TABLE 에서 FIRST_NAME 과 LAST_NAME 을 결합하여 ALIAS EMPLOYEE 로 검색하시오.
SELECT FIRST_NAME || LAST_NAME EMPLOYEE
FROM S_EMP ;

• Null값 처리
특정 COLUMN 에 값이 입력되어 있지 않을 때, 그 값이 NULL 이며, NULL 값이 산술 연산식에 포함되면 그 결과도 NULL 이다.
NULL 값은 0 이나 공백과 같지 않다. 그러므로 NVL FUNCTION 을 사용하여 NULL 값을 다른 값으로 대체하여야 한다.
NULL 값을 다른 값으로 대체.NVL (number_column, 9), NVL (date_column, '01-JAN-95'), NVL (character_column, 'ABCDE')
[ 예제 ] S_EMP TABLE 에서 LAST_NAME, COMMISSION 값을 검색하시오.
(COMMISSION 은 SALARY * COMMISSION_PCT /100 으로 계산하시오.)
SELECT LAST_NAME, SALARY * NVL(COMMISSION_PCT,0) /100 COMMISSION
FROM S_EMP ;

• 중복 row의 제거
SELECT 결과 값에 중복된 값이 있을 때 중복을 피하고 UNIQUE 하게 검색한다. 중복된 ROW 를 제거한다.
SELECT DISTINCT column명, column명 - FROM table명;
[ 예제 ] S_DEPT TABLE 에서 NAME 이 중복되지 않게 검색하시오.
SELECT DISTINCT NAME
FROM S_DEPT ;



- 계속(2) -


• 데이타의 정렬
SELECT 되는 ROW 의 순서는 알 수 없다. 그러므로 ROW 를 SORT 하고 싶으면 ORDER BY 절을 사용하여야 한다.
DATA 의 DEFAULT SORT 순서는 ASCENDING 이며 다음과 같다.
? 숫자 : 1 에서 999 순으로 SORT 한다. ? 날짜 : 01-JAN-92 에서 01-JAN-95 순으로 SORT 한다.
? 문자 : A 에서 Z 순서로 SORT 한다. ? NULL : ASC 순에서는 뒤에, DESC 순에서는 앞에 나온다.
역순으로 SORT 하고 싶으면 COLUMN 명 뒤에 DESC 를 붙인다.
COLUMN 명 대신에 ALIAS 혹은 SELECT 한 COLUMN 의 순서로 지정할 수도 있다.
SELECT expr - FROM table명 - ORDER BY {column명, expr} [ASC|DESC] ;
[ 예제 ] S_EMP TABLE 에서 LAST_NAME, DEPT_ID, START_DATE 를 LAST_NAME 순으로 검색하시오.
SELECT LAST_NAME, DEPT_ID, START_DATE
FROM S_EMP ORDER BY LAST_NAME ;

• 특정 row의 검색
WHERE 절에서 조건식을 기술하여 조건을 만족하는 ROW 만 검색할 수 있다.
조건식은 COLUMN 명, COMPARISON OPERATOR, VALUE 로 구성되어 있다.
문자 값은 ' ' 으로 묶어주고 값의 대소문자를 구별하여 적어준다. 날짜 값은 ' ' 으로 묶어주고 지정된 날짜 형태로 적어준다. '01-MAR-97', 숫자값은 값만 적어주며 특정 ROW 만 검색한다.
SELECT expr - FROM table명 - WHERE expr operator value
[ 예제 ] S_EMP TABLE 에서 LAST_NAME 이 Magee 인 사원의 FIRST_NAME, LAST_NAME,
TITLE 을 검색하시오. (=,>,<,>=,<=,<>) SELECT FIRST_NAME, LAST_NAME, TITLE
FROM S_EMP WHERE LAST_NAME = 'Magee' ;

• Between...and
BETWEEN OPERATOR 를 사용하여 범위를 지정할 수 있다. 범위를 지정할 때는 작은 값을 먼저 큰 값을 나중에 지정한다.
두 범위의 한계 값을 포함한다. BETWEEN...AND... - NOT BETWEEN...AND...
[ 예제 ] S_EMP TABLE 에서 START_DATE 가 09-MAY-91 에서 17-JUN-91 사이에 입사한 사원의 FIRST_NAME, LAST_NAME, START_DATE 를 검색하시오.
SELECT FIRST_NAME, LAST_NAME, START_DATE
FROM S_EMP WHERE START_DATE BETWEEN '09-MAY-91' AND '17-JUN-91' ;

• In[list]
IN OPERATOR 를 사용하여 나열된 값들 중에서 값을 검사한다.
IN(LIST), NOT IN(LIST)
[ 예제 ] S_EMP TABLE에서 DEPT_ID 가 10, 31, 41, 50 인 사원의 FIRST_NAME, LAST_NAME, DEPT_ID 를 검색하시오.
SELECT FIRST_NAME, LAST_NAME, DEPT_ID
FROM S_EMP WHERE DEPT_ID IN (10, 31, 41, 50) ;

• like
찾고자 하는 값을 정확히 모를 때, LIKE OPERATOR 를 사용하여 문자형태가 같은 ROW 를 검색한다.
WILDCARD 를 사용하여 문자의 형태를 지정한다. (% : 여러 문자, _ : 한문자 )
LIKE '형태', NOT LIKE '형태'
[ 예제 ] S_EMP TABLE에서 LAST_NAME 이 M 으로 시작하는 사원의 LAST_NAME 을 검색하시오.
SELECT LAST_NAME FROM S_EMP WHERE LAST_NAME LIKE 'M%' ;
SELECT LAST_NAME FROM S_EMP WHERE LAST_NAME LIKE '__M____' ;

- 계속(3) -

• is null
IS NULL OPERATOR을 사용하여 값이 NULL 인 것을 찾을 수 있다.
NULL 값은 값이 정의되지 않은 것을 의미하기 때문에 = OPERATOR를 사용하여 어떤 값과 비교할 수 없기 때문에 사용한다.
IS NULL, IS NOT NULL
[ 예제 ] S_EMP TABLE에서 COMMISSION_PCT가 NULL인 사원의 LAST_NAME, SALARY, COMMISSION_PCT를 검색하시오.
SELECT last_name, salary,commission_pct,last_name, salary
FROM s_emp WHERE commission_pct is null;

• 조건식의 결합
조건식을 기술할 때 AND 와 OR 를 사용하여 여러가지 조건을 결합할 수 있다.
AND 와 OR 가 같이 사용됐을 때 AND 가 먼저 수행되고 OR 가 나중에 수행된다.
그러므로 우선순위를 바꾸고자 하면 ( ) 를 사용한다.
WHERE 조건식 AND | OR 조건식
[ 예제 ] S_EMP TABLE에서 DEPT_ID가 41이고 TITLE이 Stock Clerk인 사원의 LAST_NAME, SALARY, DEPT_ID, TITLE을 검색하시오.
SELECT LAST_NAME, SALARY, DEPT_ID, TITLE
FROM S_EMP WHERE DEPT_ID = 41 AND TITLE = 'Stock Clerk' ;

● 제 2 장 Single Row Functions
• 소문자로 변환
모든 문자를 소문자로 변환시킨다.
LOWER(COLUMN명)
[ 예제 ] S_EMP TABLE 에서 LAST_NAME 이 Smith 인 사원의 FIRST_NAME, LAST_NAME 을 소문자로 출력시키시오.
SELECT LOWER(FIRST_NAME), LOWER(LAST_NAME)
FROM S_EMP WHERE LOWER(LAST_NAME) = 'smith' ;

• 대문자로 변환
모든 문자를 대문자로 변환시킨다.
UPPER(COLUMN명)
[ 예제 ] S_EMP TABLE 에서 LAST_NAME 이 Smith 인 사원의 TITLE 을 대문자로 출력하시오.
SELECT UPPER(TITLE)
FROM S_EMP WHERE UPPER(LAST_NAME) = 'SMITH';

• 첫글자만 대문자로 변환
단어의 첫글자는 대문자로, 나머지는 소문자로 변환시킨다.
INITCAP(COLUMN명)
[ 예제 ] S_EMP TABLE 에서 TITLE 을 단어의 첫글자만 대문자로 출력시키시오.
SELECT INITCAP(TITLE) FROM S_EMP ;

• 문자의 부분을 자름
문자를 시작위치(M)에서 자리수(N) 만큼 잘라준다. 자리수(N)이 생략되면 시작위치(M)에서 끝까지 잘라준다.
SUBSTR(COLUMN명, M, N)
[ 예제 ] S_PRODUCT TABLE 에서 NAME COLUMN 의 앞에서 부터 3글자가 Ace 인 제품의 NAME 을 출력하시오.
SELECT NAME FROM S_PRODUCT
WHERE SUBSTR(NAME, 1, 3) = 'Ace' ;

- 계속(4) -


• 문자의 길이를 계산
문자의 길이를 RETURN 한다.
LENGTH(COLUMN명)
[ 예제 ] S_PRODUCT TABLE 에서 NAME, NAME 의 길이를 출력하시오.
SELECT NAME, LENGTH(NAME)
FROM S_PRODUCT;

• 숫자의 반올림
지정된 자리수(M) 밑에서 반올림한다.
COLUMN 값이 1 2 3 4. 5 6 7 일 때 자리수(M)는 다음과 같다.
      M : -3-2-1 0 1 2 3
ROUND(COLUMN명, M)
[ 예제 ] S_EMP TABLE 에서 LAST_NAME, SALARY/22 의 값을 소수 2째 자리까지 나타내고 소수 3째 자리에서 반올림하시오.
SELECT LAST_NAME, ROUND(SALARY/22, 2)
FROM S_EMP ;

• 숫자의 절사
지정된 자리수(M) 까지 나타내고 그 밑은 잘라버린다.
COLUMN 값이 1 2 3 4. 5 6 7 일 때 자리수(M)은 다음과 같다.
      M : -3-2-1 0 1 2 3 절사 값은 RETURN 한다.
TRUNC(COLUMN명, M)
[ 예제 ] S_EMP TABLE 에서 LAST_NAME, SALARY / 22 의 값을 십의 자리까지 나타내고 일의 자리는 버림.
SELECT LAST_NAME, TRUNC(SALARY/22, -1)
FROM S_EMP ;

• 나누기의 나머지
M 을 N 으로 나누고 남은 나머지를 RETURN 한다.
MOD(M, N)
[ 예제 ] 10 을 3 으로 나눈 나머지를 구하시오.
SELECT MOD(10, 3)
FROM SYS.DUAL ;

• 날짜의 연산
DATABASE 안의 DATE 값은 다음과 같은 숫자로 저장되어 있다.
■ CENTURY, YEAR, MONTH, DAY, HOURS, MINUTES, SECONDS 그러므로 산술 연산을 할 수 있다.
● DATE + NUMBER : 숫자만큼 일이 더해진 날짜가 RETURN 된다.
● DATE - NUMBER : 숫자만큼 일이 빼진 날짜가 RETURN 된다.
● DATE1 - DATE2 : 두 날짜 사이의 일수가 계산된다.
날짜 계산을 한다. (DATE + NUMBER, DATE - NUMBER, DATE1 - DATE2)
[ 예제 ] S_EMP TABLE 에서 LAST_NAME, 입사한지 90 일째 되는 날, 입사한지 며칠 됐는 지 검색하시오.
SELECT LAST_NAME, START_DATE + 90, SYSDATE - START_DATE
FROM S_EMP; ( 날짜에는 시간도 포함되어 있으므로 일수 계산의 결과가 소수로 나온다. )



- 계속(5) -


• 날짜 사이의 개월 수
두 날짜 사이의 개월 수를 RETURN 한다.
MONTHS_BETWEEN(DATE1, DATE2)
[ 예제 ] S_EMP TABLE 에서 LAST_NAME, 입사한지 몇 달이 됐는지 출력하시오.
SELECT LAST_NAME, MONTHS_BETWEEN(SYSDATE, START_DATE)
FROM S_EMP ; (일이 포함되어 있어서 소수로 출력된다.)

• 날짜에 달을 더함
날짜에서 숫자(N) 개월만큼 더해진 날짜를 RETURN 한다.
ADD_MONTHS(DATE, N)
[ 예제 ] S_EMP TABLE 에서 LAST_NAME, START_DATE, 입사한지 3 개월되는 날짜를 출력하시오.
SELECT LAST_NAME, START_DATE, ADD_MONTHS(START_DATE, 3)
FROM S_EMP ;

• 지정한 요일 날짜
날짜에서 지정한 요일(CHAR)이 될 날짜를 RETURN 한다.
NEXT_DAY(DATE, 'CHAR')
[ 예제 ] 오늘을 기준으로 돌아오는 금요일이 언제인지 출력하시오.
SELECT SYSDATE, NEXT_DAY(SYSDATE, 'FRIDAY')
FROM SYS.DUAL ;

• 그 달의 마지막 날
날짜가 포함된 달의 마지막 날을 RETURN 한다.
LAST_DAY(DATE)
[ 예제 ] 이번 달의 마지막 날은 언제인지 출력하시오.
SELECT SYSDATE, LAST_DAY(SYSDATE)
FROM SYS.DUAL ;

• 날짜의 반올림
형태에 따른 반올림 기준은 다음과 같다.
? YEAR : 6월 이후, ? MONTH : 15일 이후, ? DAY : 12시 이후
날짜 데이타를 지정된 형태까지 나타내고 그 이하에서 반올림한다.
ROUND(COLUMN명, '형태')
[ 예제 ] S_EMP TABLE 에서 ID, LAST_NAME, 입사 시작 달을 검색하시오. (단, 15일 이후는 다음달로 올리시오.)
SELECT ID, LAST_NAME, ROUND(START_DATE, 'MONTH')
FROM S_EMP ;

• 날짜의 절사
날짜 데이타를 지정된 형태까지 나타내고 그 밑은 잘라낸다.
TRUNC(COLUMN명, '형태')
[ 예제 ] S_EMP TABLE 에서 ID, LAST_NAME, 입사 시작 달을 검색하시오. (단, 일자는 잘라버리시오.)
SELECT ID, LAST_NAME, TRUNC(START_DATE, 'MONTH')
FROM S_EMP ;


- 계속(6) -


• 문자를 날짜로 변환
CHARACTER TYPE 을 지정된 형태의 DATE TYPE 으로 변환한다.
TO_DATE(character_column명, '형태')
[ 예제 ] S_EMP TABLE 에서 LAST_NAME, START_DATE 를 검색하시오.
(단, START_DATE 의 값이 92/02/07 인 사원을 검색하시오.)
SELECT LAST_NAME, START_DATE
FROM S_EMP WHERE START_DATE = TO_DATE('92/02/07', 'YY/MM/DD') ;

• 날짜를 문자로 변환
DATE 값은 기본적으로 DD-MON-YY 형태로 출력된다.
이것을 TO_CHAR FUNCTION 을 사용하면 원하는 다른 형태로 변환할 수 있다.
■ 형태를 지정할 때 사용된 대소문자로 출력된다.
■ DAY 와 MONTH 형태는 공백을 포함한 9 자리로 출력된다.
■ TO_CHAR 의 결과는 80 자리로 출력된다.
DATE TYPE 을 지정된 형태의 CHARACTER TYPE 으로 변환한다.
TO_CHAR(date_column, '형태')
[ 예제 ] S_EMP TABLE 에서 LAST_NAME, START_DATE 를 검색하시오.
(단, START_DATE 의 형태는 1991/06/17 14:20:00 와 같이 출력하시오.)
SELECT LAST_NAME, TO_CHAR(START_DATE, 'YYYY/MM/DD HH24:MI:SS'), START_DATE
FROM S_EMP ;

• 숫자를 문자로 변환
NUMBER TYPE 을 지정된 형태의 CHARACTER TYPE 으로 변환한다.
TO_CHAR(number_column명, '형태')
[ 예제 ] S_EMP TABLE 에서 LAST_NAME, SALARY 를 검색하시오.(단 SALARY 를 $1,450 와 같은 형태로 출력시키시오.)
SELECT LAST_NAME, TO_CHAR(SALARY, '$999,999')
FROM S_EMP ;

● 제 3 장. 여러Table로부터 Data검색
• Equijoin
SIMPLE JOIN (EQUI-JOIN)
여러개의 TABLE 들로부터 정보를 검색하려면, SELECT 문장의 FROM 절에 TABLE명들을 적고
WHERE 절에 각 TABLE의 ROW들을 연결시킬 조건식을 기술한다.
각 TABLE 의 COLUMN명이 중복될 때는 반드시 COLUMN명 앞에 TABLE명을 붙여야 한다.
(중복되지 않을 때는 붙이지 않아도 되지만 명확성을 위해서나 ACCESS 를 위해서 붙이는 것이 좋다.)
N 개의 TABLE 을 JOIN 할 때는 최소한 N-1 개의 조건식이 필요하다.
복합 COLUMN 으로 JOIN 할 때는 더 많은 조건식이 필요하다.
2개 이상의 TABLE 에서 = 조건식을 만족시키는 ROW 들을 연결하여 검색한다.
SELECT table명.column명, table명.column명...-FROM table1명, table2명-WHERE table1명.column1명 = table2명.column명 ;
[ 예제 ] S_EMP TABLE 과 S_DEPT TABLE 을 사용하여 사원들의 LAST_NAME, DEPT_ID, NAME 을 검색하시오.
SELECT S_EMP.LAST_NAME, S_EMP.DEPT_ID, S_DEPT.NAME
FROM S_EMP, S_DEPT WHERE S_EMP.DEPT_ID = S_DEPT.ID ;



- 계속(7) -


• 특정 row의 join
JOIN 문장을 기술할 때 JOIN 조건식 이외에 다른 조건식을 AND 로 연결할 수 있다.
SELECT table명.column명, table명.column명...
FROM table1명, table2명 - WHERE table1명.column1명 = table2명.column2명 AND condition ;
[ 예제 ] S_EMP TABLE과 S_DEPT TABLE 을 사용하여 LAST_NAME 이 Menchu 인 사원의 LAST_NAME, DEPT_ID,
NAME 을 검색하시오.
SELECT S_EMP.LAST_NAME, S_EMP.DEPT_ID, S_DEPT.NAME
FROM S_EMP, S_DEPT WHERE S_EMP.DEPT_ID = S_DEPT.ID AND S_EMP.LAST_NAME = 'Smith' ;

• Table alias
JOIN 문장에서 TABLE명이 긴 경우 TABLE명.COLUMN명 으로 적는 것이 매우 불편하다.
그런데 TABLE명 대신 ALIAS 를 사용하면 편하게 사용할 수 있다.
(SELECT 문장에서 TABLE명 대신 ALIAS 를 지정했다면 그 문장에서는 계속해서 ALIAS 로 사용하여야 한다.)
TABLE ALIAS를 사용하여 JOIN 문장을 간단하게 기술한다.
SELECT alias명.column명, alias명.column명
FROM table1명 alias1명, table2명 alias2명 - WHERE alias1명.column1명 = alias2명.column2명 ;
[ 예제 ] S_CUSTOMER TABLE과 S_REGION TABLE 을 사용하여 고객 명,지역번호,지역 명을 검색하시오.
(단, COLUMN ALIAS 와 TABLE ALIAS 를 사용하시오.)
SELECT C.NAME "Customer Name", C.REGION_ID "Region Id", R.NAME "Region Name"
FROM S_CUSTOMER C, S_REGION R WHERE C.REGION_ID = R.ID ;

• Non-Equijoin
NON-EQUIJOIN
JOIN 문장에서 두 TABLE 을 JOIN 하는 조건식에 = OPERATOR 가 사용되지 않고
다른 OPERATOR 가 사용되는 것을 말한다.
SELECT table명.column명, table명.column명... - FROM table1명, table2명 - WHERE 조인조건식 ;
[ 예제 ] EMP TABLE 과 SALGRADE TABLE 을 사용하여 사원의 ENAME, JOB, SAL,GRADE를 검색하시오.
SELECT E.ENAME, E.JOB, E.SAL, S.GRADE FROM EMP E, SALGRADE S
WHERE E.SAL BETWEEN S.LOSAL AND S.HISAL ;
(BETWEEN OPERATOR 대신에 <= 와 >= 를 사용해도 되지만 BETWEEN 이 간편하다.)

• Outer Join
두 TABLE 을 JOIN 할 때 JOIN 조건식을 만족시키지 못하는 ROW 는 검색에서 빠지게 된다.
그런데 이러한 ROW 들이 검색되도록 하는 것이 OUTER JOIN 이다.
(+) OUTER JOIN OPERATOR 를 데이타가 없는 어느 한쪽의 COLUMN 쪽에 붙인다.
JOIN 결과, 데이타가 없는 쪽의 COLUMN 값은 NULL로 검색된다. 조건식을 만족시키지 못하는 데이타도 검색한다.
SELECT table명.column명, table명.column명 - FROM table1명, table2명
WHERE table1명.column1명 = table2명.column2명(+)
[ 예제 ] S_EMP TABLE 과 S_CUSTOMER TABLE 을 사용하여 영업사원의 LAST_NAME, SALES_REP_ID, NAME 을 검색하시오.
(단, 영업사원이 정해져 있지 않은 고객의 이름도 검색하시오.)
SELECT E.LAST_NAME, C.SALES_REP_ID, C.NAME
FROM S_EMP E, S_CUSTOMER C
WHERE E.ID(+) = C.SALES_REP_ID ;


- 계속(8) -


• Self Join
TABLE 의 ALIAS 를 사용하여, 마치 2 개의 TABLE 처럼 생각하여 자신의 TABLE 과 자신의 TABLE 을 JOIN 한다.
SELECT alias명.column명, alias명.column명...
FROM table명 alias1명, table명 alias2명 - WHERE alias1명.column1명 = alias2명.column2명 ;
[ 예제 ] S_EMP TABLE 에서 사원들의 LAST_NAME 과 그들의 상사 LAST_NAME 을 검색하시오.
SELECT W.LAST_NAME "Woker", M.LAST_NAME "Manager"
FROM S_EMP W, S_EMP M WHERE W.MANAGER_ID = M.ID ;

● 제 4 장. Group Functions
• Group Function
각각의 FUNCTION 은 ARGUMENT 를 받는데 기능은 다음과 같다.
■ DISTINCT : 중복된 값은 제외한다. ■ ALL : DEFAULT 로써 모든 값을 포함한다.
■ COLUMN명 : NULL 값은 제외한다. ■ * : NULL 값도 포함한다.
TABLE 전체를 하나의 GROUP 으로 보고 GROUP FUNCTION 값을 RETURN 한다.
SELECT group_function(column명), group_function(column명)... - FROM table명 ;
[ 예제 ] S_EMP TABLE 에서 회사 전체의 급여합계, 최고급여, 최소급여, 인원수를 검색하시오.
SELECT SUM(SALARY), MAX(SALARY), MIN(SALARY), COUNT(SALARY) FROM S_EMP ;
( COUNT(SALARY) 는 급여를 받는 사원의 총 인원수고 COUNT(*) 는 급여를 받지 않는 사원의 인원수도 포함된다.)

• 소group으로 분리
기본적인 SELECT 절(그룹화 되지 않은 SELECT절)에는 COLUMN 명과 GROUP FUNCTION 이 같이 기술될 수 없다.
SELECT 절에 COLUMN 명이 기술되려면 GROUP BY 절이 반드시 기술되어야 한다.
SELECT 절에 기술된 COLUMN 명들은 전부 GROUP BY 절에 기술되어야 하며
GROUP BY 절에 기술된 COLUMN 명들은 SELECT 절에 기술되지 않아도 된다.
(하지만 결과를 파악하기 위해서는 SELECT 절에 기술해주는 것이 좋다.)
GROUP BY 절을 기술하면 GROUP BY 절에 기술된 COLUMN 값으로 1 개의 TABLE이 소 GROUP 으로 나눠진다.
결과는 COLUMN 값으로 SORT 되어서 출력된다. 1개의 TABLE 을 소 GROUP 으로 나누어 GROUP FUNCTION 값을 구한다.
SELECT column1명[, column2명], group_function(column명) - FROM table명 - GROUP BY column1명[, column2명] ;
[ 예제 ] S_EMP TABLE 에서 DEPT_ID, TITLE 별로, 최고급여, 최소급여, 인원수를 검색하시오.
SELECT DEPT_ID, TITLE, MAX(SALARY), MIN(SALARY), COUNT(SALARY)
FROM S_EMP GROUP BY DEPT_ID, TITLE;

• 특정 group의 선택
HAVING 절이 기술됐을 때 처리되는 순서는 다음과 같다.
① ROW 들이 GROUPing 된다. ② GROUP 에 대해 GROUP FUNCTION 이 적용된다.
③ HAVING 절을 만족하는 GROUP 을 선택한다.
GROUP BY 절과 HAVING 절의 순서는 바뀌어도 되지만 의미상 GROUP BY 절 다음에 HAVING 절을 기술하는 것이 좋다.
HAVING 절에서는 GROUP FUNCTION 을 사용하여 GROUP 에 대한 조건식을 기술한다.
SELECT column1명[, column2명], group_function(column명) - FROM table명 - GROUP BY column1명[, column2명]
HAVING 그룹조건식 ;
[ 예제 ] S_EMP TABLE에서 TITLE별로 급여합계를 검색하시오. (단, 급여합계가 5000이상인 GROUP만 출력하시오)
SELECT TITLE, SUM(SALARY) PAYROLL FROM S_EMP
GROUP BY TITLE HAVING SUM(SALARY) >= 5000 ;


- 계속(9) -

• Group의 정렬
기본적으로 GROUP BY 절에 기술된 COLUMN 값으로 SORT 된다.
이 순서를 바꾸고자 하면 ORDER BY 절을 기술하면 된다. DATA 의 SORT 순서를 정한다.
SELECT column1명[, column2명], group_function(column명) - FROM table명
GROUP BY column1명[, column2명] - ORDER BY column명| group_function(column명) ;
[ 예제 ] S_EMP TABLE에서 DEPT_ID 별로 인원수를 검색하시오. (단, 인원수가 많은 부서부터 출력하시오.)
SELECT DEPT_ID, COUNT(*) FROM S_EMP GROUP BY DEPT_ID ORDER BY COUNT(*) DESC ;

● 제 5 장. Subquery
• Single Row Subquery
SUBQUERY의 결과가 1개의 ROW로 나오는 것을 SINGLE ROW SUBQUERY라 하며 다음과 같은 OPERATOR를 사용할 수 있다.
=, >, >=, <, <= VALUE 값을 구하기 위해 SELECT 문장을 사용한다.
SELECT column명, column명... - FROM table명
WHERE column명 operator (SELECT column명 FROM table명 WHERE 조건식 );
[ 예제 ] S_EMP TABLE 에서 LAST_NAME 이 Smith 인 사원과 같은 업무(TITLE)를 하고 있는 사원의 LAST_NAME, TITLE 을 검색하시오.
SELECT LAST_NAME, TITLE FROM S_EMP
WHERE TITLE = ( SELECT TITLE FROM S_EMP WHERE LAST_NAME = 'Smith') ;

• From절의 Subquery
FROM 절에 기술된 SUBQUERY 문은 VIEW 처럼 사용된다.
SELECT alias명.column명, alias명,column명... - FROM table1명 alias1명, (SELECT column2명
FROM table2명 - WHERE 조건식) alias2명 - WHERE alias1명.column1명 OPERATOR alias2명.column2명 ;
[ 예제 ] S_EMP TABLE에서 SALARY가 회사평균급여 보다 적은 사원의 LAST_NAME, SALARY, 회사평균급여를 검색하시오.
SELECT E.LAST_NAME, E.SALARY, S.AVGSAL
FROM S_EMP E, (SELECT AVG(SALARY) AVGSAL FROM S_EMP) S WHERE E.SALARY < S.AVGSAL ;

• Multi Row Subquery
SUBQUERY 의 결과가 여러 ROW 일 때는 반드시 IN OPERATOR 를 사용하여야 한다.
SELECT column명, column명... - FROM table명
WHERE column명 IN ( SELECT column명 FROM table명 WHERE 조건식);
[ 예제 ] S_EMP TABLE과 S_DEPT TABLE에서 Operations부서에서 근무하는 사원의 LAST_NAME, TITLE, DEPT_ID 를 검색하시오.
SELECT LAST_NAME, TITLE, DEPT_ID FROM S_EMP
WHERE DEPT_ID IN (SELECT ID FROM S_DEPT WHERE NAME = 'Operations') ;

• Multi Column Subquery
SELECT 문장의 WHERE 절에서 여러개의 COLUMN 값을 비교하려면 LOGICAL OPERATOR 를 사용하여 여러개의 조건식
을 기술하여야 한다. 그런데 MULTI COLUMN SUBQUERY 를 사용하면 이를 해결할 수 있다.
SELECT column명, column명,,, - FROM table명
WHERE (column명, column명...) IN (SELECT column명, column명... FROM table명 WHERE 조건식);
[ 예제 ] S_EMP TABLE에서 LAST_NAME Patel인 사원과 같은 부서, 같은 업무를 맡고 있는 사원의 LAST_NAME, TITLE, DEPT_ID 를 검색하시오.
SELECT LAST_NAME, TITLE, DEPT_ID FROM S_EMP
WHERE (DEPT_ID, TITLE) IN(SELECT DEPT_ID, TITLEFROM S_EMPWHERE LAST_NAME = 'Patel') ;
SELECT LAST_NAME, TITLE, DEPT_ID FROM S_EMP
WHERE (DEPT_ID) IN (SELECT DEPT_ID FROM S_EMP WHERE LAST_NAME = 'Patel')
OR (TITLE) IN (SELECT TITLE FROM S_EMP WHERE LAST_NAME = 'Patel') ;

- 계속(10) -


● 제 6 장. Table 생성
• 이름 붙이는 법
이름은 다음의 규칙을 따라서 지정한다.
■ TABLE 명이나 COLUMN 명은 문자로 시작하고 30 자 이내로 지정한다. ■ A~Z, a~z, 0~9, _, $, # 을 사용할 수 있다.
■ 한 USER 내에서는 다른 OBJECT 의 이름과 동일하게 지정할 수 없다.
■ ORACLE7 SERVER 예약어를 사용할 수 없다. ■ 대소문자를 구별하지 않는다.

• Oracle 7 datatype
COLUMN 의 DATATYPE 은 다음과 같다.
■ CHAR(size) : 고정된 size 의 문자 값, 최대 255 자까지 지정할 수 있다.
■ VARCHAR2(size) : size내에서의 가변길이 문자 값,최대 2000자까지 지정할 수 있다.
■ LONG : 가변길이 문자 값, 최대 2 기가 바이트까지 사용할 수 있다. TABLE 당 한 개의 COLUMN 에만 지정 가능하다.
■ NUMBER(p,s) : 정수, 소수 자리수의 합이 P, 소수 자리수가 s 인 숫자값, 최대 38 자리수까지 지정할 수 있다.
■ DATE : 날짜와 시간 값, B.C. 4712년 1월 1일부터 A.D. 4712년 12월 31일까지 입력할 수 있다.
■ RAW(size) : size 내에서의 가변길이 BINARY DATA ■ LONGRAW : 가변길이 BINARY DATA

• 다른 table로부터 table생성
기존하는 TABLE 로 부터 데이타와 구조를 복사하여 TABLE 을 생성한다.
CREATE TABLE table명 [(column명, column명...)] - AS subquery ;
[ 예제 ] S_EMP TABLE 에서 DEPT_ID 가 41 인 사원들의 ID, LAST_NAME, USERID, START_DATE 만을 복사하여 EMP_41 TABLE 을 생성하시오.
CREATE TABLE EMP_41 AS SELECT ID, LAST_NAME, USERID, START_DATE
FROM S_EMP WHERE DEPT_ID = 41;
(S_EMP TABLE 에서 COLUMN명, TYPE, SIZE, NOT NULL CONSTRAINT 가 복사되어 EMP_41 TABLE 이 생성되며,
데이타는 DEPT_ID = 41 인 ROW 만 복사된다.)

• Constraint
CONSTRAINT 의 종류는 다음과 같다.
■ NOT NULL : COLUMN에 NULL값이 입력되는 것을 허용하지 않는다. COLUMN-CONSTRAINT 로만 기술해야 한다.
■ UNIQUE : 한 개의 COLUMN혹은 복합 COLUMN을 UNIQUE KEY로 지정하며 UNIQUE KEY에는 중복된 값을 허용하지 않는다.
한개의 COLUMN 으로 구성된 UNIQUE KEY 는 NULL 값을 허용한다.
COLUMN 이나 TABLE-CONSTRAINT 로 기술할 수 있다.
복합 COLUMN 으로 구성된 UNIQUE KEY 는 TABLE-CONSTRAINT 로만 기술해야 한다.
UNIQUE KEY COLUMN 의 UNIQUE INDEX FILE 이 자동 생성된다.
■ PRIMARY KEY
ROW 를 UNIQUE 하게 대표할 수 있는 한개의 COLUMN 혹은 복합 COLUMN 으로 지정한다.
PRIMARY KEY 에는 중복된 값과 NULL 값을 허용하지 않는다.
TABLE 당 한 개의 PRIMARY KEY 만 지정할 수 있다. COLUMN 이나 TABLE-CONSTRAINT 로 기술할 수 있다.
복합 COLUMN 으로 구성된 PRIMARY KEY 는 TABLE-CONSTRAINT 로만 기술해야 한다.
PRIMARY KEY COLUMN 의 UNIQUE INDEX FILE 이 자동 생성된다.
■ FOREIGN KEY
한개의 COLUMN 혹은 복합 COLUMN 으로 지정한다.
같은 TABLE 혹은 다른 TABLE의 PRIMARY KEY 나 UNIQUE KEY 값을 참조한다.
FOREIGN KEY 값은 모 TABLE 에 존재하는 데이타와 같던가 NULL 값을 허용한다.
COLUMN 이나 TABLE-CONSTRAINT 로 기술할 수 있다.

- 계속(11) -


※ CHECK : 각각의 ROW 가 만족해야할 조건을 지정한다.
조건식은 QUERY 조건식과 동일하게 지정한다. (단, 다음과 같은 것은 사용할 수 없다.)
CURRVAL, NEXTVAL, LEVEL, ROWNUM, SYSDATE, USER COLUMN이나 TABLE-CONSTRAINT로 기술할 수 있다.
CONSTRAINT 명은 다음과 같이 지정한다.
? CONSTRAINT 는 DICTIONARY 에 저장되므로 참조하기 쉽게 의미있게 붙여준다.
? 일반적으로 TABLE명_COLUMN명_CONSTRAINT종류와 같은 형태로 지정한다.
? 사용자가 CONSTRAINT 명을 지정하지 않으면 ORACLE7이 SYS_Cn의 형태로 붙인다.
? 동일한 USER 내에서 CONSTRAINT명은 UNIQUE해야 한다.
CONSTRAINT 는 다음과 같이 기술할 수 있다.
COLUMN-CONSTRAINT : column명 [CONSTRAINT constraint명] constraint종류
TABLE-CONSTRAINT : [CONSTRAINT constraint명] constraint종류 (column명, column명..)

• Table 생성
CREATE TABLE table명 - (column명 type(size) [DEFAULT VALUE] [column constraint],
column명 type(size) [DEFAULT VALUE] [column constraint], - .... , - [table constraint], - [table constraint], ....) ;
[ 예제 ] S_EMP TABLE CHART를 보고 TABLE 을 생성하시오.
(단, TABLE CONSTRAINT 로 기술할 수 있는 것은 TABLE CONSTRAINT 로 정의하시오.)
CREATE TABLE S_EMP(ID NUMBER(7), LAST_NAME VARCHAR2(25) CONSTRAINT S_EMP_LAST_NAME_NN NOT NULL,
FIRST_NAME VARCHAR2(25), USERID VARCHAR2(8) CONSTRAINT S_EMP_USERID_NN NOT NULL,
START_DATE DATE DEFAULT SYSDATE, COMMENTS VARCHAR2(25), MANAGER_ID NUMBER(7),
TITLE VARCHAR2(25),
DEPT_ID NUMBER(7),
SALARY NUMBER(11,2),
COMMISSION_PCT NUMBER(4,2),
CONSTRAINT S_EMP_ID_PK PRIMARY KEY(ID),
CONSTRAINT S_EMP_USERID_UK UNIQUE,
CONSTRAINT S_EMP_DEPT_ID_FK FOREIGN KEY(DEPT_ID)
REFERENCES S_DEPT(ID),
CONSTRAINT S_EMP_COMMISSION_PCT CHECK
(COMMISSION_PCT IN (10, 12.5, 15, 17.5, 20))) ;

● 제 7 장. Data DICTIONARY
• DICTIONARY
? DATABASE 가 만들어 졌을때 DICTIONARY TABLE 도 만들어 진다.
? DATABASE 가 사용중일때 DICTIONARY TABLE 은 ORACLE7 SERVER 에 의해 UPDATE 된다.
? 사용자들은 DICTIONARY TABLE 을 SELECT 할 수 있다. ? DICTIONARY TABLE 은 SYS USER 의 소유다.
? DICTIONARY TABLE의 값은 대문자로 들어있다. ? DICTIONARY TABLE 의 종류는 다음과 같은 방법으로 알 수 있다.
SELECT   *
FROM    DICTIONARY ;
DICTIONARY TABLE 의 종류는 다음과 같다.
? USER : USER 가 소유하고 있는 OBJECT 의 정보를 보여준다.
? ALL : USER 가 ACCESS 할 수 있는 OBJECT 의 정보를 보여준다.
? DBA : DBA USER 가 ACCESS 할 수 있는 OBJECT 의 정보를 보여준다.


- 계속(12) -


• 활용예
DICTIONARY TABLE 의 검색예는 다음과 같다.
■ 자신이 갖고 있는 TABLE 의 이름을 검색한다.
SELECT   OBJECT_NAME - FROM    USER_OBJECTS - WHERE   OBJECT_TYPE = 'TABLE';
■ 자신이 갖고 있는 OBJECT 의 종류를 검색한다.
SELECT   DISTINCT OBJECT_TYPE - FROM   USER_OBJECTS;
■ GRANT 와 관련된 DICTIONARY TABLE 의 이름을 검색한다.
SELECT   TABLE_NAME - FROM   DICTIONARY - WHERE   UPPER(COMMENTS) LIKE '%GRANT%';
■ S_EMP TABLE 의 CONSTRAINT 종류를 검색한다.
SELECT   CONSTRAINT_NAME, CONSTRAINT_TYPE, SEARCH_CONDITION, R_CONSTRAINT_NAME
FROM   USER_CONSTRAINTS - WHERE   TABLE_NAME = 'S_EMP';
■ S_EMP TABLE 의 COLUMN CONSTRAINT 를 검색한다.
SELECT CONSTRAINT_NAME, COLUMN_NAME - FROM USER_CONS_COLUMNS - WHERE   TABLE_NAME = 'S_EMP';

● 제 8 장. Data 조작
• 데이타 입력
TABLE 전체 COLUMN 에 값을 입력한다.
INSERT INTO table명 - VALUES (value, value...);
[ 예제 ] S_EMP TABLE에 다음과 같은 데이타를 입력하시오.
[ID : 26, LAST_NAME : Jung Mi, FIRST_NAME : Hong, USERID : Hjungmi,
START_DATE : 05-APR-97, COMMENTS : Teacher, MANAGER_ID : 10,
TITLE : Stock Clerk, DEPT_ID : 45, SALARY : 1200 COMMISSION_PCT : 10]
INSERT INTO S_EMP
VALUES (26, 'Jung Mi', 'Hong', 'Hjungmi', '05-APR-97', Teacher', 10, 'Stock Clerk', 45, 1200, 10) ;
(값을 지정하는 순서는 TABLE 의 COLUMN 순서에 맞춘다. 이 방법보다는 COLUMN명을 기술하여 입력하는 방법이 더 좋다.)

• 특정 column에 데이터입력
데이타를 입력하고자 하는 COLUMN을 선택하여 입력한다.
INSERT INTO table명(column명, column명....) - VALUES (value, value....);
[ 예제 ] S_EMP TABLE 에 다음과 같은 데이타를 입력하시오.
[ID : 27, LAST_NAME : Smith, FIRST_NAME : Donna, START_DATE : 05-APR-97]
INSERT INTO S_EMP(ID, LAST_NAME, FIRST_NAME, START_DATE)
VALUES (27, 'Smith', 'Donna', '05-APR-97') ;

• Null, 특수 value 입력
COLUMN 값에 NULL 값을 지정하는 방법은 3 가지가 있다. ? INSERT 문장의 COLUMN LIST 에서 생략한다.
? INSERT 문장의 VALUE 절에서 NULL 로 지정한다. ? INSERT 문장의 VALUE 절에서 '' 로 지정한다.
COLUMN 값에 특수한 값을 입력할 수 있다. (SYSDATE : 현재날짜와 시간, USER : 현재 USERID)
[ 예제 ] S_EMP TABLE 에 다음과 같은 데이타를 입력하시오.
[ID : 29, LAST_NAME : Donna, USERID : USER, SALARY : NULL, START_DATE : SYSDATE]
INSERT INTO S_EMP(ID, LAST_NAME, USERID, SALARY, START_DATE)
VALUES (29, 'Donna', USER, NULL, SYSDATE);



- 계속(13) -


• 특수형태의 날짜/시간입력
DATE 값을 입력할 때는 지정된 DATE 형태로 입력하여야 한다.
일반적으로 DD-MON-YY 형태를 사용하며, 이 형태로 데이타를 입력하면 세기는 현재의 세기로, 시간은 자정으로 입력된다.
다른 세기의 날짜나 시간을 입력하고 싶으면 TO_DATE FUNCTION 을 사용한다.
지정된 형태가 아닌 다른 형태의 날짜 값을 입력한다. ex>TO_DATE('날짜값','날짜형태')
[ 예제 ] S_EMP TABLE 에 다음과 같은 데이타를 입력하시오.
[ID : 30, LAST_NAME : Donna, USERID : SQL01, START_DATE : 199704051400]
INSERT INTO S_EMP(ID, LAST_NAME, USERID, START_DATE)
VALUES (30, 'Donna', 'SQL01', TO_DATE('199704051400','YYYYMMDDHH24MI'));

• 다른table로부터 데이타입력
INSERT 문장을 사용하여 기존하는 TABLE 의 데이타를 다른 TABLE 로 COPY 할 수 있다.
INSERT INTO table명[(column명, column명...)] - SUBQUERY;
[ 예제 ] S_EMP TABLE 의 ROW들을 HISTORY TABLE 로 COPY 하시오.
(단, 01-JAN-94 이전에 입사한 사원의 ID,LAST_NAME,SALARY,START_DATE 를 COPY 하시오)
INSERT INTO HISTORY(ID, LAST_NAME, SALARY, START_DATE)
SELECT ID, LAST_NAME, SALARY, START_DATE
FROM S_EMP WHERE START_DATE < '01-JAN-94' ;
(INSERT 절의 COLUMN 수와 SELECT 절의 COLUMN 수는 같아야 한다.)

• 데이타 수정
UPDATE 문장을 사용하여 이미 존재하는 COLUMN 값을 수정한다.
UPDATE table명 - SET column명 = value, [column명 = value] - [WHERE 조건식] ;
[ 예제 ] S_EMP TABLE 에서 ID 가 1 인 사원의 데이타를 다음과 같이 수정하시오. (DEPT_ID : 32, SALARY : 2550)
UPDATE S_EMP SET DEPT_ID = 32, SALARY = 2550 WHERE ID = 2 ;

• 데이타 삭제
DELETE 문장을 사용하여 데이타를 삭제한다.
DELETE FROM table명 - [WHERE 조건식] ;
[ 예제 ] S_EMP TABLE에서 ID 가 20 보다 큰 사원을 삭제하시오.
DELETE FROM S_EMP WHERE ID > 20 ;

• 저장
COMMIT 문장(COMMIT;)에 의해 변경된 모든 내용이 DATABASE에 저장되며 변경된 모든 데이타는 DATABASE에 저장된다.
그 전의 데이타는 완전히 지워지며 모든 사용자가 변경한 내용을 볼 수 있고 변경된 ROW 에 걸려있던 LOCK 이 해제된다.
그러므로 다른 사용자가 수정할 수 있으며 모든 SAVEPOINT 가 없어진다.
TRANSACTION 을 종료하고 TRANSACTION 안의 모든 변경된 작업을 저장한다.

• 취소
ROLLBACK 문장(ROLLBACK)은 모든 변경된 내용을 취소하며 수정하기 전의 데이타가 복구된다.
변경된 ROW 에 걸려있던 LOCK 이 해제되고 다른 사용자들이 그 ROW 에 대해서 변경을 할 수 있다.
TRANSACTION 을 종료하고 TRANSACTION 안의 모든 변경된 작업을 취소한다.



- 계속(14) -


• Savepoint지정~취소
TRANSACTION 안에서 ROLLBACK 할 수 있는 POINT 를 지정한다. 지정된 POINT 까지만 ROLLBACK 한다.
SAVEPOINT savepoint명 ; - ROLLBACK TO savepoint명 ;
[ 예제 ] S_EMP TABLE에서 TITLE이 Stock Clerk 인 사원의 SALARY 를 10% 인상하시오. SAVEPOINT 를 지정하시오.
S_REGION TABLE 에 다음과 같은 데이타를 입력하시오. ID : 8, NAME : Central
SAVEPOINT 까지 ROLLBACK 하시오. UPDATE 결과를 저장하시오.
UPDATE S_EMP SET SALARY = SALARY * 1.1 WHERE TITLE = 'Stock Clerk' ; SAVEPOINT S1;
INSERT INTO S_REGION(ID, NAME) VALUES (8, 'Central') ; ROLLBACK TO S1; COMMIT;

● 제 9 장. Table변경/삭제
• Column 추가
TABLE 에 새로운 COLUMN 을 추가한다.
ALTER TABLE table명 - ADD (column명 type(size) [DEFAULT value] [column_constraint], - ...........) ;
[ 예제 ] S_REGION TABLE 에 다음과 같은 COLUMN 을 추가하시오. (COMMENTS VARCHAR2(25))
ALTER TABLE S_REGION ADD (COMMENTS VARCHAR2(25))
(추가될 COLUMN 의 위치는 지정할 수 없다. 새로운 COLUMN 은 마지막 위치에 생성된다.)

• Column 변경
ALTER TABLE 문장의 MODIFY 절을 사용하여 다음과 같은 변경을 할 수 있다. COLUMN 의 크기를 확장할 수 있다.
데이타가 들어있지 않으면 COLUMN 의 크기를 줄일 수 있다. 데이타가 들어있지 않다면 COLUMN 의 타입을 수정할 수 있다.
COLUMN 에 NULL 값이 없다면 NOT NULL CONSTRAINT 를 지정할 수 있다. DEFAULT VALUE 를 변경할 수 있다.
이미 생성되어 있는 COLUMN 을 변경한다.
ALTER TABLE table명 - MODIFY (column명 type(size) [DEFAULT value] [NOT NULL], - .............) ;

• Constraint 추가
이미 생성되어 있는 TABLE 에 CONSTRAINT 를 추가한다.
ALTER TABLE table명 - ADD (table_constraint) ;
[ 예제 ] S_EMP TABLE 에 다음과 같은 CONSTRAINT 를 추가하시오.
[ MANAGER_ID COLUMN 이 S_EMP TABLE 의 ID COLUMN 을 REFERENCE 하는 FOREIGN KEY CONSTRAINT 를 추가하시오. ]
ALTER TABLE S_EMP
ADD (CONSTRAINT S_EMP_MANAGER_ID_FK FOREIGN KEY(MANAGER_ID) REFERENCES S_EMP(ID)) ;

• Constraint 삭제
이미 생성되어 있는 TABLE 의 CONSTRAINT 를 삭제한다.
ALTER TABLE table명 - DROP PRIMARY KEY | - UNIQUE(column명) | - CONSTRAINT constraint명 [CASCADE] ;
[ 예제 ] S_EMP TABLE의 다음과 같은 CONSTRAINT를 삭제하시오. (MANAGER_ID COLUMN의 FOREIGN KEY CONSTRAINT)
ALTER TABLE S_EMP DROP CONSTRAINT S_EMP_MANAGER_ID_FK ;

• 전체 데이타의 삭제
TRUNCATE 문장은 DDL 이다. ROLLBACK SEGMENT 를 만들지 않고 모든 데이타를 삭제한다.
데이타가 삭제된 FREE 영역은 환원된다. TABLE 로부터 모든 데이타를 삭제한다.
TRUNCATE TABLE table명 ;
[ 예제 ] S_ITEM TABLE 의 모든 데이타를 삭제하시오.
TRUNCATE TABLE S_ITEM ;

- 계속(15) -


• Constraint disable/enable
TABLE 에 있는 모든 데이타가 CONSTRAINT 를 만족시켜야 ENABLE 할 수 있다.
PRIMARY KEY, UNIQUE CONSTRAINT 를 ENABLE 하면 그에 따른 INDEX FILE 이 자동적으로 생성된다.
CASCADE OPTION 은 FOREIGN KEY CONSTRAINT 를 DISABLE 할 때 사용한다.
CONSTRAINT 를 삭제하고 새로 만들지 않고 DISABLE, ENABLE 한다.
ALTER TABLE table명-DISABLE |ENABLE PRIMARY KEY |-UNIQUE(column명) |CONSTRAINT constraint명 [CASCADE] ;
[ 예제 ] S_DEPT TABLE 의 PRIMARY KEY CONSTRAINT 를 DISABLE 시키시오.
ALTER TABLE S_DEPT DISABLE CONSTRAINT S_DEPT_ID_PK CASCADE;
(S_EMP TABLE 의 S_EMP_DEPT_ID_FK CONSTRAINT 도 자동적으로 DISABLE 된다.)

• Table 삭제
TABLE 을 삭제하면 그 TABLE 에 딸린 INDEX FILE 도 삭제된다.
VIEW, SYNONYM, STORED PROCEDURE, FUNCTION, TRIGGER 등은 삭제되지 않는다.
CASCADE CONSTRAINTS 는 모 TABLE 을 삭제하고 자 TABLE 의 FOREIGN KEY CONSTRAINT 도 삭제한다.
DROP TABLE table명 [CASCADE CONSTRAINTS] ;
[ 예제 ] S_DEPT TABLE 을 삭제하시오.
DROP TABLE S_DEPT CASCADE CONSTRAINTS ;

• 이름의 변경
TABLE, VIEW, SEQUENCE, SYNONYM 의 이름을 변경한다.
RENAME old명 TO new명 ;
[ 예제 ] S_ORD TABLE 의 이름을 S_ORDER 로 변경하시오.
RENAME S_ORD TO S_ORDER ;

● 제 10 장. Sequence
• Sequence 생성
SEQUENCE 는 여러 사용자에게 UNIQUE 한 값을 생성해 주는 OBJECT 이다.
SEQUENCE 를 사용하여 PRIMARY KEY 값을 자동적으로 생성한다.
CREATE SEQUENCE sequence명 - INCREMENT BY n - START WITH n - MAXVALUE n | NOMAXVALUE
MINVALUE n | NOMINVALUE - CYCLE | NOCYCLE - CACHE n | NOCACHE ;
[ 예제 ] S_DEPT TABLE 의 ID COLUMN 값에 사용할 SEQUENCE 를 다음과 같이 생성하시오.
(START : 51, INCREMENT : 1, MAXVALUE : 9999999, NOCYCLE, NOCACHE)
CREATE SEQUENCE S_DEPT_ID INCREMENY BY 1 START WITH 51
MAXVALUE 9999999 NOCACHE NOCYCLE ;

• Sequence 변경
SEQUENCE 에 정의된 값을 변경한다.
ALTER SEQUENCE sequence명 - INCREMENT BY n - MAXVALUE n | NOMAXVALUE - MINVALUE n | NOMINVALUE
CYCLE | NOCYCLE - CACHE n | NOCACHE ; -
[ 예제 ] S_DEPT_ID SEQUENCE 를 다음과 같이 수정하시오. (CACHE : 10)
ALTER SEQUENCE S_DEPT_ID
CACHE 10 ;



- 계속(16) -


• Sequence 삭제
SEQUENCE 를 삭제한다.
DROP SEQUENCE sequence명 ;
[ 예제 ] S_DEPT_ID SEQUENCE 를 삭제하시오.
DROP SEQUENCE S_DEPT_ID ;

● 제 11 장. VIEW
• Simple view
SUBQUERY 문장이 간단한 경우 VIEW 를 통해 SELECT,INSERT,UPDATE,DELETE 를 할 수 있다.
■ SELECT : SUBQUERY 의 조건식을 만족하는 데이타만 검색된다.
■ INSERT : NOT NULL COLUMN 을 다 포함하고 있는 경우 INSERT 를 할 수 있다.
SUBQUERY 의 조건식을 만족하지 않는 데이타도 입력이 가능하다.
■ UPDATE : VIEW 를 통해 SELECT 할 수 있는 데이타만 수정할 수 있다.
SUBQUERY 의 조건식을 만족하지 않는 데이타도 수정이 가능하다.
■ DELETE : VIEW 를 통해 SELECT 할 수 있는 데이타만 삭제할 수 있다.
CREATE VIEW view명 [(alias명, alias명....)] - AS SUBQUERY ;
[ 예제 ] S_EMP TABLE에서 DEPT_ID가 45인 사원의 ID, LAST_NAME, DEPT_ID, TITLE을 선택해서 VIEW를 생성하시오.
CREATE VIEW EMP41 AS SELECT ID, LAST_NAME, DEPT_ID, TITLE
FROM S_EMP WHERE DEPT_ID = 45 ;

• With check option
VIEW 를 정의할때 지정한 조건식을 만족하는 데이타만 INSERT, 또는 조건식을 만족하는 데이터로만 UPDATE 가 가능하다.
데이타가 VIEW 의 조건식을 만족하는지 CHECK 한다.
CREATE VIEW view명 [ (alias명, alias명...)] - AS SUBQUERY - WITH CHECK OPTION ;
[ 예제 ] S_EMP TABLE에서 DEPT_ID가 45인 사원의 ID, LAST_NAME, DEPT_ID, TITLE을 선택해서 VIEW를 생성하시오.
(단, DEPT_ID 가 45 가 아닌 사원은 입력되지 못하게 만드시오.)
CREATE VIEW EMP45 AS SELECT ID, LAST_NAME, DEPT_ID, TITLE
FROM S_EMP WHERE DEPT_ID = 45 WITH CHECK OPTION ;

• With read only
SELECT만 가능한 VIEW 를 생성한다.
CREATE VIEW view명 [(alias명, alias명...)] - AS SUBQUERY - WITH READ ONLY ;
[ 예제 ] S_EMP TABLE 에서 ID, LAST_NAME, DEPT_ID, SALARY 가 SELECT 만 되도록 VIEW 를 생성하시오.
CREATE VIEW R_EMP AS SELECT ID, LAST_NAME, SALARY
FROM S_EMP WITH READ ONLY ;

• Force
기준 TABLE 이 존재하지 않아도 VIEW 를 생성한다.
CREATE FORCE VIEW view명 [(alias명, alias명...)] - AS SUBQUERY ;
[ 예제 ] S_EMP TABLE 이 없어도 S_EMP TABLE 에서 ID, LAST_NAME, SALARY 를 선택해서 VIEW 를 생성하시오.
CREATE FORCE VIEW T_EMP
AS SELECT ID, LAST_NAME, SALARY
FROM S_EMP ;


- 계속(17) -


• complex view
SUBQUERY문장에 JOIN, FUNCTION, DISTINCT/연산이 포함된 경우를 말하며 이 경우 VIEW를 통한 DML은 수행할 수 없다.
COMPLEX VIEW 를 생성한다. CREATE VIEW view명 (alias명, alias명...) - AS SUBQUERY ;
[ 예제 ] S_EMP TABLE과 S_DEPT TABLE에서 ID, LAST_NAME, DEPT_ID, NAME을 선택해서 VIEW를 생성하시오.
CREATE VIEW EMPDEPT AS SELECT E.ID, E.LAST_NAME, E.DEPT_ID, D.NAME
FROM S_EMP E, S_DEPT D WHERE E.DEPT_ID = D.ID ;

• View 삭제
VIEW 를 삭제하면 DATABASE 로부터 VIEW 의 정의가 삭제된다. VIEW 가 기초로 한 TABLE 은 삭제되지 않는다.
DROP VIEW view명 ;
[ 예제 ] EMPDEPT VIEW 를 삭제하시오.
DROP VIEW EMPDEPT ;

● 제 12 장. Index
• Index 생성
TABLE 생성시 PRIMARY KEY 나 UNIQUE CONSTRAINT 를 지정하면 UNIQUE INDEX 가 자동적으로 만들어 진다.
이 외의 COLUMN 으로 QUERY 를 할 때 속도를 향상시키기 위해서 INDEX 를 생성한다.
INDEX를 생성하면 QUERY 속도는 빨라질 수 있으나 DML속도는 늦어질 수 있다.
일반적으로 다음과 같은 경우에 INDEX 를 생성한다.
■ COLUMN 이 WHERE 절이나 JOIN 조건식에 빈번하게 사용될 때 ■ COLUMN 값이 넓게 분포되어 있을 때
■ COLUMN 값에 NULL 값이 많이 포함되어 있을 때 ■ TABLE 이 크고 QUERY 하는 데이터 양이 10 % 이하일 때
CREATE [UNIQUE] INDEX index명 - ON table명(column명[, column명...]) ;
[ 예제 ] S_EMP TABLE 에서 LAST_NAME 의 QUERY 속도를 향상하기 위하여 INDEX 를 생성하시오.
CREATE INDEX S_EMP_LAST_NAME_IDX ON S_EMP(LAST_NAME) ;

• Index 삭제
INDEX 는 수정할 수 없다. 수정하고 싶은 경우 삭제하고 다시 생성한다.
DROP INDEX index명 ;
[ 예제 ] S_EMP_LAST_NAME_IDX INDEX 를 삭제하시오.
DROP INDEX S_EMP_LAST_NAME_IDX ;

'프로그래밍 > DB' 카테고리의 다른 글

[펌] PL-SQL 정리  (0) 2007.11.27
select * from user_catalog;  (0) 2007.11.27
[펌] 인덱스 생성 [CREATE INDEX]  (0) 2007.11.27
Tablespace 정보보기  (0) 2007.11.27
Tablespace 삭제  (0) 2007.11.27

[펌] 인덱스 생성 [CREATE INDEX]

프로그래밍/DB 2007. 11. 27. 14:29 Posted by galad
출처 블로그 > on2uu의 블로그
원본 http://blog.naver.com/on2uu/80003972222

CREATE [ UNIQUE | BITMAP ] INDEX index_name ON table_name(column_name)

[TABLESPACE tablespace_name];


UNIQUE : UNIQUE Index를 생성한다.

BITMAP : BITMAP Index를 생성한다.

index_name : 생성하고자 하는 인덱스 이름

table_name : 인덱스를 생성하고자 하는 테이블 이름

column_name : 인덱스로 생성하고자 하는 컬럼 이름

tablespace_name : 인덱스가 위치할(생성될) 테이블 스페이스 이름


예) CREATE INDEX idx_emp ON tb_emp (empno);

tb_emp 테이블에 empno 컬럼을 이용하여 idx_emp를 생성한다.


범례)

대문자 : Reserved Word

소문자 : User Define

[ ] : Option, 지정하지 않아도 되거나 생략시 기본 설정값으로 대체됨.


적용)

ORACLE 7 이상

'프로그래밍 > DB' 카테고리의 다른 글

select * from user_catalog;  (0) 2007.11.27
[펌] SQL*Plus에서 꼭 알아두어야 할 활용 매뉴얼~!  (0) 2007.11.27
Tablespace 정보보기  (0) 2007.11.27
Tablespace 삭제  (0) 2007.11.27
Making a Tablespace Read Only  (0) 2007.11.27

Tablespace 정보보기

프로그래밍/DB 2007. 11. 27. 14:29 Posted by galad
Tablespace 정보보기
Tablespace과 관련된 데이타딕셔너리 뷰

USER_EXTENTS, DBA_EXTENTS, USER_SEGMENTS, DBA_SEGMENTS,
USER_FREE_SPACE, DBA_FREE_SPACE, DBA_USERS, DBA_TS_QUOTAS,
USER_TABLESPACES, DBA_TABLESPACES, DBA_DATA_FILES, V$DATAFILE

DBA_TABLESPACE
데이타베이스에 있는 모든 Tablespace 이름, 기본저장영역의 매개변수값에 대한 정보
 
 SQL> SELECT tablespace_name "TABLESPACE",
              initial_extent "INITIAL_EXT",
              next_extent "NEXT_EXT",
              min_extents "MIN_EXT",
              max_extents "MAX_EXT",
              pct_increase FROM sys.dba_tablespaces;

 TABLESPACE   INITIAL_EXT  NEXT_EXT   MIN_EXT   MAX_EXT PCT_INCREASE 
-----------   -----------  --------  --------- -------- ------------
 SYSTEM          10240     10240         1       121           50
 USER_DATA       10240     10240         1       121           50
 ROLLBACK_DATA   10240     10240         1       121           50
 TEMPORARY_DATA  10240     10240         1       121           50
 SP_TEST         51200     51200         2        50           50

DBA_DATA_FILES
Tablespace에 연관된 데이타파일의 이름, 크기 등의 정보
 
 SQL> SELECT file_name,bytes,tablespace_name FROM sys.dba_data_files;

 FILE_NAME                              BYTES       TABLESPACE_NAME
-----------------------------------  ------------  -----------------
 C:\ORAWIN95\DATABASE\USR1ORCL.ORA     2097152       USER_DATA
 C:\ORAWIN95\DATABASE\RBS1ORCL.ORA     5242880       ROLLBACK_DATA
 C:\ORAWIN95\DATABASE\TMP1ORCL.ORA     2097152       TEMPORARY_DATA
 C:\ORAWIN95\DATABASE\SYS1ORCL.ORA     11534336      SYSTEM
 D:\SP_TEST1.DBF                       5242880       SP_TEST

DBA_FREE_SPACE
데이타베이스에 있는 각Tablespace의 빈 확장영역크기에 대한 정보
 
 SQL> SELECT tablespace_name,file_id,count(*) "PIECES", MAX(blocks) "MAXIMUM",
       MIN(blocks) "MINMUM", AVG(blocks) "AVERAGE", SUM(blocks) "TOTAL"
       FROM sys.dba_free_space WHERE tablespace_name = *SP_TEST* 
       OR tablespace_name = *SYSTEM*
       GROUP BY tablespace_name,file_id;
 
 TABLESPACE_NAME  FILE_ID  PIECES  MAXIMUM  MINMUM  AVERAGE  TOTAL
---------------- -------- ------- -------- ------- -------- -------
   SP_TEST           5       1      2559      2559   2559     2559
   SYSTEM            1       8      348       20     93.5      748
SUM (각 Tablespace의 빈영역의 크기)
PIECES (Tablespace의 데이타 파일에 있는 단편화 크기)
MAXIMUM (가장 큰영역)