EXP-00091 먹고살기/Oracle 2011. 7. 8. 08:12

EXP-00091: Exporting questionable statistics.
Export terminated successfully with warnings.
questionable statistics 란?
1. exp 받는 동안 row error가 있는 경우
2. client char set이나 nchar char set이 server char set이나 nchar char set
과 맞지 않는 경우
3. exp시 query 옵션이 사용된 경우
4. partitions, subpartions만 exp 받는 경우

위의 4가지 경우인 경우 위의 warning 이 나타납니다.
위의 4가지인 경우 기존의 통계정보와 달라질 수 있기 때문에 recalculate가 필요합니다.
oracle 9버전부터 export시 default로 기존의 통계정보를 export받는데
export 받기 전 정상적으로 analyze가 되지 않았다면 위에 해당하는 에러가 발생하게 됩니다.

answer1>
통계정보를 무시하고 export 할려고 한다면..옵션절에 statistics = none 로 써
주시고 export받으면 됩니다.
answer2>
imp받으실때 statistics=safe로 받으면 됩니다.
여러 exp 파일이 있는 경우 저 warning이 났는지 안났는지 모르기때문에 safe 옵션을 쓰면 재계산이 필요한 경우는 해주고 안필요하면 안하고 넘어가게 됩니다.

[출처] EXP-00091|작성자 소나무

'먹고살기 > Oracle' 카테고리의 다른 글

[오라클] SQL - UNION에 관한 SQL 규칙  (0) 2011.07.19
ORACLE ROWNUM 활용  (0) 2011.07.08
[Oracle] distinct, rowid 중복 제거, 최신 데이터 하나만 가져오기  (1) 2011.06.30
Sysdate  (0) 2011.06.02
SQL _ HAVING  (0) 2011.04.29

select distinct field1

from tb_test

이렇게 하면 field1에 있는 데이터 중 중복을 제거하고 유니크 한 값들만 나온다.

그러나 시간 개념이 들어가서 최신의 데이터에 해당하는 row의 값을 다 가져 오고 싶다면?

distinct에 시간까지 걸면 모든 데이터가 다 유니크 해버린다.

oracle db 데이터 중 특정 필드의 중복을 제거하고 최신의 데이터 1개만 가져오기.

숨어 있던 rowid가 이때 도움을 준다.

select *

from tb_test

where reg_tm between start_tm and end_tm

and rowid in (select max(rowid) from tb_test group by field1)

중복이 되면 안되는 필드를 group by 해서 rowid를 큰 것 순으로 뽑아내면 된다.

...라고 썼는데, 생각해보니.. scan 범위를 더 줄일 수 있을 것 같다.

물론 이건 환경과 쓰는 사람 마음에 따라 다르다. 내가 찾은 예제에선 저렇게 되어 있었고..

나는 시간 범위 내에서 중복된 값 중 최신의 것만 찾아내면 되니까.

select *

from tb_test

where rowid in (select max(rowid) from tb_test where reg_tm between start_tm and end_tm group by field1)

요렇게 작성하면 스캔 범위가 줄어들어 위의 쿼리보단 성능향상에 도움이 될 수 있을 것 같다.

ps. 스크랩 하시는 분들이 많아져서 추가 사실을 덧붙입니다.

이 구문은 rowid가 숫자일 경우에만 유효합니다


'먹고살기 > Oracle' 카테고리의 다른 글

ORACLE ROWNUM 활용  (0) 2011.07.08
EXP-00091  (0) 2011.07.08
Sysdate  (0) 2011.06.02
SQL _ HAVING  (0) 2011.04.29
SQL _ 상관서브쿼리  (0) 2011.04.29
Sysdate 먹고살기/Oracle 2011. 6. 2. 09:17

