<스프링 시큐리티 적용시>


web.xml



<!-- 파일업로드 필터 -->
<filter>
    <filter-name>springMultipartFilter</filter-name>
    <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>springMultipartFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 스프링 시큐리티 필터 -->
<!-- 스프링 시큐리티 필터는 파일업로드 필터 앞에 나오면 안됨-->
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
cs



Servers의 content.xml



<Content>
<!-- 밑에꺼로 변경 --> 
<Context allowCasualMultipartParsing="true">
cs



<파일 용량 에러>


Servers의 server.xml


1
2
3
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
<!-- 밑에꺼로 변경 --> 
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" maxPostSize="10000000"/>
cs



tomcat 사용할 때 post로 데이터 전송하게 되면

일반적으로는 정상처리되나, 

용량이 너무 크게되면 안됨(default값이 2M인 2097152이다)


비슷하게 maxParameterCount도 있다(get이나 post로 전송시 최대 파라미터 개수)

하지만 maxParameterCount는 default가 10000개이므로 

파라미터 개수로 에러나는 경우는 적을듯


참조 : http://java7.tistory.com/83

'SPRING' 카테고리의 다른 글

스프링 파일 업로드/다운로드  (1) 2018.03.27
스프링에서 한글 인코딩  (0) 2018.03.26
스프링 시큐리티 적용시키기  (1) 2018.03.05

 pom.xml


<!-- fileUpload/download -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>
 
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>
cs



web.xml


<filter>
        <filter-name>springMultipartFilter</filter-name>
        <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>springMultipartFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
cs



dispatcher-servlet.xml



<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="52428800"/>    <!-- 50MB -->
        <property name="maxInMemorySize" value="1048576"/>    <!-- 1MB -->
</bean>
cs



FileUtils.java



