전문가칼럼

DBMS, DB 구축 절차, 빅데이터 기술 칼럼, 사례연구 및 세미나 자료를 소개합니다.

오라클 랜덤 함수와 사용자 정의 함수

전문가칼럼
DBMS별 분류
Oracle
작성자
dataonair
작성일
2015-12-29 00:00
조회
13124




◎ 연재기사 ◎


물탱크 구조로 알아본 오라클의 블록 옵션 ‘PCTFREE와 PCTUSED’


이산가족 찾기 생방송을 통해 배우는 DB 원리


개발자에게 맞는 DB 공부방법 찾기: 물리적 분류와 논리적 분류 그리고 인덱스


데이터베이스 인덱스의 오해와 진실


쉬운 것이 올바른 것이다. ‘인덱스 끝장리뷰’ (상)


쉬운 것이 올바른 것이다. ‘인덱스 끝장리뷰’ (하)


누구도 알려주지 않았던 ‘오라클 인덱스 생성도’의 비밀


누구도 알려주지 않았던 ‘오라클 쿼리 작성의 비법’


퀴리 최적화 및 튜닝을 위한 오라클 공정쿼리 작성법


만능 쿼리와 한 방 쿼리


오라클 옵티마이저 ‘CBO와 RBO’ 이해하기


재미있는 DB 이야기 ‘60갑자와 쿼리’


그림으로 배우는 ‘오라클 조인의 방식’ 이야기


반드시 알아야 하는 오라클 힌트절 7가지


오라클 플랜을 보는 법


개발자들의 영원한 숙제 ‘NULL 이야기’


알면 유용한 오라클 기능 ‘GATHER_PLAN_STATISTICS’


알면 유용한 오라클 기능들


오라클 DICTIONARY를 활용한 DB툴 프로그램 ‘FreeSQL’


이제는 말할 수 있다: 주식 자동매매 프로그램(상)


이제는 말할 수 있다: 주식 자동매매 프로그램(하)


개발자들이 자주 접하는 오라클 에러 메세지


재미있는 DB 이야기 ‘사라진 날짜를 찾아라’


오라클 랜덤 함수와 사용자 정의 함수


그림으로 배우는 ‘공정쿼리와 인덱스 생성도’


이병국의 개발자를 위한 DB 이야기: 디폴트 세팅의 함정과 오라클 파라미터


재미있는 DB 이야기 ‘놀라운 마방진의 세계’


오라클 운반 최소 단위 BLOCK


이병국의 개발자를 위한 DB 이야기: 이세돌과 알파고의 세기의 대결


이병국의 개발자를 위한 DB 이야기(30회) : DB 엔지니어의 가볍게 읽는 세상 이야기


이병국의 개발자를 위한 DB 이야기: 튜닝(31회) : 개발자를 위한 DB 튜닝 실전(1편)


이병국의 개발자를 위한 DB 이야기: 튜닝(32회) : 개발자를 위한 튜닝 실전(2편)


이병국의 개발자를 위한 DB 이야기: 튜닝(33회) : 개발자를 위한 튜닝 실전(3편)


이병국의 개발자를 위한 DB 이야기: 튜닝(34회) : 개발자를 위한 DB 튜닝 실전(4편)


이병국의 개발자를 위한 DB 이야기: 튜닝(35회) : 개발자를 위한 튜닝 실전(5편)


이병국의 개발자를 위한 DB 이야기: 페이징 처리에 대한 이해 (36회)


보기 좋은 떡이 먹기도 좋다 - 좋은 쿼리 좋은 성능


테이블의 수직분할과 수평분할에 대한 이해


DB 성능 제고를 위한 채번의 이해와 방식별 장단점 비교


이병국의 개발자를 위한 DB 이야기: 마지막회 : ‘개발자를 위한 DB 이야기’ 연재를 마치며



이병국의 개발자를 위한 DB 이야기: 함수(24회)

오라클 랜덤 함수와 사용자 정의 함수



성공과 실패의 경험을 나누자, 용기와 희망을 나누자

개발업무를 시작으로 IT계에 입문했던 필자가 10년 가까이 DB엔지니어로서 활동하면서 얻은 경험과 지식을나누고자 한다. DB를 자주 접하는 SW 개발자뿐 아니라, DB 전문가를 꿈꾸는 대학생에서DB 분야에 입문한지 1~2년 된 기입문자가 쉽게 이해할 수 있도록 비유를 통해 쉽게 접근해볼 계획이다. 물론 전문가들이라도 다시 한번 개념을 정립하는 의미에서 필요한 내용이 될 수 있다.