1. 10분에 한번씩 실행하는 경우
sysdate + 1/24/6 또는 sysdate + 1/144
-> 1/24 (1시간-60분) / 6 : 10분 단위
1/144 : 24*6 으로 나누어도 같은 의미가 된다.
2. 1분에 한번으로 지정하는 경우
sysdate + 1/24/60 또는 sysdate + 1/1440
3. 매일 새벽 2시로 지정하는 경우
trunc(sysdate) + 1 + 2/24 -> 다음날 새벽 2시를 지정함.
4. 매일 밤 11시로 지정하는 경우
trunc(sysdate) + 23/24 -> 오늘 밤 11시를 지정했음.
현재 job 이 있는지 없는지는 user_jobs 뷰를 보시면 됩니다.

5분전 Sysdate - 1/24/12
10분전 Sysdate - 1/24/6 

'먹고살기 > Oracle' 카테고리의 다른 글

EXP-00091  (0) 2011.07.08
[Oracle] distinct, rowid 중복 제거, 최신 데이터 하나만 가져오기  (1) 2011.06.30
SQL _ HAVING  (0) 2011.04.29
SQL _ 상관서브쿼리  (0) 2011.04.29
SQL _ HAVING_2  (0) 2011.04.29
SQL _ HAVING 먹고살기/Oracle 2011. 4. 29. 16:34

1.데이터의 빠진 부분 찾기

SeqTbl

seq

name

1

마이크

2

제인

3

데이브

5

조안

6

메리

8

위와 같은 일련번호를 가진 테이블이 있다고 하자. 그런데 일련번호가 있다고 해도, 번호가 연속적이지 못하다. 4와 7이 빠져있다. 이 테이블에서 데이터가 빠져있는지를 확인해 보는 SQL을 만들어보자. 만약 이 테이블이 파일이고 절차적언어를 이용한다면 다음과 같은 순서로 해결할 것이다.

1.일련번호를 정렬시킨다.

2.루프해서 한행씩 다음행과 번호를 비교한다.

이런 간단한 순서 안에서도 절차적언어와 파일 시스템의 특징을 알 수 있다. 파일의 레코드는 순서를 가지고 있고, 언어는 이를 정렬시킨다는 것이다. 하지만 테이블의 행은 순서를 가지고 있지 않고 SQL도 정렬 연산자를 가지고 있지 않다는 것이다.(ORDER BY는 SQL의 연산자가 아니다)대신 SQL은 복수행을 하나의 집합으로 취급한다. 테이블 전체를 하나의 집합으로 본다면 다음과 같은 SQL문을 만들 수 있을 것이다.

SELECT'결함있음'ASgap
FROMSeqTbl HAVINGCOUNT(*) <> MAX(seq);

gap ------------- '결함있음' 

COUNT(*)의 행수와 번호의 최대값이 같다면 처음부터 끝까지 빠짐없이 카운트되었다는 의미이다.

그런데 이 SQL문에는 GROUP BY구가 없다. 이런 경우, 테이블 전체가 한행으로 집약되어진다. 이럴 때도 HAVING구는 문제없이 사용가능하다. 현재의 표준 SQL에서는 HAVING구를 단독으로 쓸 수 있다. 단, SELECT구에 원테이블의 열을 참조할 수 없기 때문에 위의 문제처럼 정수를 지정하든지, 「SELECT COUNT(*)」처럼 집약함수를 쓸 필요가 있다.

2. HAVING구로 서브쿼리:최빈치를 구하기

아래와 같은 연봉을 나타내는 졸업생 테이블이 있다. 이 학교의 평균연봉을 계산하면 55000달러이지만 이는 샘슨의 연봉이 다른 졸업생에 비해 10배나 높기 때문이다. 단순평균은 이런 값(샘슨의 연봉같은)에 영향을 많이 받는 단점이 있는데 이런 경우, 집단의 경향을 가장 정확하게 나타내는 지표 중에 하나인 최빈치를 이용해서 문제를 해결해보자.

name income
샘슨 400000
마이클 30000
화이트 20000
아놀드 20000
스미스 20000
로렌스 15000
허드슨 15000
켄트 10000
베카 10000
스코트 10000