//다중 파일 업로드
public List<FileVO> multiUploadFile(MultipartHttpServletRequest request) throws IllegalStateException, IOException {
        
    List<FileVO> filelist = new ArrayList<BoardVO>();
    //file이라는 파라미터를 리스트로 받음
    List<MultipartFile> uploadFileList = request.getFiles("file");
        
    for (int i = 0; i < uploadFileList.size(); i++) {
        //파일 원래이름
        String oriFileName = uploadFileList.get(i).getOriginalFilename();
            
        if ((oriFileName != null&& (!oriFileName.equals(""))) {
            String ext = "";
            //확장자 구분
            int index = oriFileName.lastIndexOf(".");
            if (index != -1) {
                ext = oriFileName.substring(index);
            }
            //파일 저장이름
            String saveFileName = "File-" + UUID.randomUUID().toString()+ ext;
            //파일 저장
            uploadFileList.get(i).transferTo(new File("저장경로" + saveFileName));
            filelist.add(i, new BoardVO());
            filelist.get(i).setFileOrgName(oriFileName);
            filelist.get(i).setFileSaveName(saveFileName);
                
            }
        }
        return filelist;
    }
 
//파일 다운로드
public void downloadFile(FileVO fileVO, HttpServletRequest request, HttpServletResponse response) throws Exception {
        
    File file = new File("저장경로", fileVO.getFileSaveName());
 
    BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
 
    //User-Agent : 어떤 운영체제로  어떤 브라우저를 서버( 홈페이지 )에 접근하는지 확인함
    String header = request.getHeader("User-Agent");
    String fileName;
    
    if ((header.contains("MSIE")) || (header.contains("Trident")) || (header.contains("Edge"))) {
        //인터넷 익스플로러 10이하 버전, 11버전, 엣지에서 인코딩 
        fileName = URLEncoder.encode(boardfile.getFileOrgName(), "UTF-8");
    } else {
        //나머지 브라우저에서 인코딩
        fileName = new String(boardfile.getFileOrgName().getBytes("UTF-8"), "iso-8859-1");
    }
    //형식을 모르는 파일첨부용 contentType
    response.setContentType("application/octet-stream");
    //다운로드와 다운로드될 파일이름
    response.setHeader("Content-Disposition""attachment; filename=\""+ fileName + "\"");
    //파일복사
    FileCopyUtils.copy(in, response.getOutputStream());
    in.close();
    response.getOutputStream().flush();
    response.getOutputStream().close();
    }
cs



참조 :    http://androphil.tistory.com/330

     http://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte2:fdl:file_download

'SPRING' 카테고리의 다른 글

스프링 파일 업로드 추가사항  (0) 2018.03.27
스프링에서 한글 인코딩  (0) 2018.03.26
스프링 시큐리티 적용시키기  (1) 2018.03.05

Get전송방식


Servers server.xml

URIEncoding="UTF-8" 추가



<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
->
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
cs

Post전송방식
web.xml encodingFilter추가

<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>*.do</url-pattern>
</filter-mapping>
cs


'SPRING' 카테고리의 다른 글

스프링 파일 업로드 추가사항  (0) 2018.03.27
스프링 파일 업로드/다운로드  (1) 2018.03.27
스프링 시큐리티 적용시키기  (1) 2018.03.05

--게시판 제목, 작성자, 내용, 등록일자
CREATE TABLE BOARD (
  NO NUMBER,
  TITLE VARCHAR2(100),
  WRITER VARCHAR2(50),
  CONTENTS VARCHAR2(200),
  REGDATE DATE,
  CONSTRAINT BOARD_PK PRIMARY KEY(NO)
);
 
 
--댓글 번호, 테이블 번호, 댓글 작성자, 댓글 내용
CREATE TABLE COMMENTS (
  C_NO NUMBER,
  NO NUMBER,
  C_WRITER VARCHAR2(50),
  C_CONTENTS VARCHAR2(100),
  CONSTRAINT COMMENT_PK PRIMARY KEY (C_NO),
  CONSTRAINT COMMENT_FK FOREIGN KEY (NO) REFERENCES BOARD(NO)
);

 
--오라클 복합 게시판 쿼리(댓글갯수, 페이징, 검색조건)
SELECT 
       b.rn, b.TITLE, b.WRITER, TO_CHAR(b.REGDATE, 'YYYY-mm-dd') AS REGDATE, b.cnt
  FROM (
        SELECT ROWNUM rn, a.TITLE, a.WRITER, a.REGDATE, a.cnt
          FROM (
                SELECT 
                       B.NO,B.TITLE, B.WRITER, B.REGDATE
                       ,(
SELECT COUNT(NO) 
                         FROM COMMENTS A
                         WHERE A.NO = B.NO
                        ) AS CNT                        --댓글갯수 
                  FROM BOARD B
                 WHERE B.TITLE = '%TEST%'                --검색조건
                 ORDER BY NO DESC
               ) a 
         WHERE ROWNUM <= 20                                --마지막 게시물 번호
       ) b
WHERE rn BETWEEN 11 AND 20;                                --11번부터 20번 게시물

cs


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

오라클 11g hr계정 연습문제  (3) 2018.02.28

웹을 통해 데이터를 주고받는 업무를 진행할 경우, 보안상의 문제가 발생하기 쉽다.

Security Service는 웹을 통한 서비스 이용 시 발생할 수 있는 다양한 보안상의 취약점들을 사전에 인지하고 대응함으로써, 서비스의 안정성을 확보한다.

Security Service는 사용자 정보를 DB에서 관리하여 인증을 거쳐야만 접근할 수 있는 Authentication과 사용자 권한 정보를 계층화 시켜서 화면 및 페이지, 또는 메소드에 접근할 수 있는 Authorization이 포함된다.



웹어플리케이션 인증절차


1.리소스 요청

2.요청에 대해 보호되고 있는 자원인지 판단

3.아직 인증이 안되었으므로 HTTP 응답코드(오류) 또는 특정 페이지로 redirect

4.인증 메커니즘에 따라 웹 페이지 로그인 폼 또는 X509 인증서

5.입력 폼의 내용을 HTTP post 또는 인증 세부사항을 포함하는 HTTP 헤더를 서버로 요청

6.신원정보(credential)가 유효한지 판단

7.유효한 경우 다음단계 진행

8.유효하지 않을 경우 신원정보 재요청(되돌아감)

9.보호 자원의 접근 권한이 있을 경우 요청 성공 / 접근 권한이 없을 경우 forbidden 403 HTTP 오류






pom.xml


<!-- security -->
<dependency>
    <groupId>org.springframework.security</groupId>
     <artifactId>spring-security-web</artifactId>
    <version>4.1.2.RELEASE</version>
</dependency>
 
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
     <version>4.1.2.RELEASE</version>
 </dependency>
 
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
    <version>4.1.2.RELEASE</version>
</dependency>
 
cs



web.xml



<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
 
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
cs



context-security.xml





<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.1.xsd">
     
     <!-- url패턴과 스프링 시큐리티를 무시-->
    <security:http pattern="/**/*.js" security="none"/>
    <security:http pattern="/**/*.css" security="none"/>
    <security:http pattern="/images/*" security="none"/>
    
    <!-- 로그인페이지, 기본적인 인증, 로그아웃 기능을 사용, SpEL 사용 -->
    <security:http auto-config="true" use-expressions="true">
         <!-- 세션 관리 -->
        <security:session-management invalid-session-url="/">
            <!-- 동일 ID의 세션 최대수가 한 개, 그 이상일 경우는 기존 세션 무효화 -->
            <security:concurrency-control max-sessions="1" error-if-maximum-exceeded="false" />
        </security:session-management>
        
        <!-- 특정 url 패턴과 그것에 대한 권한 -->
        <security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
         <security:intercept-url pattern="/write.do" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" method="GET"/>
        <security:intercept-url pattern="/**/update.do" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')"/>
        <security:intercept-url pattern="/**/delete.do" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')"/
        <security:intercept-url pattern="/**" access="permitAll"/>
        
        <!--     
                로그인 폼
                login-page                                :    로그인 폼 페이지
                login-processing-url                     :    로그인 폼 페이지에서 post로 보내는 url
                always-use-default-target="true"일 경우    :    write.do -> login.do -> list.do
                always-use-default-target="false"일 경우 :    write.do -> login.do -> write.do
                default-target-url                        :    인증이 성공하면 redirect로 보내는 url        
                authentication-failure-url                :    로그인 폼 페이지에서 실패할때 보내는 url
                username-parameter                        :    로그인 폼 파라미터 (아이디)
                password-parameter                        :    로그인 폼 파라미터 (비밀번호)
         -->
        <security:form-login 
            login-page="/login.do"
            login-processing-url="/login"
            always-use-default-target="true"
            default-target-url="/list.do"
            authentication-failure-url="/login.do?error=true"
            username-parameter="id"
            password-parameter="password"
        />
        
        <!-- 
            자동로그인  
            key                      :    키 이름
            token-validity-seconds   :    유효시간
            remember-me-parameter    :    로그인 폼 파라미터 (remember-me)
        -->
        <security:remember-me key="remember-key" token-validity-seconds="604800" remember-me-parameter="remember-me-param"/>
        
        <!-- 
            로그아웃
            logout-url            :    로그아웃 url
            logout-success-url    :    로그아웃 정상적일때 보내는 url
            invalidate-session    :    로그아웃 했을때 세션을 무효화 할껀지 설정
            delete-cookies        :    삭제하는 쿠키
         -->
        <security:logout logout-url="/logout" logout-success-url="/list.do" invalidate-session="true" 
            delete-cookies="JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE"/>
        
    </security:http>
    
    <!-- 인증 관련 설정 -->
    <security:authentication-manager>
        <!-- 인증 제공자, userDetails와 userDetailsService 인터페이스 이용-->
        <security:authentication-provider>
            <!--
                jdbc 베이스로 한  userDetailsService
                data-source-ref                    : 참조할 DB빈 
                users-by-username-query            : 로그인 폼에서 입력된 아이디로 아이디, 비번, 활성화 칼럼을 select해 가져오는 쿼리
                                                     기본 파라미터가 username, password, enabled이므로 db의 칼럼이 다르면 as로 맞춰준다
                authorities-by-username-query     : 로그인 폼에서 입력된 아이디로 아이디, 권한 칼럼을 select해 가져오는 쿼리
                                                    기본 파라미터가 username, authority이므로 db의 칼럼이 다르면 as로 맞춰준다
            -->
            <security:jdbc-user-service
                data-source-ref="dataSource"
                users-by-username-query="select id as username, password, enabled from users where id = ?"
                authorities-by-username-query="select id as username, authority from user_roles where id = ?"
            />
        </security:authentication-provider>
    </security:authentication-manager>
</beans>

cs



Controller.java



@RequestMapping(value="login.do", method=RequestMethod.GET)
public ModelAndView loginForm(ModelAndView mav) {
    UsersVO usersVO = new UsersVO();
        
    mav.addObject("usersVO",usersVO);
    mav.setViewName("login");
    return mav;
}
cs



login.jsp




<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>    
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">
table {
    border: 1px solid black;
    border-collapse: collapse;
}
tr, td {
    border: 1px solid black;
}
</style>
<script type="text/javascript">
function goList() {
    location.href = "${pageContext.request.contextPath}/";
}
</script>
</head
<body>
    <header>스프링 시큐리티 로그인 테스트</header>
    <section>
        <div>
            <form:form commandName="usersVO" action="${ pageContext.request.contextPath}/login"
                <table>
                    <tr>
                        <td>
                            <form:input path="id" placeholder="아이디"/
                        </td
                        <td rowspan="2">
                            <input type="submit" value="로그인">
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <form:password path="password" placeholder="비밀번호"/>
                        </td>
                    </tr>
                    
                </table>
                    <input id="remember_me" name="remember-me-param" type="checkbox"/>아이디 저장
            </form:form>
            <input type="button" value="메인으로" onclick="goList()">
            <br>
            <c:if test="${ error eq 'true' }">
            <!-- 에러메세지와 무슨 에러인지 나타나게해줌 -->
            ${ sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message }
            <c:remove var="SPRING_SECURITY_LAST_EXCEPTION" scope="session"/>
            </c:if>
        </div>
    </section>
    <footer></footer>
</body>
</html>
cs



access 내장표현식


hasRole([role])

 현재 로그인된 사용자가 지정된 role을 가지고 있으면 true를 반환. 

 제공된 role이 'ROLE_'로 시작하지 않으면 기본적으로 'ROLE_'를 추가.

 hasAnyRole([role1,role2])

 현재 로그인된 사용자가 콤마(,)로 분리하여 주어진 role들 중 하나라도   

 가지고 있으면 true를 반환. 

 제공된 role이 'ROLE_'로 시작하지 않으면 기본적으로 'ROLE_'를 추가. 

 hasAuthority([authority])

 현재 로그인된 사용자가 지정된 권한이 있으면 true를 반환. 

 hasAnyAuthority([authority1,authority2])

 현재 로그인된 사용자가 콤마(,)로 분리하여 주어진 권한들중 하나라도 가지고 있으면 true를 반환. 

 principal

 현재 사용자를 나타내는 principal 객체에 직접 접근가능. 

 authentication SecurityContext로 부터 얻은 Authentication 객체에 직접 접근가능.

 permitAll

 항상 true를 반환. 

 denyAll

 항상 false로 반환. 

 isAnonymous()

 현재 사용자가 익명사용자(로그인 안됨) 사용자이면 true를 반환. 

 isRememberMe()

 현재 로그인된 사용자가 remember-me 사용자이면 true를 반환.

 (로그인 정보 기억 기능에 의한 사용자) 

 isAuthenticated()

 현재 사용자가 로그인된 사용자라면 true를 반환. 

 isFullyAuthenticated()

 로그인 정보 기억(remember-me)이 아니라 아이디/비밀번호를 입력하여 로그인 했다면 true를 반환.

 hasPermission(Object target, Object permission)

 사용자가 주어진 권한으로 제공된 대상에 액세스 할 수 있으면 true를 반환. 

 hasPermission(Object targetId, String targetType, Object permission)

 사용자가 주어진 권한으로 제공된 대상에 액세스 할 수 있으면 true를 반환.



  .jsp


1
2
3
4
5
6
7
8
9
10
<!-- 스프링 시큐리티 태그 -->
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%> 
 
<sec:authorize access="isAuthenticated()"></sec:authorize>
<!-- 현재 인증된 주체에 대해 구성된 액세스 표현식이 참으로 평가되는 경우 태그의 본문을 출력하는 태그 -->
 
<sec:authentication property="principal.username" var="loginID"/>${ loginID }
<!-- 현재의 Authentication 객체에 대한 액세스를 허용. 
var로 할당안하면 바로 출력 var로 할당하면 ${var의 이름}로 해야 출력-->
 
cs

 

 

 참조 :    http://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte2:fdl:server_security:architecture

                 http://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte3:fdl:server_security:authentication

                 http://pentode.tistory.com/144

 

 

 

 

 

 

'SPRING' 카테고리의 다른 글

스프링 파일 업로드 추가사항  (0) 2018.03.27
스프링 파일 업로드/다운로드  (1) 2018.03.27
스프링에서 한글 인코딩  (0) 2018.03.26


--오라클 11g hr계정 연습문제
 
--1. 직책(Job Title)이 Sales Manager인 사원들의 입사년도와 입사년도(hire_date)별 평균 급여를 출력하시오. 
--   출력 시 년도를 기준으로 오름차순 정렬하시오. 
SELECT 
       TO_CHAR(e.HIRE_DATE, 'YYYY') AS HIRE_DATE, AVG(e.salary) AS AVG
  FROM EMPLOYEES e, JOBS j
 WHERE e.JOB_ID = j.JOB_ID AND j.JOB_TITLE = 'Sales Manager' 
 GROUP BY TO_CHAR(e.HIRE_DATE,'YYYY')
 ORDER BY TO_CHAR(e.HIRE_DATE,'YYYY') ASC
;
 

--2. 각 도시(city)에 있는 모든 부서 직원들의 평균급여를 조회하고자 한다. 
--   평균급여가 가장 낮은 도시부터 도시명(city)과 평균연봉, 해당 도시의 직원수를 출력하시오. 
--   단, 도시에 근 무하는 직원이 10명 이상인 곳은 제외하고 조회하시오.
SELECT 
       l.CITY , AVG(e.SALARY) , COUNT(*)
  FROM EMPLOYEES e, LOCATIONS l, DEPARTMENTS d
 WHERE e.DEPARTMENT_ID = d.DEPARTMENT_ID AND d.LOCATION_ID = l.LOCATION_ID
 GROUP BY l.CITY
HAVING COUNT(*< 10
 ORDER BY AVG(e.SALARY) ASC
;
  

--3. ‘Public  Accountant’의 직책(job_title)으로 과거에 근무한 적이 있는 모든 사원의 사번과 이름을 출력하시오. 
--   (현재 ‘Public Accountant’의 직책(job_title)으로 근무하는 사원은 고려 하지 않는다.)      
--   이름은 first_name, last_name을 아래의 실행결과와 같이 출력한다.
SELECT 
       e.EMPLOYEE_ID , CONCAT(CONCAT(e.FIRST_NAME,' '), e.LAST_NAME) 
  FROM EMPLOYEES e, JOBS j, JOB_HISTORY h
 WHERE j.JOB_TITLE = 'Public Accountant' AND h.JOB_ID = j.JOB_ID AND e.EMPLOYEE_ID = h.EMPLOYEE_ID
;
 

--4. 자신의 매니저보다 연봉(salary)를 많이 받는 직원들의 성(last_name)과 연봉(salary)를 출 력하시오. 
SELECT
       e.LAST_NAME, e.SALARY
  FROM EMPLOYEES e, EMPLOYEES m
 WHERE e.MANAGER_ID = m.EMPLOYEE_ID AND e.SALARY > m.SALARY   
;      
 

--5. 2007년에 입사(hire_date)한 직원들의 사번(employee_id), 이름(first_name), 성(last_name), 
-- 부서명(department_name)을 조회합니다.  
--   이때, 부서에 배치되지 않은 직원의 경우, ‘<Not Assigned>’로 출력하시오. 
SELECT 
       e.EMPLOYEE_ID , e.LAST_NAME , e.FIRST_NAME , NVL(d.DEPARTMENT_NAME, '<Not Assigned>')
  FROM EMPLOYEES e
  LEFT JOIN DEPARTMENTS d
  ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
  WHERE TO_CHAR(e.HIRE_DATE, 'YYYY'= '2007'
  ORDER BY e.EMPLOYEE_ID ASC
;  

 
--6. 업무명(job_title)이 ‘Sales Representative’인 직원 중에서 연봉(salary)이 9,000이상, 10,000 이하인 
-- 직원들의 이름(first_name), 성(last_name)과 연봉(salary)를 출력하시오
SELECT 
       e.FIRST_NAME, e.LAST_NAME, e.SALARY
  FROM EMPLOYEES e, JOBS j
  WHERE e.JOB_ID = j.JOB_ID AND e.SALARY BETWEEN 9000 AND 10000 AND j.JOB_TITLE = 'Sales Representative'
;
 

--7. 부서별로 가장 적은 급여를 받고 있는 직원의 이름, 부서이름, 급여를 출력하시오. 
--   이름은 last_name만 출력하며, 부서이름으로 오름차순 정렬하고, 
-- 부서가 같은 경우 이름을 기준 으로 오름차순 정렬하여 출력합니다. 
SELECT 
       E.LAST_NAME, A.*
  FROM EMPLOYEES E, 
      (
      SELECT 
             d.DEPARTMENT_NAME, MIN(e.SALARY) AS MIN_SALARY
        FROM EMPLOYEES e, DEPARTMENTS d 
       WHERE e.DEPARTMENT_ID = d.DEPARTMENT_ID 
       GROUP BY d.DEPARTMENT_NAME
      ) A 
 WHERE E.SALARY = A.MIN_SALARY
 ORDER BY A.DEPARTMENT_NAME ASC, E.LAST_NAME ASC
;
 

--8. EMPLOYEES 테이블에서 급여를 많이 받는 순서대로 조회했을 때 결과처럼 6번째부터 10 번째까지 
-- 5명의 last_name, first_name, salary를 조회하는 sql문장을 작성하시오.
SELECT 
       * 
  FROM
       (
       SELECT 
               RANK() OVER (ORDER BY TRUNC(SALARY, -1) DESC) AS RANKING, LAST_NAME, 
FIRST_NAME, TRUNC(SALARY, -1) AS SALARY
          FROM EMPLOYEES 
         ORDER BY SALARY DESC
       )
  WHERE RANKING 
  BETWEEN 6 AND 10
 ;
 

--9. 사원의 부서가 속한 도시(city)가 ‘Seattle’인 사원의 이름, 해당 사원의 매니저 이름, 사원 의 부서이름을 출력하시오. 
--   이때 사원의 매니저가 없을 경우 ‘<없음>’이라고 출력하시오. 이름은 last_name만 출력하며, 
-- 사원의 이름을 오름차순으로 정렬하시오. 
SELECT 
       E.E_NAME, NVL(E.M_NAME, '<없음>'), D.DEPARTMENT_NAME
  FROM 
      (
       SELECT 
              A.LAST_NAME AS E_NAME, B.LAST_NAME AS M_NAME, A.DEPARTMENT_ID 
         FROM EMPLOYEES A 
         LEFT JOIN EMPLOYEES B 
           ON A.MANAGER_ID = B.EMPLOYEE_ID
      ) E, DEPARTMENTS D, LOCATIONS L
 WHERE L.CITY = 'Seattle' AND E.DEPARTMENT_ID = D.DEPARTMENT_ID AND D.LOCATION_ID = L.LOCATION_ID
 ORDER BY E.E_NAME ASC
;  

 
--10. 각 업무(job) 별로 연봉(salary)의 총합을 구하고자 한다. 연봉 총합이 가장 높은 업무부터 
-- 업무명(job_title)과 연봉 총합을 조회하시오. 단 연봉총합이 30,000보다 큰 업무만 출력하시오. 
SELECT J.JOB_TITLE, SUM(E.SALARY)
  FROM JOBS J, EMPLOYEES E
 WHERE E.JOB_ID = J.JOB_ID
 GROUP BY J.JOB_TITLE
 HAVING SUM(E.SALARY) > 30000
 ORDER BY SUM(E.SALARY) DESC
;
 

--11. 각 사원(employee)에 대해서 사번(employee_id), 이름(first_name), 업무명(job_title), 
-- 부서 명(department_name)을 조회하시오. 
-- 단 도시명(city)이 ‘Seattle’인 지역(location)의 부서 (department)에 근무하는 직원을 사원번호 오름차순순으로 출력하시오.
SELECT 
       E.EMPLOYEE_ID, E.FIRST_NAME, J.JOB_TITLE, D.DEPARTMENT_NAME
  FROM EMPLOYEES E, DEPARTMENTS D, LOCATIONS L, JOBS J
 WHERE L.CITY = 'Seattle' AND J.JOB_ID = E.JOB_ID AND E.DEPARTMENT_ID = D.DEPARTMENT_ID 
AND D.LOCATION_ID = L.LOCATION_ID
 ORDER BY E.EMPLOYEE_ID ASC
;
 

--12. 2001~20003년사이에 입사한 직원의 이름(first_name), 입사일(hire_date), 관리자사번 (employee_id), 
-- 관리자 이름(fist_name)을 조회합니다. 단, 관리자가 없는 사원정보도 출력 결과에 포함시켜 출력한다.
SELECT 
       E.FIRST_NAME, TO_CHAR(E.HIRE_DATE, 'YYYY-MM-DD AM HH12:MI:SS') AS HIRE_DATE, E.MANAGER_ID, M.FIRST_NAME
  FROM EMPLOYEES E LEFT JOIN EMPLOYEES M ON
  E.MANAGER_ID = M.EMPLOYEE_ID WHERE TO_CHAR(E.HIRE_DATE, 'YYYY') BETWEEN '2001' AND '2003'
;
 

--13. ‘Sales’ 부서에 속한 직원의 이름(first_name), 급여(salary), 부서이름(department_name)을 조회하시오. 
--    단, 급여는 100번 부서의 평균보다 적게 받는 직원 정보만 출력되어야 한다. 
SELECT 
        E.FIRST_NAME, E.SALARY, D.DEPARTMENT_NAME 
  FROM EMPLOYEES E, DEPARTMENTS D
 WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID AND D.DEPARTMENT_NAME = 'Sales'
   AND E.SALARY < (
                   SELECT 
                          AVG(SALARY) 
                     FROM EMPLOYEES 
                    WHERE DEPARTMENT_ID = 100
                  )
 

--14. Employees 테이블에서 입사한달(hire_date)별로 인원수를 조회하시오.
SELECT 
       CONCAT(TO_CHAR(E.HIRE_DATE, 'MM'), '월') AS HIRE_DATE, COUNT(*)
  FROM EMPLOYEES E
  GROUP BY TO_CHAR(E.HIRE_DATE, 'MM')
  ORDER BY TO_CHAR(E.HIRE_DATE, 'MM') ASC
;  
  

--15. 부서별 직원들의 최대, 최소, 평균급여를 조회하되, 
-- 평균급여가 ‘IT’ 부서의 평균급여보다 많고, ‘Sales’ 부서의 평균보다 적은 부서 정보만 출력하시오. 
SELECT 
       D.DEPARTMENT_NAME, MAX(E.SALARY), MIN(E.SALARY), TRUNC(AVG(E.SALARY), 0)
  FROM EMPLOYEES E, DEPARTMENTS D
 WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID
 GROUP BY D.DEPARTMENT_NAME
HAVING TRUNC(AVG(E.SALARY), 0> (
                                  SELECT 
                                         TRUNC(AVG(E.SALARY), 0)
                                    FROM EMPLOYEES E, DEPARTMENTS D
                                   WHERE D.DEPARTMENT_NAME = 'IT' AND D.DEPARTMENT_ID = E.DEPARTMENT_ID
                                   )
   AND  TRUNC(AVG(E.SALARY), 0< (
                                   SELECT 
                                          TRUNC(AVG(E.SALARY), 0)
                                     FROM EMPLOYEES E, DEPARTMENTS D
                                    WHERE D.DEPARTMENT_NAME = 'Sales' AND D.DEPARTMENT_ID = E.DEPARTMENT_ID)
;

 
--16. 각 부서별로 직원이 한명만 있는 부서만 조회하시오. 
--    단, 직원이 없는 부서에 대해서는 ‘<신생부서>’라는 문자열이 출력되도록 하고,
--  출력결과는 다음과 같이 부서명이 내림차순 으로 정렬되어야한다. 
SELECT 
       NVL(D.DEPARTMENT_NAME, '<신생부서>') AS DEPARTMENT_NAME , COUNT(*)
  FROM EMPLOYEES E LEFT JOIN DEPARTMENTS D
  ON E.DEPARTMENT_ID = D.DEPARTMENT_ID
 GROUP BY D.DEPARTMENT_NAME
HAVING COUNT(*= 1
 ORDER BY D.DEPARTMENT_NAME DESC
;
 

--17. 부서별 입사월별 직원수를 출력하시오. 
--    단, 직원수가 5명 이상인 부서만 출력되어야 하며 출력결과는 부서이름 순으로 한다.
SELECT 
       D.DEPARTMENT_NAME, TO_CHAR(E.HIRE_DATE, 'MON''NLS_DATE_LANGUAGE=ENGLISH') AS HIRE_DATE, COUNT(*)
  FROM DEPARTMENTS D, EMPLOYEES E
 WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID 
 GROUP BY D.DEPARTMENT_NAME, TO_CHAR(E.HIRE_DATE, 'MON''NLS_DATE_LANGUAGE=ENGLISH')
HAVING COUNT (*>= 5
 ORDER BY D.DEPARTMENT_NAME ASC;
 

--18. 국가(country_name) 별 도시(city)별 직원수를 조회하시오. 
--    단, 부서에 속해있지 않은 직원 이 있기 때문에 106명의 직원만 출력이 된다. 
--    부서정보가 없는 직원은 국가명과 도시명 대신에 ‘<부서없음>’이 출력되도록 하여 107명 모두 출력되게 한다.
SELECT 
       NVL(C.COUNTRY_NAME, '<부서없음>') AS COUNTRY_NAME, NVL(L.CITY, '<부서없음>') AS CITY, COUNT(*)
  FROM EMPLOYEES E LEFT JOIN DEPARTMENTS D ON E.DEPARTMENT_ID = D.DEPARTMENT_ID 
                   LEFT JOIN LOCATIONS L ON D.LOCATION_ID = L.LOCATION_ID
                   LEFT JOIN COUNTRIES C ON L.COUNTRY_ID = C.COUNTRY_ID 
 GROUP BY COUNTRY_NAME, CITY
 ORDER BY COUNTRY_NAME ASC, CITY ASC
;  

 
--19. 각 부서별 최대 급여자의 아이디(employee_id), 이름(first_name), 급여(salary)를 출력하시오. 
--    단, 최대 급여자가 속한 부서의 평균급여를 마지막으로 출력하여 평균급여와 비교할 수 있게 할 것.
SELECT 
       E.EMPLOYEE_ID, E.FIRST_NAME, A.SALARY, A.AVG
  FROM 
       EMPLOYEES E, (
                      SELECT 
                             E.DEPARTMENT_ID, MAX(E.SALARY) AS SALARY, TRUNC(AVG(E.SALARY),2) AS AVG
                        FROM 
                             EMPLOYEES E, DEPARTMENTS D
                       WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID
                       GROUP BY E.DEPARTMENT_ID
                    ) A
 WHERE E.SALARY = A.SALARY AND E.DEPARTMENT_ID = A.DEPARTMENT_ID
 ORDER BY E.EMPLOYEE_ID ASC
;
 

--20. 커미션(commission_pct)별 직원수를 조회하시오. 
--    커미션은 아래실행결과처럼 0.2, 0.25는 모두 .2로, 0.3, 0.35는 .3 형태로 출력되어야 한다. 
--    단, 커미션 정보가 없는 직원들도 있는 데 커미션이 없는 직원 그룹은 ‘<커미션 없음>’이 출력되게 한다.
SELECT 
       NVL(TO_CHAR(TRUNC(E.COMMISSION_PCT,1)), '<커미션없음>') AS COMMISSION, COUNT(*)
  FROM 
       EMPLOYEES E 
 GROUP BY NVL(TO_CHAR(TRUNC(E.COMMISSION_PCT,1)), '<커미션없음>')
 ORDER BY NVL(TO_CHAR(TRUNC(E.COMMISSION_PCT,1)), '<커미션없음>') DESC
;
 

--21. 커미션(commission_pct)을 가장 많이 받은 상위 4명의 부서명(department_name), 
-- 직원명 (first_name), 급여(salary), 커미션(commission_pct) 정보를 조회하시오. 
--    출력결과는 커미션 을 많이 받는 순서로 출력하되 동일한 커미션에 대해서는 급여가 높은 직원이 먼저 출력 되게 한다.
SELECT 
       * 
  FROM
       (
        SELECT 
               D.DEPARTMENT_NAME, E.FIRST_NAME, E.SALARY, E.COMMISSION_PCT
          FROM 
               EMPLOYEES E, DEPARTMENTS D
         WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID
         ORDER BY E.COMMISSION_PCT DESC NULLS LAST, E.SALARY DESC
       )
 WHERE ROWNUM <= 4
;

cs


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

오라클 페이징 처리 쿼리  (0) 2018.03.20

+ Recent posts