전체적으로 DB의 기본 원리와 개념을 이해하고 테이블, 인덱스, 쿼리, 튜닝, 플랜 등 개발자들이 알아야 하는 DB 전분야에 대해 쉽게 이해하도록 설명하겠다. DB 기술서적이나 번역서보다는 조금 더 부드럽게 접근할 계획이다. 그렇다고 흔히 서점에서 만날 수 있는 개발자 위주의 SQL 소개서도 아니다. 이 연재는 시리즈로 나갈 것이다. 연재를 끝까지 읽는 독자라면 준전문가 수준의 DB 원리를 아는 것을 목표로 한다.



22회 연재 문제 이벤트에 대한 고지

지난 22회 연재에서 출제한 문제에 대한 정확한 답을 보내 주신 분은 아무도 없었다. 정답을 가장 먼저 보내 주신 분께 소정의 선물을 드린다고 했으나 당첨자가 없어서 무척 아쉽다. 선물이 무엇이냐는 질문을 하신 분이 있었는데, 서태지 LP판이었다. 혹시 LP 턴테이블이 없어서 필요 없다고 한다면, 샤오미 휴대폰 보조 배터리를 드리려고 했다.

그때 출제한 문제는 ‘오라클에서 제공하는 날짜 함수를 사용하지 않고, 요일을 구하는 쿼리 작성’ 이었는데 사실 좀 어려운 문제였다. 윤년에 대한 이해와 그레고리력의 역사적 사실을 정확히 알아야만 풀 수 있는 내용이었다. 필자도 정답을 완벽하게 알고 있는 상태에서 출제한 문제가 아니었기에 정답을 도출해 나가는 풀이 과정을 적은 이번 연재에서 많은 고통이 따랐다.

조만간 이러한 이벤트를 다시 진행 할 때는 정답자가 없을 경우에도 가장 유사한 답을 주신 분께 선물을 드리도록 하겠다. 많은 참여를 기대해 본다.



오라클 랜덤 패키지 DBMS_RANDOM

오라클이 제공하는 DBMS_RANDOM 패키지는 랜덤값을 제공하는 함수 기능을 포함하고 있다. 이 패키지는 오라클 8.0버전 이상부터 지원했는데 그 사용 분야는 다양하고 폭넓다. 주로 아래와 같은 경우에 주로 사용한다.

- 이벤트 당첨에서 당첨자를 램덤하게 추출할 수 있다.
- 로그인 화면에서 자동 가입 방지를 위한 숫자와 문자의 조합을 랜덤하게 추출할 수 있다.
- 자격증 관련 시험은행에서 카테고리별 및 가중치별로 랜덤하게 시험 문제를 추출할 수 있다.
- 윈도우 운영체제의 기본 제공 게임인 지뢰찾기의 지뢰판을 랜덤하게 추출할 수 있다.
- 포털 사이트의 메인 화면에서 제공하는 각종 콘텐츠를 랜덤하게 추출할 수 잇다.
- 쇼핑몰에서 물품 구매시 SMS 인증에 사용하는 번호를 랜덤하게 추출할 수 있다.
- 기타 여러 분야에서 다양한 방법으로 랜덤값을 추출하는 데 사용된다.

가장 기본적인 예시인 1~10 사이의 값을 추출하는 방법을 살펴보자.



SELECT DBMS_RANDOM.VALUE(1, 10) FROM DUAL
================================
3.56757192841058651735473361019736900258
------------------------------------------------------

소수점 이하 값을 포함하는 1에서 10사이의 값을 리턴한다. 물론 실행할 때마다 다른 값을 리턴 할 것이다. 그렇다면 쇼핑몰에서 물품 구매 시 SMS 인증에 사용하는 6자리 번호를 추출하는 예제를 살펴보자.



SELECT ROUND(DBMS_RANDOM.VALUE(100000, 999999), 0) FROM DUAL
================================
731132
------------------------------------------------------

100000~999999 사이의 값을 리턴 하는데 ROUND 함수를 사용해 소수점 이하 값을 제외한 6자리 숫자를 랜덤하게 리턴함을 알 수 있다.

DBMS_RANDOM.VALUE 함수를 이용하여 랜덤 숫자를 구하였다. 그렇다면 랜덤 문자를 구하기 위해서는 어떤 함수를 써야 할까 바로 DBMS_RANDOM.STRING이다.