수입이 같은 졸업생을 하나로 하는 집단을 만들어 그 집단들로부터 요소의 수가 가장 많은 집함을 찾으면 된다. 아래와 같은 SQL문을 만들 수 있을 것이다.

SELECT income, COUNT(income) cnt
FROM graduates
GROUP BY income
HAVING COUNT(*) >= ALL(SELECT COUNT(*)
FROM graduates
GROUP BY by income)

INCOME CNT
--------- ----------
10000 3
20000 3

ALL 대신 Null과 공집합일 경우에 신경을 쓴다면 MAX,MIN도 사용가능하다. 지금은 "가장 많은" 경우이므로 MAX함수를 사용한다.

SELECT income
FROM Graduates
GROUP BY income
HAVING COUNT(*) >= ( SELECTMAX(cnt)
FROM ( SELECT COUNT(*) AS cnt
FROM Graduates
GROUP BY income) TMP) ;

3.Null을 포함하지 않는 집합을 찾기

COUNT함수의 사용법에는 COUNT(*)과 COUNT(열명)의 2가지 방법이 있다. 이 둘의 차이가 2가지 있다. 첫번째는 퍼포먼스의 차이이고 두번째는 COUNT(*)는 Null을 세지만 COUNT(열명)은 Null을 제외한다는 점이다.

Students

student_id

dpt

sbmt_date

100

이학부

2005-10-10

101

이학부

2005-09-22

102

문학부

 

103

문학부

2005-09-10

200

문학부

2005-09-22

201

공학부

 

202

경제학부

2005-09-25

학생이 레포트를 제출하면, 제출일에 날짜를 기입한다. 미제출일 때는 Null이다. 이 테이블에서 소속된 전학생이 제출완료된 학부를 찾아보자.

--COUNT함수 이용--

SELECT dpt
FROM Students
GROUP BY dpt
HAVING COUNT(*) = COUNT(sbmt_date);

--CASE식 이용--

SELECT dpt
FROM Students
GROUP BY dpt
HAVING COUNT(*) = SUM(CASE WHEN sbmt_date IS NOT NULL
THEN 1
ELSE 0 END);

이번에는 "전원이 9월중에 제출 완료된 학부"를 선택하는 SQL문을 만들어보자.

SELECT dpt
FROM students
GROUP BY dpt
HAVING COUNT(*) = SUM(CASE WHEN sbmt_date is not null

AND TO_DATE(sbmt_date) BETWEEN '20050901' AND '20050930'
THEN 1

ELSE 0 END);

4. 모든조건을 만족하는 가게 찾기

Items ShopItems

item shop item
맥주 대구 맥주
종이기저귀 대구 종이기저귀
자전거 대구 자전거
대구 커텐
서울 맥주
서울 종이기저귀
서울 자전거
부산 테레비
부산 종이기저귀
부산 자전거



「item」테이블의 모든 상품을 갖추고 있는 가게를 선택해보자.

SELECT DISTINCTshop
FROM ShopItems
WHEREitem IN(SELECT item FROM Items);

shop
--------
대구
서울
부산

「ShopItems」테이블처럼 한개의 실체(여기서는 가게)에 대한 정보가 복수행에 분산되어져 있는 경우에는 WHERE구에서 단순히 OR 나 IN으로 조건을 지정해도 정답이 얻기가 힘들다. WHERE구에 지정된 조건은 어디까지나 1행에 대해서 적용되기 때문이다.

여기서 IN의 조건은 결국 「Items」테이블의 상품중 어느 한가지라도 있으면 결과에 포함되어져 버리게 된다. 그렇다면 복수행에 걸쳐 있는 조건, 즉 집합에 대한 조건.을 설정하려면 어떻게 해야 될까? 바로 HAVING구를 이용하면 된다.

SELECT SI.shop
FROM ShopItems SI, Items I
WHERE SI.item = I.item
GROUP BY SI.shop
HAVING COUNT(SI.item) = (SELECT COUNT(item) FROM Items);

