검색결과 리스트
분류 전체보기에 해당되는 글 93건
- 2011.04.29 리눅스 명령어
- 2011.04.29 SQL _ HAVING
- 2011.04.29 SQL _ 상관서브쿼리
- 2011.04.29 SQL _ HAVING_2
- 2011.04.29 SQL _ CASE식
글
arp
# arp [옵션]
arp는 커널의 ARP 테이블을 조작하기 위한 명령이다. ARP 테이블은 네트워크를 통해 연결되어 있는 호스트의 IP 주소와 실제 물리적인 이더넷 MAC 주소가 대응되어 있는 지도라고 할 수 있다. 실제로 네트워크를 통해 컴퓨터끼리 데이터를 주고받는 데에는 네트워크 카드 제조사에 부여된 하드웨어 주소인 MAC(Media Address Control) 주소를 사용한다. 특정 IP 주소에 대한 네트워크 전송 요청이 생기면 리눅스는 이 ARP 테이블을 보고 물리적인 주소인 MAC 주소를 알아낸다.
-a [IP주소] : ARP 테이블을 표시한다. 명령 뒤에 IP 주소가 지정되면 컴퓨터의 IP 주소와 MAC 주소만 표시된다.
-d [IP주소] : ARP 테이블에서 주소의 호스트를 지운다.
-s : ARP 테이블에 강제로 호스트를 추가하고 호스트의 IP 주소와 MAC 주소를 연결할 때 사용한다.
yum
# yum [명령] [옵션] [패키지이름]
yum은 온라인 패키지 관리 도구이다. yum은 레드햇 패키지 관리 도구인 rpm을 기반으로 한다. 시스템 관리자는 yum을 이용하여 네트워크로 연결되어 있는 패키지 저장소에서 패키지를 검색하거나 내려받아 설치할 수 있다.
check-update : 패키지 저장소의 패키지 정보를 업데이트한다.
search [검색어] : 패키지를 검색한다.
install [패키지이름] : 패키지를 설치한다.
update [패키지이름] : 패키지의 버전을 판올림한다. 특정 패키지 이름을 지정하지 않는다면 시스템에 설치되어 있는 모든 패키지의 버전을 판올림할 것이다.
remove [패키지이름] : 패키지를 없앤다.
smbpasswd
# smbpasswd [옵션]
smbpasswd는 삼바 사용자 계정의 비밀번호를 변경하는 명령이다. 루트 계정에서 smbpasswd 명령을 수행하면 리눅스 서버의 사용자 계정(/etc/passwd에 등록되어 있는 사용자)을 삼바 사용자 계정으로 등록할 수 있다. 이렇게 추가된 삼바 사용자 계정은 /etc/smbpasswd에서 확인할 수 있다.
-r [원격호스트이름] : 비밀번호를 변경할 삼바 서버의 이름을 지정한다.
-a [사용자이름] : 삼바 사용자 계정을 추가한다.
-d [사용자이름] : 삼바 사용자 계정을 비활성화(disabled)한다.
-e [사용자이름] : 삼바 사용자 계정을 활성화(enabled)한다.
-n : 사용자 계정의 비밀번호가 없도록 설정한다.
usermod
# usermod [옵션] [사용자계정]
usermod는 리눅스 사용자 계정의 정보를 변경하기 위한 명령이다.
-c [사용자에대한설명] : 사용자에 대한 설명 필드의 내용을 수정한다.
-d [홈디렉터리] : 사용자의 홈 디렉터리를 변경한다.
-e [계정만료일] : 사용자의 비밀번호 만료 날짜를 변경한다.
-G [그룹] : 사용자의 그룹을 변경한다.
-u [UID] : 사용자의 UID(User ID)를 변경한다.
-l [사용자계정] : 사용자의 계정 이름을 변경한다.
smbclient
# smbclient //[서버이름]/[공유자원이름] [비밀번호] [옵션]
smbclient는 SMB 프로토콜을 통해 네트워크 공유 자원에 접근할 수 있는 클라이언트 프로그램이다. ftp 클라이언트와 같이 명령 행을 바탕으로 한 서버와의 상호작용을 제공한다. '//[서버이름]/[공유자원이름]'과 같은 형식으로 네트워클 공유 자원에 접근할 수 있으며 자원에 비밀번호가 설정되어 있는 경우 직접 명령 행에서 비밀번호를 입력할 수 있다. smbclient로 로그인에 성공하면 smbclient 프롬프트('smb:\=')가 나타나며 ftp 클라이언트와 비슷한 여러 가지 명령을 사용할 수 있다.
-l [IP주소] : 접속 대상 호스트의 IP 주소를 입력한다.
-p [포트번호] : 클라이언트가 요청을 받아들일 포트 번호를 입력한다.
-L [서버이름] : 컴퓨터가 제공하는 공유 자원과 서비스에 대한 목록을 표시한다.
-t [터미널코드] : 한글 파일 이름을 보기 위한 문자 세트를 지정할 수 있다.
-s [환경설정파일] : 삼바 환경설정 파일의 위치를 지정한다.
-l [로그파일] : 지정된 파일로 로그 기록을 내보낸다.
-W [작업그룹이름] : 클라이언트가 연결을 원하는 작업그룹을 지정한다.
wget
# wget [옵션] [주소]
wget는 텍스트 환경에서 인터넷을 통해 파일을 받아오기 위한 명령이다. 인터넷의 기본 프로토콜인 HTTP, FTP 프로토콜을 지원한다. 단순히 파일의 주소만 입력해주기만 하면 파일을 내려받기 시작한다.
-b : 내려받는 파일의 용량이 많을 때 wget 명령을 백그라운드 프로세스로 실행한다.
-o [파일이름] : 파일을 받아오는 동안의 로그 정보를 남길 파일을 지정한다.
-i [파일이름] : 받아올 파일이 많을 경우 파일의 목록을 하나의 파일로 만들어서 wget 명령에 전달할 수 있다. 받아올 파일의 목록이 기록되어 있는 파일을 지정한다.
sort
# sort [옵션]
sort는 텍스트 파일의 문자를 줄 단위로 정렬하는 명령이다. 명령 뒤에 [파일이름]이 없다면 정렬 결과를 표준 출력(모니터)으로 출력할 것이다.
-c : 이미 정렬된 상태인지 검사하고 정렬된 상태라면 정렬하지 않는다.
-b : 정렬을 할 때 행의 앞부분에 있는 공백을 무시한다.
-d : 정렬의 기준으로 영어 알파벳 대소문자와 숫자만을 고려한다.
-o [파일이름] : 정렬 결과를 지정된 파일로 출력한다.
-r : 내림차순으로 정렬한다.
ssh
# ssh [사용자]@[SSH서버주소]
# ssh -l [사용자] [SSH서버주소]
ssh는 명령 행에서 사용할 수 있는 OpenSSH 클라이언트 프로그램이다. 리눅스의 명령 프롬프트에서 원격 접속을 위해 사용된다.
-l [사용자계정] : 서버에 로그인할 사용자 계정을 지정한다.
-p [포트번호] : SSH 서버의 포트 번호를 지정한다.
-F [환경설정파일] : ssh 클라이언트의 기본 환경설정 파일을 지정된 설정 파일로 대체한다.
logout
# logout
logout은 현재의 세션을 끝내기 위한 명령이다. X 윈도우 세션에서 로그아웃을 하면 X 윈도우 사용자의 세션을 끝내고 처음 로그인 화면으로 돌아가는 것과 같은 원리로 원격 터미널에서 로그아웃하면 터미널 접속을 끝낸다.
ssh-keygen
# ssh-keygen [옵션]
ssh-keygen은 리눅스에서 SSH 접속에 사용되는 인증 키를 만드는 명령이다. 명령을 입력하고 키가 저장될 파일을 지정한 다음 키에 접근하기 위해 필요한 passphrase를 지정하면 SSH 인증 키가 만들어진다.
-t [rsa 또는 rsa1] : 인증 키 형식을 지정한다. rsa는 SSH 프로토콜 버전 2로, rsa1은 SSH 프로토콜 버전 1로 저장한다.
-f [파일이름] : 인증 키를 저장할 파일을 지정한다.
init
# init [옵션(실행단계)]
init 명령은 시스템 초기화 프로세스 init를 시작(재시작)하는 명령이다. 이때 init 명령의 옵션으로 실행 단계를 지정하면 현재 세션을 끝내고 inittab에 설정되어 있는 각 실행 단계로 전환합니다. 예를 들면 잠깐 동안 X 윈도우 환경에서 콘솔 환경으로 전환할 때 유용하게 사용할 수 있다. /etc/inittab을 편집하여 기본 실행 단계를 3으로 지정하고 시스템을 재부팅할 필요 없이 터미널에서 'init 3'이라는 명령을 입력하면, X 윈도우를 끝내고 바로 콘솔 환경으로 전환될 것이다.
init 0 : 시스템을 끝낸다.
init 1 ~ init 5 : 지정한 실행 단계로 부팅한다.
init 6 : 시스템을 다시 재부팅한다.
init S 또는 init single : 단일 사용자 모드로 부팅한다.
telnet
# telnet [옵션] [접속대상호스트] [포트번호]
telnet 명령은 원격 접속을 위한 TELNET 프로토콜을 통해서 다른 호스트에 접속하기 위한 명령이다. telnet 클라이언트 명령으로서 접속 대상 호스트에 telnet 서버가 운영되고 있어야 접속할 수 있다. 호스트 다음에 특정 포트 번호(텔넷의 기본 포트 번호는 23번으로 예약되어 있음)를 입력함으로써 다른 포트 번호를 사용하는 호스트에 접속할 수 있다.
-a : 자동 접속을 시도한다. 환경 변수 USER에 설정되어 있는 현재 로그인해 있는 사용자 계정을 접속 대상 호스트로 전송할 것이다.
-l : 접속 대상 호스트에 로그인할 사용자 계정을 지정한다.
grub-install
# grub-install [옵션] [장치이름]
grub-install은 부트로더 GRUB를 지정한 영역에 설치하는 명령이다. 장치 이름에는 디스크 파티셔느이 장치 파일 이름을 입력한다. 이때 일반적인 리눅스 시스템 장치 파일 이름인 /dev/hdXX와 같은 형식으로 입력할 수도 있지만, GRUB 형식의 이름 hd0과 같이 사용하는 것도 허용된다.
--root-directory=[디렉터리] : 루트 디렉터리 대신 GRUB 이미지를 설치할 디렉터리를 명시할 수 있다.
--force-lba : 오래되거나 버그와 같은 문제가 있는 바이오스 환경에서 GRUB를 설치하기 위해 LBA 모드를 활성화한다.
mke2fs
# mke2fs [옵션] [장치이름]
mke2fs는 디스크 장치에 리눅스 파일 시스템을 만들기 위한 명령이다. 장치 이름에는 /dev/hdXX와 같이 디스크 파티션의 장치 파일 이름을 입력한다.
-b [블록크기] : 바이트 단위로 만들어지는 파일 시스템의 블록 크기를 지정한다.
-c : 파일 시스템을 만들면서 배드 블록이 있는지 물리적으로 점검한다.
-v : 파일 시스테이 만들어지는 과정을 자세하게 표시한다.
startx
# startx [클라이언트] [옵션] [--서버] [옵션]
startx는 X 윈도우를 실행하는 명령 스크립트이다. '스크립트'라는 말에서 알 수 있듯이 단순히 X 윈도우를 실행하는 명령뿐만 아니라 X 윈도우를 실행하기 위해 등록되어 있는 다양한 환경설정 명령을 먼저 내리고 최종적으로 X 윈도우를 실행한다.
-- -depth [색상] : X 서버의 색상수를 지정한다.
-- -dpi [해상도] : X 서버의 해상도를 지정한다.
export
# export [환경변수]=[값]
export 명령은 환경 변수를 지정, 변경하거나 현재 정의되어 있는 환경 변수를 보여주는 명령이다. 환경 변수를 변경함으로써 명령 프롬프트에서 실행한 프로그램에 영향을 미치게 된다. 다만 export 명령에 의해 변경되 환경 변수는 export 명령을 실행한 사용자의 로그아웃 전까지만 유효하며 영구적으로 변경하기 위해서는 환경 변수를 정의하는 설정 파일(/etc/profile 등)을 직접 수정해야 한다.
uname
# uname [옵션]
uname 명령은 현재 시스템에 대한 정보를 표시하는 명령이다. 다양한 옵션을 이용해서 원하는 정보를 확인할 수 있다.
-a : 시스템의 모든 정보를 표시한다. -s : 시스템의 커널의 이름을 표시한다.
-n : 시스템의 호스트 이름을 표시한다. -r : 커널의 릴리스 정보를 표시한다.
-v : 시스템의 커널 버전을 표시한다. -m : 하드웨어의 아키텍처 정보를 표시한다.
-i : 하드웨어 플랫폼 정보를 표시한다.
init
init는 실행 단계를 변경할 수 있는 명령이다.
setkeycodes
# setkeycodes [스캔코드] [키코드]
setkeycodes 명령은 스캔 코드를 키코드에 대응시키는 명령이다. 명령의 첫 번째 인자는 스캔 코드로서 키마다 정해져 있는 키 값을 뜻한다. 키코드는 커널에서 키보드의 각 키마다 부여한 키 값으로 setkeycodes는 스캔 코드 값을 두 번째 인자인 키 코드 값으로 커널에 등록할 것이다.
showkey
# showkey [옵션]
showkey는 키보드로부터 입력된 키를 테스트하기 위한 명령이다. 키보드 키를 누르는 순간 해당 키 코드에 대한 press 메시지가 출력되고 키에서 손을 떼는 순간 release 메시지가 출력될 것이다.
-s : 키보드의 스캔 코드 값을 출력한다.
-k : 키보드의 키 코드 값을 출력한다.
-a : 키보드의 아스키 값을 출력한다.
xev
# xev [옵션]
xev는 X 윈도우에서 벌어지는 이벤트를 출력하는 명령이다. xev 명령을 실행하면 창이 하나 뜨는데 이 창에서 벌어지는 키보드 입력, 마우스의 이동, 마우스 클릭 등 모든 이벤트를 수치 정보로 보여준다.
-display : 이벤트 정보를 출력할 X 윈도우 서버를 지정한다.
-geometry : 이벤트 정보를 받아들일 창의 크기, 위치를 지정한다.
-bw : 이벤트 정보를 받아들일 창 테두리선의 두께를 지정한다.
xmodmap
# xmodmap [옵션] [파일이름]
xmodmap은 X 윈도우에서 키보드의 키 코드를 해당하는 키와 대응시키는 명령이다. 현재 키보드에 설정되어 있는 키코드 값을 변경하거나 새로운 키코드 값을 추가한다. 옵션 keycode를 이용해서 하나의 키에 대한 키코드를 지정할 수도 있지만, 예제에 나온 것처럼 Xmodmap이라는 파일로 여러 키의 키코드를 일괄적으로 등록하는 것이 일반적이다.
-e : 특정 키 코드를 해당 키와 대응시킨다.
-pk : 현재 키 코드에 대응되어 있는 키 값을 보여준다.
locale
# locale [옵션]
locale은 현재 로케일 상태를 확인하는 명령이다. locale 명령으로 확인할 수 있는 환경 변수는 LANG(언어), LC_CTYPE(문자), LC_COLLATE(문자 정렬 순서), LC_MESSAGE(메시지 표현을 위한 특별한 설정), LC_NUMERIC(숫자), LC_MONETARY(화폐 단위), LC_TIME(시간과 날짜) 등이 있다.
-a : 로케일을 확인한다.
dmesg
# dmesg [옵션]
dmesg는 커널의 상태 정보를 확인하기 위한 명령이다. 리눅스가 부팅될 때의 각종 메시지를 다시 볼 때 이 명령을 사용한다.
-n [실행단계] : 해당 실행 단계의 상태 정보만 보여준다.
lsmod
# lsmod
lsmod는 커널 메모리에 올라가 있는 모듈들의 목록을 보여주는 명령이다. 모듈의 이름(Module), 모듈의 크기(Size), 모듈이 사용되고 있는 횟수(Used), 해당 모듈을 참조하고 있는 다른 모듈(by)를 표시한다. 이 명령의 결과는 /proc/modules에서도 확인할 수 있다.
modprobe
# modprobe [모듈이름] [옵션]
modprobe 명령은 커널 모듈을 커널 메모리에 적재하는 데 사용하는 명령이다. 모듈 이름에는 커널에 올리려는 모듈을 /lib/modules 디렉터리에서 찾고 이를 입력한다.
rmmod
# rmmod [옵션] [모듈이름]
rmmod는 커널 메모리에서 해당 모듈을 내릴 때 사용하는 명령이다. 어떤 장치의 경우 모듈을 함부로 내릴 수 없는데, rmmod 명령을 입력하면 Device or resource busy라는 메시지가 나타날 것이다.
-r : 의존 관계에 있는 모든 모듈을 한꺼번에 내린다.
mysqladmin
# mysqladmin [옵션] [명령]
mysqladmin은 MySQL 데이터베이스 관리자 명령이다. 명령에 특정 키워드를 입력하면 데이터베이스에 직접 로그인하지 않은 리눅스 명령 프롬프트에서 데이터베이스 관리와 관련된 작업(MySQL 종료, 재시작, 새로운 데이터베이스 생성과 삭제 등)을 수행할 수 있다.
다음과 같은 명령을 사용할 수 있다.
status : 데이터베이스의 상태를 출력한다.
shutdown : 데이터베이스를 끝낸다.
reload : 데이터베이스를 재시작한다.
create [데이터베이스이름] : 새로운 데이터베이스를 만든다.
drop [데이터베이스이름] : 데이터베이스를 지운다.
-u [사용자 계정] : 데이터베이스에 접속하는 MySQL 사용자 계정을 지정한다.
-p [비밀번호] : 데이터베이스에 접속하기 위한 사용자 계정의 비밀번호를 지정한다(※ 주의 : -p 옵션 뒤에 공백 없이 비밀번호를 입력해야 한다).
--default-character-set=[문자세트] : 데이터베이스의 기본 문자 세트를 지정한다.
-h [호스트이름] : 접속할 대상 데이터베이스의 호스트 이름을 지정한다.
-P [포트번호] : 접속할 대상 데이터베이스의 포트 번호를 지정한다.
--protocol=[프로토콜] : 데이터베이스에 접속할 때 사용할 프로토콜을 지정한다.
mysql
# mysql [옵션] [데이터베이스이름]
mysql은 MySQL의 데이터베이스에 접속하기 위한 클라이언트 명령 행 도구이다. 로그인에 성공하면 MySQL 명령 프롬프트('mysql>')가 나타나는데 여기에서 데이터베이스를 조작할 수 있는 명령을 내릴 수 있다.
-D [데이터베이스이름] : 접속할 데이터베이스 이름을 지정한다.
-u [사용자계정] : 데이터베이스에 접속하는 MySQL 사용자 계정을 지정한다.
-p [비밀번호] : 데이터베이스에 접속하기 위한 사용자 계정의 비밀번호를 지정한다(※ 주의 : -p 옵션 뒤에 공백 없이 비밀번호를 입력해야 한다).
--default-character-set=[문자세트] : 데이터베이스의 기본 문자 세트를 지정한다.
-h [호스트이름] : 접속할 대상 데이터베이스의 호스트 이름을 지정한다.
-P [포트번호] : 접속할 대상 데이터베이스의 포트 번호를 지정한다.
--protocol=[프로토콜] : 데이터베이스에 접속할 때 사용할 프로토콜을 지정한다.
sh
# sh [셸스크립트 파일]
sh는 리눅스와 유닉스의 기본 셸 스크립트 언어로 짜인 스크립트 파일을 실행하는 명령이다.
ping
# ping [옵션]
ping은 네트워크 연결 상태를 검사하기 위한 도구이다. ICMP 프로토콜 형식의 패킷을 보내어 연결 상태를 확인한다.
-c [횟수] : ping을 통해 보낼 패킷의 수를 지정한다.
-i [초] : 정해진 시간 간격(초 단위)으로 패킷을 보낸다.
-l [네트워크 인터페이스] : 패킷을 보낼 네트워크 인터페이스를 지정한다.
-s [패킷크기] : 보낼 패킷의 크기(바이트 단위)를 지정한다.
-t [ttl] : 패킷의 ttl 값을 지정해서 보낸다.
※ttl(Time To Live) 값이란?
-> ttl은 ping으로 보낸 패킷이 네트워크에서 영원히 돌아다니는 것을 막기 위해(이렇게 되면 네트워크의 부하가 커질 것이다) 패킷이 자동으로 소멸하는 시간 간격을 말한다. ttl의 시간 간격은 일반적으로 라우터를 통과할 때마다, 패킷이 다른 네트워크로 넘어갈 때마다 줄어들어 ttl이 0이 되면 패킷은 소멸한다.
sestatus
# sestatus [옵션]
sestatus는 SELinux 시스템의 상태를 확인하기 위한 명령이다.
-v : /etc/sestatus.conf에 등록되어 있는 파일, 프로세스 보안 문맥을 확인한다.
chcon
# chcon [옵션] [보안문맥] [파일이름]
chcon은 파일의 보안 문맥을 변경할 때 사용하는 명령이다.
-r : 파일 보안 문맥 중 역할(role) 필드를 변경한다.
-t : 파일 보안 문맥 중 유형(type) 필드를 변경한다.
-u : 파일 보안 문맥 중 신분(identity) 필드를 변경한다.
-R : 하위 디렉터리의 파일과 디렉터리에 대해 보안 문맥을 적용한다.
setsebool
# setsebool [보안정책] [1 또는 0]
setsebool은 system-config-securitylevel에서 설정할 수 있는 SELinux의 보안 정책을 터미널 환경에서 제어하는 명령이다. 보안 정책은 각 항목별로 표시되는데 1은 활성, 0은 비활성 상태임을 나타낸다.
-P : -P 옵션이 주어지면 보안 정책을 디스크에 반영하게 된다. 다시 부팅을 하더라도 설정한 보안 정책이 유지될 것이다. -P 옵션이 없다면 현재 설정되어 있는 보안 정책에만 영향을 미칠 것이며, 시스템의 보안 정책이 정의되어 있는 파일 /etc/selinux/SELINUXTYPE/booleans은 수정되지 않을 것이다.
crontab
# crontab [-u 사용자] [파일] 옵션
crontab 명령은 작업할 내용을 작성하거나 현재 설정되어 있는 작업 스케줄을 확인하거나 이미 설정되어 있는 작업을 지우는 등의 스케줄 관리를 할 수 있다.
-u : 작업을 수행할 사용자를 지정한다.
-e : 작업할 내용을 작성한다.
-l : 현재 설정되어 있는 작업 내용을 확인한다.
-r : 설정되어 있는 작업 스케줄 정보를 지운다.
rdate
# rdate [옵션] [타임서버주소]
rdate는 네트워크를 통해 타임 서버에서 날짜와 시간 정보를 받아오는 명령이다.
-p : 타임 서버에서 받은 날짜와 시간 정보를 표시한다.
-s : 타임 서버에서 받은 날짜와 시간 정보를 시스템의 현재 시간으로 지정한다.
-u : 타임 서버에서 날짜와 시간정보를 받는 데 UDP 프로토콜을 사용한다.
hwclock
# hwclock [옵션]
hwclock는 하드웨어 시간(바이오스에서 받아온 시간 정보)을 현재 시스템의 시간으로 설정하는 명령이다.
-r : 받아온 하드웨어 시간을 표시한다.
-w 또는 --systohc : 받아온 하드웨어 시간을 시스템의 현재 시간으로 지정한다.
--utc : 시간 정보를 국제적인 시간 기준인 UTC(Universal Time Coordinated)로 지정한다.
--localtime : 시간 정보를 일반적인 지역별 시간대로 지정한다.
logrotate
# logrotate
logrotate는 시스템 로그를 순환시키기 위한 명령이다.
-d : logrotate를 디버그 모드로 실행한다.
-f : 로그 순환을 중지한다.
-s [상태파일] : 특정 상태 파일에 대한 순환을 지시한다. 다양한 형태의 로그를 순환시킬 때 필요한 옵션이다.
[출처] [본문스크랩] 리눅스 명령어|작성자 미우
'먹고살기 > Unix' 카테고리의 다른 글
공백제거 (5) | 2014.03.21 |
---|---|
쉘 스크립트 (0) | 2011.06.30 |
리눅스 실무 명령어 (0) | 2011.04.29 |
설정
트랙백
댓글
글
1.데이터의 빠진 부분 찾기
SeqTbl
seq |
name |
1 |
마이크 |
2 |
제인 |
3 |
데이브 |
5 |
조안 |
6 |
메리 |
8 |
안 |
위와 같은 일련번호를 가진 테이블이 있다고 하자. 그런데 일련번호가 있다고 해도, 번호가 연속적이지 못하다. 4와 7이 빠져있다. 이 테이블에서 데이터가 빠져있는지를 확인해 보는 SQL을 만들어보자. 만약 이 테이블이 파일이고 절차적언어를 이용한다면 다음과 같은 순서로 해결할 것이다.
1.일련번호를 정렬시킨다.
2.루프해서 한행씩 다음행과 번호를 비교한다.
이런 간단한 순서 안에서도 절차적언어와 파일 시스템의 특징을 알 수 있다. 파일의 레코드는 순서를 가지고 있고, 언어는 이를 정렬시킨다는 것이다. 하지만 테이블의 행은 순서를 가지고 있지 않고 SQL도 정렬 연산자를 가지고 있지 않다는 것이다.(ORDER BY는 SQL의 연산자가 아니다)대신 SQL은 복수행을 하나의 집합으로 취급한다. 테이블 전체를 하나의 집합으로 본다면 다음과 같은 SQL문을 만들 수 있을 것이다.
SELECT'결함있음'ASgap 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
INCOME CNT |
ALL 대신 Null과 공집합일 경우에 신경을 쓴다면 MAX,MIN도 사용가능하다. 지금은 "가장 많은" 경우이므로 MAX함수를 사용한다.
SELECT income |
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 --CASE식 이용-- SELECT dpt |
이번에는 "전원이 9월중에 제출 완료된 학부"를 선택하는 SQL문을 만들어보자.
SELECT dpt AND TO_DATE(sbmt_date) BETWEEN '20050901' AND '20050930' ELSE 0 END); |
4. 모든조건을 만족하는 가게 찾기
Items ShopItems
item | shop | item | |
맥주 | 대구 | 맥주 | |
종이기저귀 | 대구 | 종이기저귀 | |
자전거 | 대구 | 자전거 | |
대구 | 커텐 | ||
서울 | 맥주 | ||
서울 | 종이기저귀 | ||
서울 | 자전거 | ||
부산 | 테레비 | ||
부산 | 종이기저귀 | ||
부산 | 자전거 |
「item」테이블의 모든 상품을 갖추고 있는 가게를 선택해보자.
SELECT DISTINCTshop |
shop |
「ShopItems」테이블처럼 한개의 실체(여기서는 가게)에 대한 정보가 복수행에 분산되어져 있는 경우에는 WHERE구에서 단순히 OR 나 IN으로 조건을 지정해도 정답이 얻기가 힘들다. WHERE구에 지정된 조건은 어디까지나 1행에 대해서 적용되기 때문이다.
여기서 IN의 조건은 결국 「Items」테이블의 상품중 어느 한가지라도 있으면 결과에 포함되어져 버리게 된다. 그렇다면 복수행에 걸쳐 있는 조건, 즉 집합에 대한 조건.을 설정하려면 어떻게 해야 될까? 바로 HAVING구를 이용하면 된다.
SELECT SI.shop |
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) |
SHOP COUNT(SI.ITEM) COUNT(I.ITEM) |
자, 이번에는 상품마스터에 없는 커텐을 갖고 있는 대구점을 제외한 서울점만 선택하는 SQL문을 만들어보자.
SELECT SI.shop |
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일인 상품을 상관서브쿼리를 이용해서 참조
--상관서브쿼리--
───── ─── ── |
사용예_2 :주문개수를 납품일별로 집계해서, 각자의 합계가 주문개수의 최대치를 150넘길 때만 참조
--HAVING구에서 상관서브쿼리이용--
SELECT SUM(주문개수),납품일 HAVING SUM(주문개수) > (SELECT 150 + MAX(주문개수) --결과-- |
Sales
year |
sale |
1990 |
50 |
1991 |
51 |
1992 |
52 |
1993 |
52 |
1994 |
50 |
1995 |
50 |
1996 |
49 |
1997 |
55 |
위의 테이블을 이용해서 작년과 비교해서 「년간판매실적이 늘었는지 줄었는지 그대로인지」를 SQL문으로 만들어보자. 먼저 「그대로였다」를 SQL문으로 작성해보자.
--상관서브쿼리이용-- SELECT year,sale 「Sales」테이블과 별도로 「작년의 행」을 보유하고 있는 집합 S2를 추가한다.서브쿼리내의 「S2.year = S1.year -1」이라는 조건에 의해서 비교대상의 행을 1행 밀어내는 것이다.
--셀프조인이용--
--결과-- YEAR SALE |
이번에는 년도별 판매실적 비교결과를 한눈에 나타내는 SQL문을 만들어보자.
--상관쿼리이용-- SELECT S1.year, S1.sale, WHEN sale >
--셀프조인이용-- 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
--결과-- |
Sales2
year |
sale |
1990 |
50 |
1992 |
50 |
1993 |
52 |
1994 |
55 |
1997 |
55 |
과거의 데이터가 빠져있는 년도가 있는 테이블이 있다. 이런 경우 앞의 Sale1과 같이 「올해 -1」과 같은 조건설정이 불가능하다. 가장 일반적으로 가장가까운 행을 비교대상으로 할 필요가 있다. 어느년도에서 봐도 「과거에 가장 가까운 년도」라는 것은 다음 두가지 조건을 만족하는 년도를 말하는 것이다.
1. 자신보다 앞의 년도에 있을 것.
2. 조건 1을 만족하는 년도 중에서 최대값일 것
이 조건을 SQL문으로 바꾸면 다음과 같다.
--상관서브쿼리-- SELECT year, sale
--셀프조인-- SELECT S2.year AS pre_year, S1.year AS 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, PRC_DATE PRC_AMT ONHAND_AMT
--노이만재귀집합이용-- SELECT prc_date, A1.prc_amt,
--결과-- PRC_DATE PRC_AMT ONHAND_AMT |
이번에는 3행단위로 누적하는 이동누적을 구해보자
--OLAP함수 이용-- SELECT prc_date, prc_amt, SELECT prc_date, A1.prc_amt,
--결과-- PRC_DATE PRC_AMT ONHAND_AMT |
겹쳐지는 기간을 구하기
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
--결과-- RESERVER START_DATE END_DATE |
위 테이블에서 최민철씨의 투숙일이 3일이 아닌 4일이면 어떻게 될까? 위의 SQL을 이용하면 결과에 송영수씨는 제외된다. 송영수씨의 투숙일과 출발일이 다른 손님들과 겹쳐지지 않게 되기 때문이다. 즉, 위의 쿼리는 상대의 기간을 완전히 포함하고 있는 기간은 선택되지 않는다는 것이다.
이런 기간을 구하기 위해 조건을 추가해보자.
--최민철씨의 투숙일 변경-- update reservations --위 쿼리를 그대로 이용-- SELECT reserver, start_date, end_date --결과(송영수씨가 제외됨)-- RESERVER START_DATE END_DATE --상대를 전부 포함한 기간을 출력-- SELECT reserver, start_date, end_date RESERVER START_DATE END_DATE
[출처] 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 |
설정
트랙백
댓글
글
아래 테이블은 소방대원의 상태를 나타내는 표이다. 팀 전원이 대기 상태일 때만 출동이 가능하다.
출동명령을 내릴 수 있는 팀을 찾아보자.
Teams
member |
team_id |
status |
죠 |
1 |
대기 |
켄 |
1 |
출동중 |
미크 |
1 |
대기 |
카렌 |
2 |
출동중 |
키스 |
2 |
휴가 |
죤 |
3 |
대기 |
하트 |
3 |
대기 |
딕 |
3 |
대기 |
베스 |
4 |
대기 |
알렌 |
5 |
출동중 |
로버트 |
5 |
휴가 |
마크 |
5 |
대기 |
「모든 멤버의 상태가 "대기중"이다」라는 조건은 전칭양화이므로 NOT EXISTS를 사용하면 된다.
SELECT team_id, member
--결과-- TEAM_ID MEMBER |
이것은 전칭양화와 존재양화간의 동치변환을 이용한 것이다.
「모든 멤버의 상태가 대기중이다」
= 「대기중이지 않은 멤버가 한명도 존재하지 않는다」
이 쿼리는 퍼포먼스면에서 뛰어나고 구체적인 팀멤버도 표시가능하다는 장점이 있다. 하지만 이중부정을 사용하기 때문에 직감적으로 알기 어려운 쿼리이기도 하다.
HAVING구를 사용하면 다음과 같이 간단하게 표현할 수 있다.
--전칭문을 집합으로 표현 ① SELECT team_id THEN 1 ELSE 0 END);
----전칭문을 집합으로 표현 ② SELECT team_id
--결과-- team_id ------- 3 4 |
이번에는 출동가능멤버를 일람하는 쿼리를 만들어보자
SELECT team_id,
--결과-- TEAM_ID STATUS |
Materials
center |
receive_date |
material |
서울 |
2007-4-01 |
주석 |
서울 |
2007-4-12 |
아연 |
서울 |
2007-5-17 |
알루미늄 |
서울 |
2007-5-20 |
아연 |
부산 |
2007-4-20 |
동 |
부산 |
2007-4-22 |
니켈 |
부산 |
2007-4-29 |
납 |
대구 |
2007-3-15 |
티탄 |
대구 |
2007-4-01 |
탄소강 |
대구 |
2007-4-24 |
탄소강 |
대구 |
2007-5-02 |
마그네슘 |
대구 |
2007-5-10 |
티탄 |
인천 |
200-5-10 |
아연 |
인천 |
2007-5-28 |
주석 |
위의 테이블에서 자원이 중복되어 있는 거점을 찾는 쿼리를 만들어보자.
--자원이 중복된 거점 선택 SELECT center
--결과-- CENTER
--거점마다 중복여부 일람표시 SELECT center,
--결과-- CENTER STATUS
--중복이 있는 집합: EXISTS이용 SELECT center, material
--결과-- CENTER MATERIAL |
위테이블에서 원산국을 추가시킨 테이블을 이용해 (자원,원산국)의 2열로 봤을 때 중복되어 있는 거점을 선택하는 쿼리를 만들어보자.
Materials2
center |
receive_date |
material |
orgland |
서울 |
2007-04-01 |
주석 |
칠레 |
서울 |
2007-04-12 |
아연 |
타이 |
서울 |
2007-05-17 |
알루미늄 |
브라질 |
서울 |
2007-05-20 |
아연 |
타이 |
부산 |
2007-04-20 |
동 |
호주 |
부산 |
2007-04-22 |
니켈 |
남아프리카 |
부산 |
2007-04-29 |
납 |
인도 |
대구 |
2007-03-15 |
티탄 |
볼리비아 |
대구 |
2007-04-01 |
탄소강 |
칠레ㅔ |
대구 |
2007-04-24 |
탄소강 |
아르헨티나 |
대구 |
2007-05-02 |
마그네슘 |
칠레 |
대구 |
2007-05-10 |
티탄 |
타이 |
인천 |
200-05-10 |
아연 |
미국 |
인천 |
2007-05-28 |
주석 |
러시아 |
COUNT함수가 인수로 쓸 수 있는 열은 한개밖에 없다. COUNT(material, orgland)라고는 쓸 수 없을 것이다. 어떻게 하면 될까? 한개밖에 인수로 쓸 수 없다면 강제로 인수를 한개로 만들면 될 것이다.
SELECT center
--결과-- CENTER
--EXISTS를 사용하기 |
select distinct center |
TestResults테이블을 이용해 아래 문제의 쿼리를 작성해보자.
TestResults
student_id |
class |
sex |
score |
001 |
A |
남 |
100 |
002 |
A |
여 |
100 |
003 |
A |
여 |
49 |
004 |
A |
남 |
30 |
005 |
B |
여 |
100 |
006 |
B |
남 |
92 |
007 |
B |
남 |
80 |
008 |
B |
남 |
80 |
009 |
B |
여 |
10 |
010 |
C |
남 |
92 |
011 |
C |
남 |
80 |
012 |
C |
여 |
21 |
013 |
D |
여 |
100 |
014 |
D |
여 |
0 |
015 |
D |
여 |
0 |
Q1.클래스의 75%이상의 학생이 80점이상인 클래스를 선택하시오
SELECT class THEN 1 ELSE 0 END);
--결과-- CLASS |
Q2.50점 이상을 받은 학생 중, 남자수가 여자수보다 많은 클래스를 선택하시오
SELECT class
--결과-- CLASS -------- B C |
Q3. 여자의 평균점이 남자의 평균점보다 높은 클래스를 선택하시오.
SELECT class
--결과-- CLASS ------- A |
아래 테이블을 이용해서 수학이 80점 이상이고 국어가 50점 이상인 학생을 찾는 쿼리를 작성해보자.
TestScores
student_id |
subject |
score |
100 |
수학 |
100 |
100 |
국어 |
80 |
100 |
과학 |
80 |
200 |
수학 |
80 |
200 |
국어 |
95 |
300 |
수학 |
40 |
300 |
국어 |
90 |
300 |
사회 |
55 |
400 |
수학 |
80 |
SELECT student_id
--결과-- STUDENT_ID |
HAVING구를 사용함에 있어 포인트를 한마디로 얘기하라면 "무엇으로 집합이라고 가정할 것인지에 착목하라"는 것이다. SQL에 있어서 무엇을 집합으로 가정할 것인지의 기준은 집합을 이루는 것이 현실세계에서 어떤 레벨인지는 상관없고, 단지 테이블에서 어떻게 표현되는지만이 중요하다. 어떤 실체가 때에 따라서는 요소가 되기도 하고 집합이 되기도 하는 것이다. 실체 한개당 한행만이 할당된다면 이 실체는 집합의 요소로써 취급되고 있는 것이다. 이때는 조건을 지정할 때 WHERE구를 사용하면 된다. 한편 한개당 복수행이 할당된다면 집합으로 취급되고있다는 증거이다. 그렇다면 HAVING구를 사용하면 된다.
집합의 성질을 조사하기 위한 대표적인 조건을 정리해두자. 이 조건은 HAVING구 혹은 SELECT구의 CASE식에서 사용할 수 있다.
집합의 성질을 찾기 위한 조건의 사용법 일람
|
조건식 |
용도 |
1 |
COUNT(DISTINCT col) = COUNT(col) |
col값이 유일하다 |
2 |
COUNT(*) = COUNT(col) |
col에 NULL이 존재하지 않는다 |
3 |
COUNT(*) = MAX(col) |
col는 결번이 없는 연번(개시값은 1) |
4 |
COUNT(*) = MAX(col) - MIN(col) + 1 |
col는 결번이 없는 연번(개시값은 임의의 정수) |
5 |
MIN(col) = MAX(col) |
col가 한개만의 값을 가지던가 아니면 NULL이다 |
6 |
MIN(col) * MAX(col) > 0 |
모든 col_x의 기호가 동일하다 |
7 |
MIN(col) * MAX(col) < 0 |
최대값은 양수고 최소값은 음수이다 |
8 |
MIN(ABS(col)) = 0 |
col은 적어도 한개의 0를 포함한다 |
9 |
MIN(col - 정수 ) = -MAX(col - 정수) |
col의 최대값과 최소값은 지정한 정수에서 값은 간격으로 떨어져있다 |
[출처] SQL _ HAVING_2|작성자 미우
'먹고살기 > Oracle' 카테고리의 다른 글
SQL _ HAVING (0) | 2011.04.29 |
---|---|
SQL _ 상관서브쿼리 (0) | 2011.04.29 |
SQL _ CASE식 (0) | 2011.04.29 |
[Oracle] ROWNUM 사용 시 주의 (0) | 2011.04.25 |
오라클 데이터 타입 (0) | 2011.04.22 |
설정
트랙백
댓글
글
--단순CASE식--
CASE sex
WHEN '1' THEN '남'
WHEN '2' THEN '여'
ELSE '기타'
END
--검색CASE식--
CASE WHEN sex = '1' THEN '남'
WHEN sex = '2' THEN '여'
ELSE '기타' END
CASE식의 서식은 위와 같이 단순CASE식과 검색CASE식 두가지가 있다. 단순 CASE식은 이름 그대로 간결하게 쓸 수 있으나 비교조건 밖에 가능하지 못한 반면 검색 CASE식은 다양한 비교조건을 사용할 수 있다.
1.기존 코드체계를 새로운 체계로 변경하여 집계하기
PopTbl 집계결과
pref_name
population
지방명
인구
인천
100
경기
650
수원
200
→
경북
600
광명
150
기타
450
안양
200
대구
300
경주
100
포항
200
부산
400
제주
50
왼쪽 테이블의 도시별 인구를 집계하는 SQL을 만들어보자.
SELECT CASEpref_name
DISTRICT SUM(POPULATION) |
2.다른 조건의 집계를 하나의 SQL로 행하기
pref_name |
sex |
population |
지방명 |
남 |
여 | |
인천 |
1 |
60 |
인천 |
60 |
40 | |
인천 |
2 |
40 |
수원 |
100 |
100 | |
수원 |
1 |
100 |
광명 |
100 |
50 | |
수원 |
2 |
100 |
|
안양 |
100 |
100 |
광명 |
1 |
100 |
→ |
대구 |
100 |
200 |
광명 |
2 |
50 |
경주 |
20 |
80 | |
안양 |
1 |
100 |
포항 |
125 |
125 | |
안양 |
2 |
100 |
서울 |
250 |
150 | |
대구 |
1 |
100 |
||||
대구 |
2 |
200 |
||||
경주 |
1 |
20 |
||||
경주 |
2 |
80 |
||||
포항 |
1 |
125 |
||||
포항 |
2 |
125 |
||||
서울 |
1 |
250 |
||||
서울 |
2 |
150 |
|
SELECT pref_name,
PREF_NAME CNT_M CNT_F
|
3. 조건을 분지시킨 UPDATE
name |
salary |
영희 |
300000 |
순희 |
270000 |
민희 |
220000 |
원희 |
290000 |
위의 테이블에 대해, 다음과 같은 조건으로 변경시켜보자
1.현재의 급료가 30만이상인 사원은 10%삭감한다.
2.현재의 급료가 25만이상 28미만인 사원은 20%인상한다.
단순히 생각하면 다음과 같이 UPDATE문을 2번 실행하면 될 것 같지만 이는 맞지 않다.
--조건1. |
왜 이런 결과가 나올까? 예를 들어 현재 급료가 30만원인 사원의 경우 조건1의 UPDATE문에 의해 급료가 27만원으로 줄었다. 하지만 이것이 끝이 아니라 다음에 실행되는 조건2의 UPDATE문에 의해서 32만4000원으로 늘어나버리기 때문이다. 두가지 조건을 정확하게 반영하는 SQL문은 다음과 같다.
UPDATE Personnel |
위의 SQL뮨은 정확한데다 한번의 실행으로 해결되기 때문에 속도도 빨라진다.
4. 테이블 간의 매칭
DECODE함수등과 비료해서 CASE식의 최대 장점은 식을 평가가능하다는 것이다. 이말은 즉, CASE식 중에 BETWEEN,LIKE,<,>등을 사용할 수 있다는 말이다. 그 중에서도 IN 과EXISTS는 서브쿼리를 인수로 취하기 때문에 매우 강력한 표현력을 가진다.
CourseMaster OpenCourses
course_id |
course_name |
month |
course_id | |
1 |
피아노 |
200706 |
1 | |
2 |
태권도 |
200706 |
3 | |
3 |
미술 |
200706 |
4 | |
4 |
컴퓨터 |
200707 |
4 | |
200708 |
2 | |||
200708 |
4 | |||
위 테이블로 부터 다음과 같은 월별 개강 상태를 한눈에 알 수 있도록 표를 만들어보자.
COURSE_NAME 6월 7월 8월 |
이는 즉, OpenCourses의 어느 달에 CourseMaster테이블의 강좌가 존재하는지를 체크하는 것이다. 이 매칭의 조건을 CASE식으로 쓰는 것이 가능하다.
--IN 이용-- SELECT CM.course_name, --EXISTS 이용-- SELECT CM.course_name, |
IN 이나EXISTS 어느쪽을 써도 결과는 같지만 퍼포먼스면에서 EXISTS를 쓰는 편이 좋다. 서브쿼리에서 (month, course_id)라는 주키의 인덱스를 이용할 수 있기 때문에 특히나 OpenCourses테이블의 사이즈가 클 경우는 굉장히 우위에 서게 된다.
5.CASE식 중에 집약함수를 사용
std_id |
club_id |
club_name |
main_club_flg |
100 |
1 |
야구 |
Y |
100 |
2 |
기타 |
N |
200 |
2 |
기타 |
N |
200 |
3 |
배드민턴 |
Y |
200 |
4 |
축구 |
N |
300 |
4 |
축구 |
N |
400 |
5 |
수영 |
N |
500 |
6 |
바둑 |
N |
학생은 복수의 클럽에 소속되어있는 경우도 있으면 (100,200), 1개밖에 소속되지 않은 경우도 있다.(300,400,500). 복수의 클럽에 소속되어 있는 학생에 대해서는 주클럽이 어느것인지 나타내는 클럽열에 Y 혹은 N 의 값이 들어간다. 1개의 클럽에만 전념하는 학생은 N이 들어간다.
그럼, 위 테이블로부터 다음과 같은 조건으로 쿼리를 만든다.
1. 1개의 클럽에 소속된 학생에 대해서는 그 클럽의 ID를 취득한다.
2. 복수의 클럽에 소속된 학생에 대해서는 주요한 클럽의 ID를 취득한다.
단순히 생각하면 다음과 같은 두개의 조건에 대응하는 쿼리를 만들면 될 것이다.
--조건1 :1개의 클럽에 전념하는 학생을 선택-- select std_id, max(club_id) main_club
--조건2 : 복수 클럽에 소속되어 있는 학생을 선택-- select std_id, club_id main_club
|
이것으로도 조건에 만족하는 결과를 얻을 수 있지만 열에 의해 복수의 SQL이 필요하다. CASE식을 쓰면, 다음과 같은 한개의 SQL만으로 쓸 수 있다.
select std_id, STD_ID MAIN_CLUB |
CASE식 중에 집약함수를 써서, 거기다 그 안에 CASE식을 쓰는 어지러워보이는 네스트구조이지만 정리하자면 「한개 클럽에 전념하는가, 복수의 클럽에 소속되어 있는가」라는 조건분지를 CASE WHEN COUNT(*) _ 1 .....ELSE .....라는 CASE식으로 표현한 것이다. 이는 혁명적인 표현방법이다. 왜냐하면 우리가 처음 SQL입문을 배울 때 집계결과에 대한 조건은 HAVING구를 써서 설정한다고 배웠지만 CASE식을 쓰면 SELECT구에서도 동등 조건 분지를 쓸 수 있기 때문이다. 이 예문에서도 알 수 있듯이 CASE식은 SELECT구에서 집약함수 중에서도 밖에서도 쓸 수 있다. 이 자유도가 높은 점이 CASE식의 큰 매력이다.
------ 정리
SQL에서의 cASE식을 순차적언어의 CASE문에 연연해서 CASE「문」이라고 하는 경우가 있다. 하지만 정확히는 문이 아니라 1+1이나 a/b와 같은 식의 동료이다. 「문」과「식」의 차이는 기능의 방식의 차이를 반영하는 중요한 포이트이다. 식이기 때문에 CASE식은 실행시에는 평가되어져 하나의 값으로 결정되어지고 (그렇기 때문에 집약함수 중에 쓸 수 있다), 식이기 때문에 SELECT구에서도 GROUP BY구에서도 WHERE구에서도 ORDER BY구에서도 쓸 수 있는 것이다. 쉽게 말하면 CASE식은 열명이나 정수를 쓸 수 있는 장소에서는 언제든지 쓸 수 있다.
[출처] SQL _ CASE식|작성자 미우
'먹고살기 > Oracle' 카테고리의 다른 글
SQL _ 상관서브쿼리 (0) | 2011.04.29 |
---|---|
SQL _ HAVING_2 (0) | 2011.04.29 |
[Oracle] ROWNUM 사용 시 주의 (0) | 2011.04.25 |
오라클 데이터 타입 (0) | 2011.04.22 |
오라클 DECODE (0) | 2011.04.22 |
RECENT COMMENT