SELECT DBMS_RANDOM.STRING('U', 10) FROM DUAL -- 대문자 10자리
SELECT DBMS_RANDOM.STRING('L', 10) FROM DUAL -- 소문자 10자리
SELECT DBMS_RANDOM.STRING('A', 10) FROM DUAL -- 대소문자 10자리

로그인 화면에서 자동 가입 방지를 위한 숫자와 문자 조합 10자리를 추출 하기 위해서는 아래와 같은 형식으로 함수를 사용하면 된다.

SELECT DBMS_RANDOM.STRING('X', 10) FROM DUAL -- 대문자 및 숫자 10자리

그 외에 특수 문자도 포함하는 랜덤 문자를 추출하기 위해서는 아래와 같이 사용한다.

SELECT DBMS_RANDOM.STRING('P', 10) FROM DUAL -- 대소문자 및 특수문자

이벤트 참가 대상자 중에서 1등 당첨자 1명, 2등 당첨자 10명, 3등 당첨자 100명을 추첨하는 쿼리는 다음과 같이 작성할 수 있다.



SELECT 참가자ID, 참가자명,
CASE WHEN 순위 BETWEEN 1 AND 1 THEN '1등'
WHEN 순위 BETWEEN 2 AND 11 THEN '2등'
WHEN 순위 BETWEEN 12 AND 111 THEN '3등' END AS 당첨자
FROM
(
SELECT 참가자ID, 참가자명,
ROW_NUMBER() OVER (ORDER BY DBMS_RANDOM.VALUE) AS 순위
FROM 이벤트참가대상자
)
ORDER BY 순위

윈도우 운영체제의 기본 제공 게임인 지뢰찾기의 지뢰판을 랜덤하게 구성하는 쿼리도 아래와 같이 만들 수 있다. 지뢰판은 5행 5열이고 지뢰는 10개인 경우다.



WITH 지뢰판 AS
(
SELECT 행,열,
CASE WHEN ROW_NUMBER() OVER (ORDER BY DBMS_RANDOM.VALUE) < = 10 THEN
'*' ELSE '' END AS 지뢰
FROM (SELECT LEVEL 행 FROM DUAL CONNECT BY LEVEL < = 5)
, (SELECT LEVEL 열 FROM DUAL CONNECT BY LEVEL < = 5)
)
SELECT MAX(DECODE(열, 1, 지뢰)) AS 열1
, MAX(DECODE(열, 2, 지뢰)) AS 열2
, MAX(DECODE(열, 3, 지뢰)) AS 열3
, MAX(DECODE(열, 4, 지뢰)) AS 열4
, MAX(DECODE(열, 5, 지뢰)) AS 열5
FROM 지뢰판
GROUP BY 행
ORDER BY 행

문자열을 역순으로 리턴 하는 오라클 REVERSE 함수

오라클에서 제공하는 함수 중에는 문자열을 역순으로 리턴 하는 함수가 있다.



SELECT REVERSE('ABCDEFGHIJKLMNOPQRSTUVWXYZ') FROM DUAL
================================
ZYXWVUTSRQPONMLKJIHGFEDCBA
------------------------------------------------------

그렇다면 아래와 같은 경우도 가능할까

SELECT REVERSE('12345') FROM DUAL -- 문자형인 경우 역순으로 리턴
SELECT REVERSE(12345) FROM DUAL -- 숫자형인 경우 오라클 에러 발생

문자형인 경우는 정상적으로 리턴 하지만 숫자형인 경우 오라클 에러가 발생함을 확인할 수 있다. 그렇다면 아래와 같이 한글이나 한글 자모인 경우도 살펴보자.

SELECT REVERSE(‘대한민국만세’) FROM DUAL -- 한글인 경우 오라클 에러 발생
SELECT REVERSE(‘ㄷㅎㅁㄱㅁㅅ’) FROM DUAL -- 한글자모인 경우 오라클 에러 발생

한글이나 한글 자모인 경우에는 에러가 발생함을 확인 할 수 있다. 결국 오라클에서 기본적으로 제공하는 내장 함수인 REVERSE 함수는 한글을 제외한 문자형에서만 역순으로 변환 가능함을 알 수 있다. MAX 함수인 경우에는 문자형, 숫자형, 날짜형 모두 가능하지만 REVERSE 함수는 다름을 알 수 있다. 그렇다면 한글인 경우 역순의 문자열을 리턴 받으려면 어떻게 해야 하나 바로 사용자가 직접 함수를 만들어야 한다. 이와 같은 함수를 사용자 정의 함수라고 한다.