shop
--------
대구
서울

기대하던 결과가 나왔다.

그런데 여기서 주의할 점이 있다!

SELECT SI.shop
FROM ShopItems SI, Items I
WHERE SI.item = I.item
GROUP BY SI.shop
HAVING COUNT(SI.item)
= COUNT(I.item);

shop
--------
대구
서울
부산

보다시피 이 조건으로는 결과로 모든 가게가 선택되어졌다. 이것은 결합의 영향을 받아서 COUNT(I.item)의 값이 원래의 「Items」테이블의 행수가 아니게 되어버렸기 때문이다.그 결과를 보자.

SELECT SI.shop, COUNT(SI.item), COUNT(I.item)
FROM ShopItems SI, Items I
WHERE SI.item = I.item
GROUP BY SI.shop;

SHOP COUNT(SI.ITEM) COUNT(I.ITEM)
---------------- -------------- -------------
대구 3 3
부산 2 2
서울 3 3

자, 이번에는 상품마스터에 없는 커텐을 갖고 있는 대구점을 제외한 서울점만 선택하는 SQL문을 만들어보자.

SELECT SI.shop
FROM ShopItems SI, Items II
WHERE SI.item=I.item(+)
GROUP BY SI.shop
HAVING COUNT(SI.item) = (SELECT COUNT(item) FROM Items) /* 조건1 */
AND COUNT(I.item) = (SELECT COUNT(item) FROM Items); /* 조건2 */

shop
--------
서울

「ShopItems」테이블을 마스터로 해서 외부결합을 하면 「item」테이블에 존재하지 않는 커텐과 테레비는 NULL로써 I.item열에 나타난다.

조건1에 의해서 COUNT(SI.item)=4인 대구점이 제외 되고, COUNT(I.item)=2인 부산점이 제외된다.

shop SI.item I.item
대구 맥주 맥주
대구 종이기저귀 종이기저귀
대구 자전거 자전거
대구 커텐   -NULL
서울 맥주 맥주
서울 종이기저귀 종이기저귀
서울 자전거 자전거
부산 테레비   -NULL
부산 종이기저귀 종이기저귀
부산 자전거 자전거

[출처] SQL _ HAVING|작성자 미우


'먹고살기 > Oracle' 카테고리의 다른 글

[Oracle] distinct, rowid 중복 제거, 최신 데이터 하나만 가져오기  (1) 2011.06.30
Sysdate  (0) 2011.06.02
SQL _ 상관서브쿼리  (0) 2011.04.29
SQL _ HAVING_2  (0) 2011.04.29
SQL _ CASE식  (0) 2011.04.29

상관서브쿼리를 이용해서 행과 행을 비교하기

SQL에서는 같은 행내의 열끼리 비교하는 것은 간단하다. 단순히 WHERE구에 「col_1 = col_2」처럼 쓰면 되기 때문이다. 하지만 다른 행의 열끼리를 비교하는 것은 그리 간단한 일이 아니다. SQL에서 행간 비교시 위력을 발휘하는 것인 상관서브쿼리, 특히 자기결합과 함께 쓰일 때이다.

여기서 잠깐! 상관서브쿼리란..? 내부의 쿼리에서 외부 쿼리의 테이블의 데이터를 참조하는 쿼리. 이때 메인 쿼리의 테이블의 행마다 서브쿼리가 반복 실행되어진다.

사용예_1 : 납품일이 2001년 4월 1일인 상품을 상관서브쿼리를 이용해서 참조

--상관서브쿼리--


SELECT * FROM 상품테이블 AA
WHERE '20010401' IN (SELECT 납품일
FROM 주문테이블 BB
WHERE AA.상품코드 = BB.상품코드);
--결과--
상품코드 상품명 단가

───── ─── ──
101 BEER 500
102 JUICE 400

사용예_2 :주문개수를 납품일별로 집계해서, 각자의 합계가 주문개수의 최대치를 150넘길 때만 참조

