SQL언어를 통한 문장의 종류:
하나의 트랜잭션(TX)안에는, 한개 이상의 DML문장을 포함할 수 있다!!!!
TX Boundary(범위) -----------> BEGIN ~ END 문을 이용해서 만듦
TX unit#1 (한개의 DML문) ---> 성공
....
TX unit#100 ---> 실패
TCL : 시작된 하나의 TX를 완성
commit (영구적으로 저장소에 변경을 반영)
rollback (이전상태로, 모든 TX Unit의 변경을, 되돌린다!!!!)
하나의 TX를 처리하는 방식 ==> ALL or Nothing
계좌이체:
(1) 소스계좌에서 정해진 금액 인출
(2) 타겟계좌에 정해진 금액 입금
롤백(위의 2개 작업중에 하나라도 실패 ---> 이전상태로 되돌려야 함)
커밋(위의 2개 작업모두 성공하면 --> 이때라야, 이체거래를 완성시켜야 함)
-DML을 사용하면 트랜잭션이 발생함 (행에 대한 연산과정을 뜻함)
BEGIN,END가 하나의 트랜잭션을 만드는 명령어
트랜잭션안에는 수천 수백개의 DML을 포함할 수 있다.
-마구잡이 변경되면 참조무결성제약이 깨지니까
누가 먼저 DB에 접근했나를 따져서 lock 이라는 개념이 존재함.
한명의 트랜잭션이 끝나기까지 기다려야하는데
트랜잭션안에 DML이 잘 끝마쳤는지 부분으로 확인하는 것이 COMMIT 또는 ROLLBACK이다.
가. 테이블에 데이터를 저장하기 위한 문장.
나. 구분:
(1) 단일 행 INSERT문: 한 번에 하나의 행을 테이블에 저장
(2) 다중 행 INSERT문: 한 번에 여러 행을 테이블에 저장
다. 테이블에 새로운 레코드(행)이 삽입 됨.
라. INTO 절에 명시한 컬럼은, VALUES 절에서 지정한 컬럼값과
일대일 대응되도록, 순서대로 입력해야 함.
So, INTO 절에 명시된 컬럼과 VALUES 절에 명시된 값의
개수와 타입은 같아야 함.
마. INTO 절의 컬럼목록은 생략가능.
if 생략하면, 테이블 생성시 정의한 컬럼순서와 동일한 순서로
- 모든 컬럼값을 VALUES 절에 지정해야 한다.
바. 저장되는 데이터의 타입은, 컬럼의 데이터 타입과 일치해야 함
사. 저장되는 데이터의 크기는, 컬럼의 크기보다 같거나 작아야 함
아. 기본키(PK) 또는 UNIQUE컬럼은, 동일한 값을 저장할 수 없음.
자. INTO 절에서 생략된 컬럼은, 자동으로 널(NULL) 값이 저장됨.
따라서, NOT NULL 제약조건이 아닌 컬럼만 INTO절에서 생략가능.
: 한 번에 하나의 행을 테이블에 저장
-PK = UK + NOT NULL 부터 순서대로 값을 명시해서 넣어줘야함
-NULL값 지정은 명시적방법이 좋지만 너무 수가 많으면 묵시적으로 할 수도 있다.
BEGIN -- 트랜잭션의 시작
-- 컬럼명을 명시한 INSERT 문 (단일행 인서트문)
INSERT INTO dept (deptno, dname, loc) -- (어느컬럼에 지정해서 행을 넣을지 정하는 것)
VALUES (50, '개발', '서울'); -- 개수에 맞게 값을 넣어줌
-- 컬럼명을 생략한 INSERT 문
--INSERT 수행시, "컬럼선언부"를 생략하면,
--반드시, 해당 테이블의 스키마에 나온 컬럼의 순서대로 값을 준비해야 함
INSERT INTO dept --이렇게 하지말라!
VALUES (60, '인사', '경기');
-- 묵시적으로 널(null) 값 저장
-- 1) 묵시적 방법(Implicitly)
INSERT INTO dept (deptno, dname) -- 두개의 컬럼에 넣자!
VALUES (70, '인사'); -- 이 값을
-- 명시적으로 널(null) 값 저장:
-- 2) 명시적 방법(Explicitly)
INSERT INTO dept (deptno, dname, loc)
VALUES (80, '인사', NULL);
-- ROLLBACK;
COMMIT;
END; -- To end a transaction
-오류문장 수행에 대해 (+롤백과 커밋)
SHOW AUTOCOMMIT; --> 오토커밋이 켜져있는지 확인
SET AUTOCOMMIT ON; --> 오토커밋을 켠다. / on 대신 off 적으면 끈다
ㄱ) INTO 절에 명시된 컬럼의 갯수와 VALUES 절에 명시된 값의 개수가 틀린 경우
INSERT INTO dept (deptno, dname, loc)
VALUES (11, '인사'); -- ORA-00947: not enough values 값이 모자라다는 오류
ㄴ) INTO 절에서 컬럼목록을 생략한 경우: VALUES절에서 테이블의 모든 컬럼값을 누락하지 말아야 함.
INSERT INTO dept
VALUES (12, '인사'); -- ORA-00947: not enough values
ㄷ) INTO 절의 컬럼 데이터 타입과 VALUES 절의 값의 데이터 타입이 일치하지 않는 경우
INSERT INTO dept (deptno, dname, loc)
VALUES ('개발', 13, '인사'); -- ORA-01722: invalid number
ㄹ) VALUES 절의 컬럼값 지정시, 반드시 리터럴 형식에 맞게 설정해야 함;
-- ------------------------------------------------------
-- * 리터럴(Literal) 규칙:
-- ------------------------------------------------------
-- a. 문자와 날짜 리터럴: 반드시, '' 로 묶어야 함.
-- 만일, ''를 누락하면, 리터럴(값)이 아닌, 식별자로 인식
-- b. 수치 리터럴: '' 없이 사용해야 함.
-- ------------------------------------------------------
INSERT INTO dept (deptno, dname, loc)
VALUES ('개발', 14, 인사); -- ORA-00984: column not allowed here
: 한 번에 여러 행을 테이블에 저장
INSERT + Subquery = 인서트셀렉트문 이라고 부름
가. 하나의 INSERT 문장으로, 한번에 여러 행 저장
나. VALUES 절 대신에, 서브쿼리(= 부속질의) 사용
다. 서브쿼리를 사용하여, 기존 테이블의 데이터를 복사한 후에,
INSERT 문으로 새로운 행 생성.
라. (*주의할 점*)
INTO 절에서 지정한 컬럼의 개수와 타입에 맞추어,
서브쿼리의 수행결과가 반드시 동일해야 함.
ㄱ) 기존 테이블을 이용하여, 새로운 테이블 생성 (CTAS)
CTAS: 기존 테이블 스키마 복사 시, NOT NULL 제약조건을 제외한, 그 외 제약조건은 복사되지 않음. -(완전하게 복사는 되지않는다. / 복사된 모든 값들은 기본적으로 NULL을 허용되게 되어있다 .)
예시)
CREATE TABLE 테이블명 [(컬럼명,컬럼명2)]
AS
Subquery;
CREATE TABLE mydept
AS
SELECT * FROM dept
WHERE 1 = 2; -- 기존 테이블의 스키마만 복사(데이터 제외) /false
DESC mydept;
ㄴ) 복수 행 INSERT 문 수행
( 실험용 복제데이터를 빠르게 넣을 때 많이 사용 )
PK 등 제약조건은 복사가 되지 않기 때문에 중복확인 안된다. 따라서 계속 데이터가 삽입된다.
INSERT INTO mydept -- 컬럼선언부 생략
SELECT
deptno,
dname,
loc
FROM
dept;
SELECT
*
FROM
mydept;
ORDER BY
가. 하나의 INSERT 문장으로, 한번에 한 개 이상의 테이블에,
여러 개의 행을 저장하는 문장.
나. INSERT ALL 문장이라고 부름.
다. 서브쿼리의 실행결과가 INTO절에 지정한 테이블(1..N)에
자동으로 INSERT 됨.
라. ** WHEN 절은 생략가능 ** (= 무조건 INSERT ALL 문)
마. WHEN절이 있는 경우, 조건식이 참일 때에만, 지정된 테이블에
서브쿼리의 결과가 INSERT 됨.
(이땐, "조건 INSERT ALL 문" 이라고 부름)
바. (**주의사항**) VALUES 절에 사용된 컬럼명과 Subquery에서
사용된 컬럼명이 반드시 동일해야 함.
사. 구분:
(1) 무조건 INSERT ALL문 : WHEN 절이 생략된 경우.
(2) 조건 INSERT ALL문 :
WHEN 절의 조건식의 참일 경우에만, INSERT 수행.
여러 WHEN 절이 중복되어 참인 경우에는,
각 테이블에 모두 해당 행이 INSERT 됨.
(3) 조건 INSERT FIRST문 :
WHEN 절에 지정된 조건이 중복되어 참인 경우에,
처음조건에 일치하는 테이블에만 해당 행이 저장되고,
이후 조건이 일치해도, 해당 테이블에 저장하지 않는 문장.
ㄱ)기존 테이블을 이용하여, 새로운 테이블 생성 (CTAS)
DROP TABLE myemp_hire;
CREATE TABLE myemp_hire AS -- 1st. Table creation.
SELECT
empno,
ename,
hiredate,
sal
FROM
emp
WHERE
1 = 2; -- 기존 테이블의 스키마만 복사(데이터 제외)
DESC myemp_hire;
-- ------------------------------------------------------
DROP TABLE myemp_mgr;
CREATE TABLE myemp_mgr AS -- 2nd. Table creation.
SELECT
empno,
ename,
mgr
FROM
emp
WHERE
1 = 2; -- 기존 테이블의 스키마만 복사(데이터 제외)
DESC myemp_mgr;
ㄴ)무조건 INSERT ALL 문장 수행
INSERT ALL
INTO myemp_hire VALUES (empno, ename, hiredate, sal)
INTO myemp_mgr VALUES (empno, ename, mgr)
SELECT
empno,
ename,
hiredate,
sal,
mgr
FROM
emp;
INTO 절하나마다 WHEN절이 하나 나올 수 있다.
ㄱ)기존 테이블을 이용하여, 새로운 테이블 생성 (CTAS)
DROP TABLE myemp_hire2;
CREATE TABLE myemp_hire2 AS -- 1st. Table creation.
SELECT
empno,
ename,
hiredate,
sal
FROM
emp
WHERE
1 = 2; -- 기존 테이블의 스키마만 복사(데이터 제외)
DESC myemp_hire2;
-- ------------------------------------------------------
DROP TABLE myemp_mgr2;
CREATE TABLE myemp_mgr2 AS -- 2nd. Table creation.
SELECT
empno,
ename,
mgr
FROM
emp
WHERE
1 = 2; -- 기존 테이블의 스키마만 복사(데이터 제외)
DESC myemp_mgr2;
ㄴ)조건 INSERT ALL 문장 수행
INSERT ALL
WHEN sal > 3000 THEN --조건에 충족하는 테이블의 행만 넣겠다.
INTO myemp_hire2 VALUES (empno, ename, hiredate, sal)
WHEN mgr = 7698 THEN
INTO myemp_mgr2 VALUES (empno,ename,mgr)
SELECT
empno,
ename,
hiredate,
sal,
mgr
FROM
emp;
여러개 조건을 만족을 시킨다하더라도 가장 처음 WHEN 절을 만족하는 테이블에만 값을 넣는다.
ㄱ) 기존 테이블을 이용하여, 새로운 테이블 생성 (CTAS)
1.재료 테이블
DROP TABLE myemp_hire3;
CREATE TABLE myemp_hire3 AS -- 1st. Table creation.
SELECT
empno,
ename,
hiredate,
sal
FROM
emp
WHERE
1 = 2; -- 기존 테이블의 스키마만 복사(데이터 제외)
DESC myemp_hire3;
-- ------------------------------------------------------
DROP TABLE myemp_mgr3;
CREATE TABLE myemp_mgr3 AS -- 2nd. Table creation.
SELECT
empno,
ename,
mgr
FROM
emp
WHERE
1 = 2; -- 기존 테이블의 스키마만 복사(데이터 제외)
DESC myemp_mgr3;
ㄴ)조건 INSERT FIRST 문장 수행
INSERT FIRST
-- sal = 800 인 사원은, 아래 두 WHEN 절의 조건식을 모두 만족.
-- 이때, 첫번째 WHEN절에서만 INSERT가 수행되고,
-- 두번째 WHEN절은 설령 조건이 참이어도, INSERT 수행되지 않음.
WHEN sal = 800 THEN -- 1st. condition
INTO myemp_hire3 VALUES (empno, ename, hiredate, sal)
WHEN sal < 2500 THEN -- 2nd. condition
INTO myemp_mgr3 VALUES (empno, ename, mgr)
SELECT
empno,
ename,
hiredate,
sal,
mgr
FROM
emp;
유일한 주의점: UPDATE문과 DELETE문은 형태가 같아 WHERE절을 빼먹고 모든 데이터를 지우거나 업데이트 시키는 실수를 저지를 수도 있다.
가. 테이블에 저장된 데이터 수정.
나. 한 번 수행으로, 여러 개의 행들을 수정할 수 있음.
다. WHERE 절은 *생략가능* (일반적이지 않음)
이 경우엔, 해당 테이블의 모든 데이터가 수정됨.
ㄱ)기본문법
UPDATE 테이블명 -- 변경(수정)할 테이블명 지정.
SET -- 변경할 한개 이상의 컬럼명=값 형식 지정
컬럼명1 = 변경값1,
[컬럼명2 = 변경값2],
...
[컬럼명n = 변경값n]
[WHERE 조건식];
UPDATE mydept
SET
dname = '영업',
loc = '경기'
WHERE
deptno = 40;
ㄴ) 서브쿼리(=부속질의)를 이용한 UPDATE 문
가. UPDATE의 SET 절에서 서브쿼리를 이용하면, 서브쿼리의 실행
결과값으로, 테이블 수정가능.
나. 이 문장으로, 기존 다른 테이블의 데이터를 이용하여, 혀재
지정 테이블의 특정 컬럼값의 변경이 가능.
-스칼라 값이 들어감을 알아야함!
-- 서브쿼리를 사용한 UPDATE 문 실행
UPDATE mydept
SET
dname = (SELECT dname FROM dept WHERE deptno = 10), -- 스칼라 X 스칼라
loc = (SELECT loc FROM dept WHERE deptno = 20)
WHERE
deptno = 40;
특징
1)인덱스로 관리
2)중복해서 객체로 저장하능
1)ArrayList
2)Vector
인접 참조를 링크해서 체인처럼 관리
특정 인덱스에서 객체를 제거하거나 추가하게 되면 바로 앞뒤 링크만 변경
빈번한 객체 삭제와 삽입이 일어나는 곳에서는 ArrayList보다 좋은 성능
대신 검색에 시간이 더 걸림
public class LinkedLIstEx {
public static void main(String[] args) {
//ArrayList에 새로운 요소를 목록의 가장 처음위치(인덱스 0번)에
//계속 넣을 때의 소요시간을 측정하자!!
List<String> list1 = new ArrayList<>();
long startTime;
long endTime;
// ---
startTime = System.nanoTime();
for(int i=0; i<10000; i++) {
list1.add(0, String.valueOf(i));
}//for
endTime = System.nanoTime();
double i1= endTime-startTime;
System.out.println("ArrayList: "+(endTime-startTime)+"나노초 걸렸습니다.");
//----------------
List<String> list2 = new LinkedList<>();
startTime = System.nanoTime();
for(int i=0; i<100000; i++) {
list2.add(0, String.valueOf(i));
}//for
endTime = System.nanoTime();
double i2= endTime-startTime;
System.out.println("LinkedList: "+(endTime-startTime)+"나노초 걸렸습니다." );
}// main
}// end class
저장 순서가 유지되지 않음
중복 저장 안된다.(하나의 null만 저장 가능,객체를 중복 저장 불가 )
객체의 같음과 다름은 주소인 메모리, hashcode OID가 아니라 비즈니스 관점에서 이해해야한다.
ex)
회원1(name=NAME_1,ID=100)
회원2(name=NAME_1,ID=100)
위 객체는
같은 사람이기 때문에 같은거다 .
관점에 따라서 다르다.
따라서
회원을 어떻게 해쉬코드를 짜야 할까? 이를 고민해라
ex) 간단한 예시
@EqualsAndHashCode
public class Student22 {
// 1. 중복판단 알고리즘 :학번
// 2. sno + name + age 모두 같으면 중복으로 판단!
private int sno;
private String name;
private int age;
}//end class
@EqualsAndHashCode
@ToString
public class Member {
public String name;
public int age;
public Member(String name, int age) {
this.name = name;
this.age = age;
}// Member
public boolean equals(Object obj) {
if(obj instanceof Member) {
Member member = (Member) obj;
return member.name.equals(name) && (member.age==age) ;
} else {
return false;
}
}// equals
public int hashCode() {
return name.hashCode() + age;
}// hashcode
}// end class
public class HashSetEx {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Java");
set.add("JDBC");
set.add("Servlet/JSP");
set.add("Java");
set.add("iBATIS");
System.out.println(set);
// 결과:[Java, JDBC, Servlet/JSP, iBATIS] --> 중복이 제거되었다.
}// main
}// end class
public class HashSetEx2 {
public static void main(String[] args) {
Set<Member> set = new HashSet<>();
set.add(new Member("홍길동",30));
set.add(new Member("홍길동",30));
System.out.println(set);
//결과값:[Member(name=홍길동, age=30)]
//멤버객체 해쉬코드 오버라이딩 제거하면
// 결과값: [Member(name=홍길동, age=30)][Member(name=홍길동, age=30)] 2개
//HashCode 오버라이딩으로 비즈니스 기준안맞추면 이상하게 작동함
}// main
}// class
키와 값의 쌍으로 저장
키는 중복 저장이 안된다.