사용자 정의 함수에 대한 이해

오라클 내장 함수는 오라클에서 자체적으로 제공하는 함수이다. 반면에 사용자가 필요에 따라 직접 만든 함수는 사용자 정의 함수라 한다. REVERSE 함수는 오라클에서는 기본적으로 제공하지만 DB2에서는 제공하지 않는다. 반면에 ISNUMERIC 함수는 MS SQL Server에서는 제공하지만 오라클에서는 제공하지 않는다. 이와 같이 기본적으로 제공하지 않는 함수는 필요에 의해서 개발자 혹은 DBA가 직접 만들어야 한다.

우리가 사용하는 DB 종류는 많다. 지금 사용하는 DB에서 지원하는 함수가 다른 DB에서는 지원하지 않을 수도 있다. 또한 그 반대인 경우도 있을 것이다. 기본적으로 제공하지는 않지만 꼭 필요한 함수라면, 개발자가 스스로 만들 수 있어야 한다. 그리고 DBA에게 생성 요청을 하여야 한다. 솔직히 개발자가 새로운 함수의 생성을 요청해도 DBA가 부담감 없이 생성해 줄지는 미지수다. 왜냐하면 관리해야 하는 자원이 늘어나는 것을 어떤 DBA도 좋아하지 않기 때문이다.

사용자 정의 함수는 호출 시 별도의 실행 엔진에서 구동된다고 한다. 곧 부하가 있다는 얘기다. DB를 안정적으로 유지-관리해야 하는 DBA 입장에선 조심스러울 수밖에 없다. 개발자들은 DBA에게 사용자 정의 함수가 반드시 필요한 이유를 명확히 제시할 필요가 있다. 그것은 개발자의 몫이다.



사용자 정의 함수 ISNUMERIC

간단한 사용자 정의 함수를 만들어 보자. MS-SQL에서는 ISNUMERIC 함수가 있다. 숫자이면 1을 리턴하고 아니면 0을 리턴하는 함수다. 오라클에서는 제공하지 않는 함수이므로 개발자가 사용자 정의 함수로 직접 만들어야 한다.



CREATE OR REPLACE FUNCTION ISNUMERIC (P_NUM IN VARCHAR2) RETURN NUMBER
AS
V_NUM NUMBER;
BEGIN
V_NUM := TO_NUMBER(P_NUM);
RETURN 1;
EXCEPTION
WHEN OTHERS THEN
RETURN 0;
END;

사용자 정의 함수를 생성하지 않고 기존 함수 중에서 TRANSLATE 함수를 이용하는 방법도 고려해 볼 만하다. 아래 예시와 같이 사용하면 ISNUMERIC 함수와 동일한 결과를 얻을 수 있다.

SELECT NVL2(LENGTH(TRANSLATE('123ABC', '+-.0123456789', ' ')), 0, 1) FROM DUAL

이번 연재에서는 오라클에서 제공하는 랜덤 함수에 대해서 주로 설명하였다. 흔히 접하는 함수는 아니지만 여러 분야에서 요긴하게 사용할 수 있다. 또한 사용자 정의 함수에 대해서도 설명했다. DB에서 기본적으로 제공하지 않아서 사용자가 직접 만들어서 사용하는 함수다. 필자는 예전에 필요한 함수를 수십 개 정도 미리 만들어서 사용하였는데 서로 다른 DB 환경에서 지원하지 않는 함수가 있는 경우에 요긴하게 활용했다.

또한 내장 함수를 사용하면서 간혹 이건 어떻게 만들었을까 궁금증을 가지곤 하였는데, 그러한 궁금증이 함수에 대한 이해를 높이는 계기가 되기도 했다. 지금도 스스로에게 그러한 노력이 필요하다고 생각한다. 지금 편하게 사용하는 함수가 다른 DB 에서도 지원하는지 알 수 없기 때문이다.

다음 연재의 내용은 공정쿼리와 인덱스 생성도에 관한 것이다. 예전 연재에서 이미 한번씩 언급한 내용이지만, 많은 분들이 재차 궁금한 점을 물어 오기도 하고 많은 관심을 보여 주었던 내용이었다. 따라서 이번에는 그전 연재의 내용에서 빠진 부분을 추가하고 내용을 보완해 보다 더 자세하고 쉽게 설명할 것이다.



[지난 문제의 정답과 풀이] 원리를 이해하고 논리로 풀어가는, 쉬어가는 DB 문제