--HAVING구에서 상관서브쿼리이용--

SELECT SUM(주문개수),납품일
FROM 주문테이블 PP
GROUP BY 납품일

HAVING SUM(주문개수) > (SELECT 150 + MAX(주문개수)
FROM 주문테이블 QQ
WHERE PP.납품일 = QQ.납품일);

--결과--
SUM(주문개수) 납품일
─────── ────
650 20010401
485 20010402
490 20010403

Sales

year

sale

1990

50

1991

51

1992

52

1993

52

1994

50

1995

50

1996

49

1997

55

위의 테이블을 이용해서 작년과 비교해서 「년간판매실적이 늘었는지 줄었는지 그대로인지」를 SQL문으로 만들어보자. 먼저 「그대로였다」를 SQL문으로 작성해보자.

--상관서브쿼리이용--

SELECT year,sale
FROM Sales S1
WHERE sale = (SELECT sale
FROM Sales S2
WHERE S2.year = S1.year - 1)
ORDER BY year;

「Sales」테이블과 별도로 「작년의 행」을 보유하고 있는 집합 S2를 추가한다.서브쿼리내의 「S2.year = S1.year -1」이라는 조건에 의해서 비교대상의 행을 1행 밀어내는 것이다.

--셀프조인이용--
SELECT S1.year, S1.sale
FROM Sales S1, Sales S2
WHERE S2.sale = S1.sale
AND S2.year = S1.year - 1
ORDER BY year;

--결과--

YEAR SALE
----- ----------
1993 52
1995 50

이번에는 년도별 판매실적 비교결과를 한눈에 나타내는 SQL문을 만들어보자.

--상관쿼리이용--

SELECT S1.year, S1.sale,
CASE WHEN sale =
(SELECT sale
FROM Sales S2
WHERE S2.year = S1.year - 1) THEN '→'

WHEN sale >
(SELECT sale
FROM Sales S2
WHERE S2.year = S1.year - 1) THEN '↑'
WHEN sale
(SELECT sale
FROM Sales S2
WHERE S2.year = S1.year - 1) THEN '↓'
ELSE '-' END AS var
FROM Sales S1
ORDER BY year;


--결과--
YEAR SALE VA
------ ---------- --
1990 50 ―
1991 51 ↑
1992 52 ↑
1993 52 →
1994 50 ↓
1995 50 →
1996 49 ↓
1997 55 ↑

--셀프조인이용--

SELECT S1.year, S1.sale,

CASE WHEN S1.year = S2.year THEN '→'

WHEN S1.year > S2.year THEN '↑'

WHEN S1.year < S2.year THEN '↓'

FROM Sales S1, Sales S2

WHERE S2.year = S1.year -1
ORDER BY S1.year;

--결과--
YEAR SALE VA
------- ---------- --
1991 51 ↑
1992 52 ↑
1993 52 →
1994 50 ↓
1995 50 →
1996 49 ↓
1997 55 ↑

Sales2

year

sale

1990

50

1992

50

1993

52

1994

55

1997

55

과거의 데이터가 빠져있는 년도가 있는 테이블이 있다. 이런 경우 앞의 Sale1과 같이 「올해 -1」과 같은 조건설정이 불가능하다. 가장 일반적으로 가장가까운 행을 비교대상으로 할 필요가 있다. 어느년도에서 봐도 「과거에 가장 가까운 년도」라는 것은 다음 두가지 조건을 만족하는 년도를 말하는 것이다.

1. 자신보다 앞의 년도에 있을 것.

2. 조건 1을 만족하는 년도 중에서 최대값일 것

이 조건을 SQL문으로 바꾸면 다음과 같다.

--상관서브쿼리--

SELECT year, sale
FROM Sales2 S1
WHERE sale =
(SELECT sale
FROM Sales2 S2
WHERE S2.year =
(SELECT MAX(year) /* 조건2:조건1을 만족하는 년도 중에서 최대*/
FROM Sales2 S3
WHERE S1.year > S3.year)) /* 조건1:자신보다 과거*/
ORDER BY year;

--셀프조인--

SELECT S2.year AS pre_year, S1.year AS now_year
FROM Sales2 S1, Sales2 S2
WHERE S1.sale = S2.sale
AND S2.year = (SELECT MAX(year)
FROM Sales2 S3
WHERE S1.year > S3.year)
ORDER BY now_year;

--결과--
YEAR SALE
----- ----------
1992 50
1997 55

현재의 값과 가장 가까운값의 차분을 구하는 것도 가능하다.

--상관서브쿼리 : 시작시점이 결과에 포함되지 않음--
SELECT S2.year AS pre_year,
S1.year AS now_year,
S2.sale AS pre_sale,
S1.sale AS now_sale,
S1.sale - S2.sale AS diff
FROM Sales2 S1, Sales2 S2
WHERE S2.year = (SELECT MAX(year)
FROM Sales2 S3
WHERE S1.year > S3.year)
ORDER BY now_year;

-- 자기외부결합이용 : 시작시점도 결과에 포함됨--
SELECT S2.year AS pre_year,
S1.year AS now_year,
S2.sale AS pre_sale,
S1.sale AS now_sale,
S1.sale - S2.sale AS diff
FROM Sales2 S1LEFT OUTER JOIN Sales2 S2
ON S2.year = (SELECT MAX(year)
FROM Sales2 S3
WHERE S1.year > S3.year)
ORDER BY now_year;

은행계좌의 입출금을 기록한 테이블에서 누적을 구해보자

Accounts

pro_date
(
처리일)

prc_amt
(
처리금액)

2006-10-26

12,000

2006-10-28

2,500

2006-10-31

-15,000

2006-11-03

34,000

2006-11-04

-5,000

2006-11-06

7,200

2006-11-11

11,000

---OLAP함수이용--

SELECT prc_date, prc_amt,
SUM(prc_amt) OVER (ORDER BY prc_date) AS onhand_amt
FROM Accounts;

--결과--

PRC_DATE PRC_AMT ONHAND_AMT
-------- ---------- ----------
06-10-26 12000 12000
06-10-28 2500 14500
06-10-31 -15000 -500
06-11-03 34000 33500
06-11-04 -5000 28500
06-11-06 7200 35700
06-11-11 11000 46700

--노이만재귀집합이용--

SELECT prc_date, A1.prc_amt,
(SELECT SUM(prc_amt)
FROM Accounts A2
WHERE A1.prc_date >= A2.prc_date ) AS onhand_amt
FROM Accounts A1
ORDER BY prc_date;

--결과--

PRC_DATE PRC_AMT ONHAND_AMT
-------- ---------- ----------
06-10-26 12000 12000
06-10-28 2500 14500
06-10-31 -15000 -500
06-11-03 34000 33500
06-11-04 -5000 28500
06-11-06 7200 35700
06-11-11 11000 46700

이번에는 3행단위로 누적하는 이동누적을 구해보자

--OLAP함수 이용--

SELECT prc_date, prc_amt,
SUM(prc_amt) OVER (ORDER BY prc_date
ROWS 2 PRECEDING) AS onhand_amt
FROM Accounts;

--이동누적 구하기--

SELECT prc_date, A1.prc_amt,
(SELECT SUM(prc_amt)
FROM Accounts A2
WHERE A1.prc_date >= A2.prc_date
AND (SELECT COUNT(*)
FROM Accounts A3
WHERE A3.prc_date
BETWEEN A2.prc_date AND A1.prc_date ) <= 3 ) AS mvg_sum
FROM Accounts A1
ORDER BY prc_date;

--결과--

PRC_DATE PRC_AMT ONHAND_AMT
-------- ---------- ----------
06-10-26 12000 12000
06-10-28 2500 14500
06-10-31 -15000 -500
06-11-03 34000 21500
06-11-04 -5000 14000
06-11-06 7200 36200
06-11-11 11000 13200