지난 연재에 출제한 ‘원리를 이해하고 논리로 풀어가는, 쉬어가는 DB 문제’에 대한 정답과 해설은 아래와 같다. 문제를 풀면서 DB 원리를 하나씩 배우고 이해할 수 있다.



column_img_2273.jpg

해설 가로와 세로의 크기가 5 x 5이고 영어 단어 길이가 4의 HOPE인 경우에 대해 살펴보자. 아래 그림과 같이 알파벳판과 단어판을 결합하면 우리가 원하는 결과를 얻게 된다. column_img_2274.jpg

알파벳판은 아래와 같이 쉽게 구현할 수 있다.



WITH 알파벳판 AS
(
SELECT 행, 열,
SUBSTR('ABCDEFGHIJKLMNOPQRSTUVWXYZ',ROUND(DBMS_RANDOM.VALUE(1,26)),1) AS 철자
FROM (SELECT LEVEL AS 행 FROM DUAL CONNECT BY LEVEL < = 5)
, (SELECT LEVEL AS 열 FROM DUAL CONNECT BY LEVEL < = 5)
)
SELECT MAX(DECODE(열, 1, 철자)) AS 열1
, MAX(DECODE(열, 2, 철자)) AS 열2
, MAX(DECODE(열, 3, 철자)) AS 열3
, MAX(DECODE(열, 4, 철자)) AS 열4
, MAX(DECODE(열, 5, 철자)) AS 열5
FROM 알파벳판
GROUP BY 행
ORDER BY 행

반면에 단어판의 구성은 의외로 쉽지가 않다. 단어의 길이에 따라서 시작점의 위치에 대한 가능 여부가 결정되기 때문이다. 또한 가로, 세로, 대각선에 대한 가능 여부도 판단 되어야 한다. 이 모든 것에 대한 선택도 랜덤하게 이루어져야 하기 때문이다.

단어판을 구성하기 전에 아래 방향표 그림을 살펴 보면, 8개 방향에 대한 고유한 번호 및 값이 부여돼 있다. 또한 방향에 따른 행과 열의 증감 값이 설정 되어 있다. 만약 동남쪽 방향이면 행과 열은 각각 1씩 증가 해야 하며 서북쪽 방향이면 행과 열은 각각 1씩 감소해야 한다.

column_img_2275.jpg

위 방향도 그림의 (4,4) 위치에서는 HOPE 단어를 나열할 수 있는 방향은 북쪽, 서북쪽, 서쪽 3가지만 가능함을 알 수 있다. 이와 같이 우리는 다른 모든 좌표에서도 단어를 나열할 수 있는 방향을 구할 수 있다. 아래 [그림 5]는 각각의 좌표에서 단어 배치가 가능한 방향의 번호를 문자열로 결합시킨 것이며, [그림 6]은 각각의 좌표에서 단어 배치가 가능한 방향의 값을 합한 값이다. 쿼리 구현에는 두 가지 경우가 모두 사용 가능한데 필자는 [그림 5]의 경우로 쿼리를 작성했다.



column_img_2276.jpg

정답
-- 알파벳판 + (단어판 + 방향판)
SELECT MAX(DECODE(X.열, 1, DECODE(Y.철자, NULL, X.철자, Y.철자))) AS 열1
, MAX(DECODE(X.열, 2, DECODE(Y.철자, NULL, X.철자, Y.철자))) AS 열2
, MAX(DECODE(X.열, 3, DECODE(Y.철자, NULL, X.철자, Y.철자))) AS 열3
, MAX(DECODE(X.열, 4, DECODE(Y.철자, NULL, X.철자, Y.철자))) AS 열4
, MAX(DECODE(X.열, 5, DECODE(Y.철자, NULL, X.철자, Y.철자))) AS 열5
FROM
(
-- 알파벳판
SELECT 행, 열,
SUBSTR('ABCDEFGHIJKLMNOPQRSTUVWXYZ',ROUND(DBMS_RANDOM.VALUE(1,26)),1) AS 철자
FROM (SELECT LEVEL AS 행 FROM DUAL CONNECT BY LEVEL < = 5)
, (SELECT LEVEL AS 열 FROM DUAL CONNECT BY LEVEL < = 5)
) X,
(
-- 단어판 + 방향판
SELECT A.방향, A.행 + B.행 AS 행, A.열 + B.열 AS 열, A.철자
FROM
(
-- 단어판
SELECT 방향, 행, 열, 철자
FROM
(
SELECT '1' AS 방향, 0 AS 행, LEVEL-1 AS 열, SUBSTR('HOPE', LEVEL, 1)
AS 철자 FROM DUAL CONNECT BY LEVEL < = 4 UNION ALL -- 동
SELECT '2' AS 방향, 0 AS 행, -LEVEL+1 AS 열, SUBSTR('HOPE', LEVEL, 1)
AS 철자 FROM DUAL CONNECT BY LEVEL < = 4 UNION ALL -- 서
SELECT '3' AS 방향, LEVEL-1 AS 행, 0 AS 열, SUBSTR('HOPE', LEVEL, 1)
AS 철자 FROM DUAL CONNECT BY LEVEL < = 4 UNION ALL -- 남
SELECT '4' AS 방향, -LEVEL+1 AS 행, 0 AS 열, SUBSTR('HOPE', LEVEL, 1)
AS 철자 FROM DUAL CONNECT BY LEVEL < = 4 UNION ALL -- 북
SELECT '5' AS 방향, LEVEL-1 AS 행, LEVEL-1 AS 열, SUBSTR('HOPE', LEVEL, 1)
AS 철자 FROM DUAL CONNECT BY LEVEL < = 4 UNION ALL -- 동남
SELECT '6' AS 방향, -LEVEL+1 AS 행, -LEVEL+1 AS 열, SUBSTR('HOPE', LEVEL, 1)
AS 철자 FROM DUAL CONNECT BY LEVEL < = 4 UNION ALL -- 서북
SELECT '7' AS 방향, LEVEL-1 AS 행, -LEVEL+1 AS 열, SUBSTR('HOPE', LEVEL, 1)
AS 철자 FROM DUAL CONNECT BY LEVEL < = 4 UNION ALL -- 남서
SELECT '8' AS 방향, -LEVEL+1 AS 행, LEVEL-1 AS 열, SUBSTR('HOPE', LEVEL, 1)
AS 철자 FROM DUAL CONNECT BY LEVEL < = 4 -- 북동
)
) A,
(
-- 방향판
SELECT 행, 열, 방향리스트, 방향, 선택
FROM
(
SELECT 행, 열, 방향리스트
, SUBSTR(방향리스트,ROUND(DBMS_RANDOM.VALUE(1,LENGTH(방향리스트))),1) 방향
, CASE WHEN ROW_NUMBER() OVER (ORDER BY DBMS_RANDOM.VALUE) < = 1 THEN
'Y' END AS 선택
FROM
(
SELECT 행, 열
, CASE WHEN 5-열+1 >= 길이 THEN '1' END -- 동
|| CASE WHEN 5-(5-열) >= 길이 THEN '2' END -- 서
|| CASE WHEN 5-행+1 >= 길이 THEN '3' END -- 남
|| CASE WHEN 5-(5-행) >= 길이 THEN '4' END -- 북
|| CASE WHEN 5-열+1 >= 길이 AND 5-행+1 >= 길이 THEN '5' END -- 동남
|| CASE WHEN 5-(5-열) >= 길이 AND 5-(5-행) >= 길이 THEN '6' END -- 서북
|| CASE WHEN 5-(5-열) >= 길이 AND 5-행+1 >= 길이 THEN '7' END -- 남서
|| CASE WHEN 5-열+1 >= 길이 AND 5-(5-행) >= 길이 THEN '8' END -- 북동
AS 방향리스트
FROM (SELECT LEVEL AS 행 FROM DUAL CONNECT BY LEVEL < = 5) -- 행크기
, (SELECT LEVEL AS 열 FROM DUAL CONNECT BY LEVEL < = 5) -- 열크기
, (SELECT LENGTH('HOPE') AS 길이 FROM DUAL) -- 단어길이
)
WHERE 방향리스트 > 0
ORDER BY 행, 열
)
WHERE 선택 = 'Y'
) B
WHERE A.방향 = B.방향
) Y
WHERE X.행 = Y.행(+)
AND X.열 = Y.열(+)
GROUP BY X.행
ORDER BY X.행

[이번 호 문제] 원리를 이해하고 논리로 풀어가는, 쉬어가는 DB 문제

각 연재의 말미에 간단하면서도 재미있고 생각해 보는 문제를 출제하려 한다. 모든 문제는 DB의 원리를 이해할 수 있는 문제로 출제할 예정이다. 문제를 풀면서 DB 원리를 하나씩 배우고 이해할 수 있다. 정답과 그에 대한 설명은 다음 연재에서 한다. column_img_2277.jpg