겹쳐지는 기간을 구하기

reserver
(
숙박자)

start_date
(
투숙일)

end_date
(
출발일)

김철수

2006-10-26

2006-10-27

이영희

2006-10-28

2006-10-31

박순희

2006-10-31

2006-11-01

최민철

2006-11-03

2006-11-04

송영수

2006-11-03

2006-11-05

고민수

2006-11-06

2006-11-06

위의 테이블은 어느 호텔의 객실 예약상황을 나타내는 표이다. 위 테이블을 이용해서 예약일이 겹치는 기간을 구해보자

SELECT reserver, start_date, end_date
FROM Reservations R1
WHERE EXISTS
(SELECT *
FROM Reservations R2
WHERE R1.reserver <> R2.reserver /* 자신이외의 손님과 비교 */
AND ( R1.start_date BETWEEN R2.start_date AND R2.end_date /* 条件(1):개시일이 다른 기간내에 있음 */
OR R1.end_date BETWEEN R2.start_date AND R2.end_date)); /* 条件(2):종료일이 다른 기간내에 있음 */

--결과--

RESERVER START_DATE END_DATE
--------------------------- ------------ -----------
이영희 06-10-28 06-10-31
박순희 06-10-31 06-11-01
송영수 06-11-03 06-11-05
최민철 06-11-03 06-11-04

위 테이블에서 최민철씨의 투숙일이 3일이 아닌 4일이면 어떻게 될까? 위의 SQL을 이용하면 결과에 송영수씨는 제외된다. 송영수씨의 투숙일과 출발일이 다른 손님들과 겹쳐지지 않게 되기 때문이다. 즉, 위의 쿼리는 상대의 기간을 완전히 포함하고 있는 기간은 선택되지 않는다는 것이다.

이런 기간을 구하기 위해 조건을 추가해보자.

--최민철씨의 투숙일 변경--

update reservations
set start_date = '2006-11-04'
where reserver = '최민철';

--위 쿼리를 그대로 이용--

SELECT reserver, start_date, end_date
FROM Reservations R1
WHERE EXISTS
(SELECT *
FROM Reservations R2
WHERE R1.reserver <> R2.reserver /* 자신이외의 손님과 비교 */
AND ( R1.start_date BETWEEN R2.start_date AND R2.end_date /* 条件(1):개시일이 다른 기간내에 있음 */
OR R1.end_date BETWEEN R2.start_date AND R2.end_date)); /* 条件(2):종료일이 다른 기간내에 있음 */

--결과(송영수씨가 제외됨)--

RESERVER START_DATE END_DATE
--------------------------- ------------ -----------
이영희 06-10-28 06-10-31
박순희 06-10-31 06-11-01
최민철 06-11-04 06-11-04

--상대를 전부 포함한 기간을 출력--

SELECT reserver, start_date, end_date
FROM Reservations R1
WHERE EXISTS
(SELECT *
FROM Reservations R2
WHERE R1.reserver <> R2.reserver
AND ((R1.start_date BETWEEN R2.start_date AND R2.end_date
OR R1.end_date BETWEEN R2.start_date AND R2.end_date)
OR (R2.start_date BETWEEN R1.start_date AND R1.end_date
AND R2.end_date BETWEEN R1.start_date AND R1.end_date)));
--결과--

RESERVER START_DATE END_DATE
--------------------------- ------------ -----------
이영희 06-10-28 06-10-31
박순희 06-10-31 06-11-01
송영수 06-11-03 06-11-05
최민철 06-11-04 06-11-04


[출처] SQL _ 상관서브쿼리|작성자 미우


'먹고살기 > Oracle' 카테고리의 다른 글

Sysdate  (0) 2011.06.02
SQL _ HAVING  (0) 2011.04.29
SQL _ HAVING_2  (0) 2011.04.29
SQL _ CASE식  (0) 2011.04.29
[Oracle] ROWNUM 사용 시 주의  (0) 2011.04.25