셋 set (중복을 허용하지 않는 집합)

합집합, 교집합 , 차집합

 

채널을 구독할때 중복 구독되지 않도록 할때 유용

 

sadd

sinter

srem

 

추가가 되면 1 이 되고 이미 추가가 되어 있다면 0이 된다

이때 는 faker:gudok 이 되고 abc가  member 가 된다

 

 

sinter 로 faker:gudok 를 통해 읽어오면 member 인  abc 를 얻어올 수 있다

 

 

abc1 과 abc2 를 추가한뒤 sinter 로 값을 보면 정렬되어 있진 않고 중복 없는 값이 들어간걸 알 수 있다

 

 

삭제는 srem 으로 삭제 할수 있다

 

 

 

 

 

 

정렬된 Set

 

zadd, zrange 로 다음 처럼 정렬된 랭킹 정보를 구할 수도 있다

 

zadd 할때 중간에 숫자를 꼭 넣어줘야 한다, 이 숫자로 정렬된다

 

127.0.0.1:6379> zadd test:ranking 300 book
(integer) 1
127.0.0.1:6379> zadd test:ranking 200 store
(integer) 1
127.0.0.1:6379> zadd test:ranking 700 board
(integer) 1
127.0.0.1:6379> zrange test:ranking 0 10
1) "store"
2) "book"
3) "board"
127.0.0.1:6379>

 

숫자값에의해 정렬된것을 알 수 있다

 

 

리트스의 경우

lpush, rpush, lrange, lpop, rpop 등의 명령어가 있고

lrange key 0 -1 을 쓰면 전체 리스트 내용을 볼 수 있다

 

 

 

 

해시 (해시 기반)

hset :  다음 순으로 데이터를 넣게 된다

key 는 전체 카테고리 key 이고 field 와 value 가  <key, value> 가 된다

 

hget

hlen : 개수가 몇개인지

hdel : 삭제

hgetall : 모든데이터 보기

 

 

 

다음은 한번에 다른 필드로 여러 항목을 추갛 ㅏ는 방식을 보여준다

 

 

REF : 

http://redisgate.kr/redis/command/zadd.php

https://redis.io/commands/sinter/

반응형

https://github.com/tporadowski/redis/releases

 

Releases · tporadowski/redis

Native port of Redis for Windows. Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported: Strings, Lists, Sets, Sorted Se...

github.com

.zip 압축을 풀고 sever 를 실행시킨다음 cli.exe 로 클라이언트에서 테스트 해볼 수 있다

 

 

서버

 

클라 기본 상태

 

key1 으로 값 hello world를 저장

 

 

get 으로 가져올 수 있다

 

즉 이렇게 메모리상에 들고 있게 되는 것이다

 

 

서버를 끄고 get 을 요청하면 아무 일도 일어나지 않게 된다, 데이터도 역시 날라가게 된다

 

 

다시 서버를 키고 get 을 해보면 nil 이 나온다

 

set user:name "abc"

 

get user:name

"abc"

 

이렇게 나오고

append user:name " is good"

get user:name

"abc  is good"

 

이 된다

 

 

incr : 11은 문자인데 문자를 숫자로 인식하여 1을 증가한다음 12로 찍는 명령어

 

 

mset, mget  : 여러개를 설정하거나 가져올 수 있는 것

 

 

기존 키 값을 set 으로 다시 쓰게 되면 덮어써지게 된다

 

 

ttl : 유효 시간이 얼만나 남았는지 확인, -1 , 이면 무한대를 말한다

expire : 유효시간 설정

 

 

 

유효시간을 설정하고 ttl 을 호출하면 남은 시간을 볼 수 있다

 

서버에서 세션에 대한 정보를 DB 에서도 처리 할 수 있다

먼저 ID 와 pw 가 맞는지는 웹서버에서 검증한다 그리고 이 유저가 맞는지는 DB 를 통해서 인증을 거치는데

인증을 통과했다면 인증 받은 사람이라는 토큰을 클라에게 전달해준다

 

username:세션ID 를 하나의 컬럼에 설정한다음 유효시간을 별도로 설정한다

세션 id 가 존재하는지에 대해선 username 의 세션 ID를 확인하여 존재하는 유저인지 알 수 있고

관계형 DB 에선 이렇게 username 의 세션 ID를 클라에게 던져주는 형태가 된다

즉 클라가 서버에 다시 뭔가 할때 세션ID를 던진다

 

이렇게 되면 매번 서버와 DB 를 왔다갔다 하며 유효시간을 별도로 설정해줘야 한다는 것등의 별도의작업 및

불필요한 비용이 발생 할 수 있다 어차피 세션 ID가 서버에선 유효한 값 이므로
(클라에서 변조된것인지 서버에서만 판단해 주면 됨으로) 이때 redis 가 좋은대안이 될 수 있다

 

 

 

 

반응형

관계형 DB 는 B-Tree 기반으로 이뤄지고

데이터가 엄청 많아지면(1억 단위를 넘어간다면) 느려진다는 단점이 있다

MMORPG 는 대부분 1억 단위인 빅데이터 단위로 넘어가지 않는다 

그리고 한 서버군마다 동접이 5000 명에서 10000명이다

 

그런데 만약 데이터간의 관계가 떨어져서 Key-Value 로 관리 해도 무리가 없다면 NO-SQL 형태를 고려해 볼 수 있다

Hash 를 떠올리면 된다

그리고 Value 에는 문자열, 리스트, 셋, 정렬된 셋, 해시를 넣을 수 있다

 

그리고 NO-SQL 은 In memory 방식으로 전원을 끄면 데이터를 날라가는 방식이다

 

 

중요한 데이터는 관계형 DB 로 저장하고 휘발성인 랭킹 같은것들은 redis 로 사용 하는 것을 검토해 볼 수 있다

Redis 는 기본적으로 Linux 에서 돌아간다 (개발 단계에서 window 에서 돌릴 수는 있다)

 

대규모 게임이 아닌 소규모에서 redis 윈도우를 사용하거나

윈도우환경에선 redis 대용으로 나오는 memuria 를 고려해볼만 하다

 

https://www.memurai.com/

 

Redis for Windows alternative, In-Memory Datastore | Memurai

" Migrating from a legacy hardware and software system to the Microsoft stack was an interesting journey. Our in-house developers are well versed and trained on Windows, .NET, Azure and other tools available for the Microsoft ecosystem. We explored several

www.memurai.com

 

반응형

Read 에서 전반적인 흐름은 유저가 요청을 하면 서버에서 데이터 베이스에 자료를 요청하고 데이터베이스는 큰 램에서 데이터가 있다면 리턴 그렇지 않다면 하드에서 읽어 리턴하는 형식이 된다

 

노란색이 유저이고 데이터 read 요청을 한다면 노란색 박스인 램 즉 하드에서 미리 올려놓은 램에서 보고 데이터가 있다면 리턴하고 그렇지 않다면 하드에서 읽어들여온다 

만약 램이 다 차면 LRU 방식 등으로 날린다

LRU 알고리즘 : 가장 오랫동안 참조되지 않은 페이지를 교체하는 기법

 

램엔 데이터뿐만 아니라 인덱스 또한 올려 놓게되어 빠른 처리를 하는데 돕게 된다

 

 

 

 

쓸때는 쓰는 스레드를 빽단에서 돌려 별도로 쓰게 하여 하드로 접근하여 데이터를 다 쓸때까지의 대기 시간을 줄이는 방식이다

 

유저가 서버에 요청하면

SQL 파싱 처리후 DB 에 쓰기 명령 을 보낸다

데이터베이스에서 빽그라운드에서 쓰기를 처리한다

 

 

락의 종류

 

 

shared 는 read_write rock 을 말한다 : 읽을때는 동시에 동기화 부하 없이 읽다가 

쓸때는 한번에 하나만 처리 되는 방식이다, 다른 스레드는 진입 불가

 

Exclusive 는 mutex 같은 것이라 생각하면 된다

 

Update 락은 shared, exlusive 준간 정도로 처음엔 shared 로 동작하다가 상황에 따라 Exclusive 로 동작하는 락이다

 

 

row 에 가까워 질 수록 락 범위가 작아지고 윗단에서 잡을 수록 전반적으로 느려지고 자원소모가 덜해지는 경향을 보인다

ex ) row 를 몇백개 잡는 일이 발생한다면 Page 단에서 lock 을 잡는 것이 더 빠를 수 도 있다 => 하지만 어차피 데이터베이스에서 알아서 처리한다

 

 

 

트랜잭션 특징 ACID

 

1,4번이 중요함

 

원자성 : 만약 두개의 정보를 동시에 변경 해야 할때 한개만 변경되고 완료 처리가 되면 안된다는 것

 

지속성 : 물리적인 장애로 문제가 발생해도 저장해야 하는데, 만약 데이터 저장이 실패하면 롤백해야함

=> DB 에서 어떤 작업을 할때 항상 로그를 남긴다 => 이 로그를 통해 정전이 일어나서 중간 과정이 날라갔다 하더라도 로그로 기록은 남아 있기 때문에 해당 부분의 작업을 되살리거나 되돌릴 수 있다

 

 

 

 

반응형

'서버(Server) > DB' 카테고리의 다른 글

redis (2) 설치 와 기본 사용법과 컨셉  (0) 2023.04.05
NOSQL - Redis (1)  (0) 2023.04.04
[MSSQL] 예상 실행계획  (0) 2023.04.02
Clustered(바로 찾기), Non-Clustered (경유해서 찾기)  (0) 2023.03.03
DB : 복합 인덱스  (0) 2023.03.02

% 가 클 수록 시간이 더 걸린다는 것임으로 큰 쪽의 % 를 낮추는 작업을 해주면 된다

 

CTRL + M 으로 실행계획을 볼 수 있다

 

 

 

ref : https://m.blog.naver.com/seek316/222306507699

반응형

Clustered 는 Leaf Page 에 데이터가 들어가고 이전까지 보던 방식
Non-Clustered 같은 경우는 RID 를 통해 한번 경유하여 데이터를 저장하는 방식이다

Clustered 영한사전 , Non-Clustered 색인

Clustered : 실제로 논리적으로 정렬 되는 데이터 순서가 키 값 정렬 순서가 된다
Leaf Page = Data Page 끝 노드에 실제 데이터가 들어가는 형태
    데이터는 clustered index 키 순서로 정렬

 

 Non-Clustered 는 clustered index 유무에 따라서 다르게 동작한다

  1.  Non-Clustered 인데 clustered index 가 없는 경우(추가 안한 경우)
    leaf page 에는 heap table 에 대한 heap rid가 존재하여 이 rid 로 -> Heap table 에 접근 데이터 얻어온다
    >  heap rid = Heap table 에서 어느 주소에 몇번째 슬롯에 데이터가 있는지를 알 수 있는 RID
    >  데이터는 heap table 이 있고 이곳에 데이터들이 저장된다
        (즉 leaf Page 가 인덱스 페이지가 아니고 데이터 페이지가 아니라는 얘기)

  2. Non-Clustered 가 키가 있는데 이때  clustered index 를 추가 하게 되면
    heap table 이 없고 leaf page 에 데이터가 있는 상태이다 => leaf table 에 실제 데이터가 있게된다
    > heap table 이 없는 대신에 Clustered Index 의 실제 데이터 키 값을 들고 있게 된다, 이  키 값을 통해 cluster page 에서 데이터를 찾게 된다
    > Non clustered 에서 먼저 트리를 통해서 자식 중에서 cluster id에 를 찾고 이 id를 통해 cluster index 가 이루고 있는 트리 부모로 가서 여기서 다시 id 를 찾는 형태가 된다
    Non-Clustered  가 기존에 있을때 clustered index 를 추가 하면 기존에 Non-Clustered 도 영향을 주어 한단계 더 찾게 된다

 

 

기존 테이블을 지우고 테이블을 새로 하나 만든 다음
non clustered index 를 생성 하여 테스트

select *
into TestORderDetails 
from [Order Details];

select *
from TestORderDetails;


--non clustered index 를 생성
create index Index_OrderDetails
ON TestOrderDetails(orderID, ProductID);


--TestORderDetails 테이블에 있는 인덱스 정보 보기
exec sp_helpindex 'TestORderDetails';

 

TestORderDetails 테이블에 있는 인덱스 정보는 다음과 같다는걸 알 수 있다

 

 

인덱스 번호를 찾아 보려면 다음 처럼 작성하면 된다

sys.indexes 에서 오브젝트 id 를 비교하여 TestORderDetails 오브젝트 id 롸 같은 오브젝트의 index_id 들을 가져올 수 있다

select index_id, name
from sys.indexes
where object_id = object_id('TestORderDetails');

 

 

TestORderDetails 의 index_id 는 2 번이고 2 번으로 인덱스를 담고 있는 인덱스 페이지들을  볼 수 있다

--Index_OrderDetails Index_id 가 2 임으로 2를 인저로 넣어 페이지들을 보기
DBCC IND('Northwind', 'TestORderDetails', 2);

1048 이 root 고 나머지가 자식으로 들어간 걸 indexLevel 을 통해 알 수 있다

 

                              1048 

1008  1016  1017  1018  1019  1020

 

이 중에서 1008 페이지 정보를 보면 

--페이지 정보 보기
DBCC PAGE('Northwind', 1 , 1008, 3);

이 처럼 HEAP RID 가 있는 것을 알 수 있다 (index 를 non clustered index 로 생성했기 때문)

 

Heap RID = ([페이지 주소(4)[파일ID(2)[슬롯(2)] ROW)  의 바이트들로 구성 되는데이 ID 를 통해 Heap Table 테이블에서

Heap Table = [{page} {page} {page} {page}

 

몇번째 페이지 몇번 슬롯으로 되어 있는지를 Heap RID가 가리키고 있기 때문에

1008  에서 Heap RID 를 통해서 Heap Table 에 있는 데이터를 바로 검색해 찾을 수 있게 된다

 

 

DBCC  로 페이지 정보를 볼때 나오는 PageType 은 

  • 1 : Data Page
  • 2 : Index Page

를 나타낸다

 

 

 

 

현재 까지 상황은 

NonClusted Index 가 추가 된 상황이고  여기서  Clustered index 를 추가 해보면

-- clustered index 추가
create clustered index Index_OrderDetails_Clustered
ON TestOrderDetails(orderID);

이렇게 추가 된것을 볼 수 있다

 

이때 다시 2번 Non Clustered index 를 살펴보면 어떻게 달라져는지를 보면

 

cluster index 추가 하기 전
cluster index 추가 한후

 

 

페이지 번호가 바뀐 것을 알 수 있다

기존에는 

                              1048 

1008  1016  1017  1018  1019  1020

 

이런 번호였지만

1024 부터 자식이 시작 하는 걸 알 수 있는데 clustered index 를 추가 하게 되면 

 

                             1072

1024  1032  1033  1034  1035  1036

 

로 바뀌었다, 이때 1024 페이지 정보를 보면 

--페이지 정보 보기
DBCC PAGE('Northwind', 1 , 1024, 3);

원래는 Heap Rid 가 기존엔 있었지만 clustered index  를 추가하여 Heap Rid 가 없어진 것을 알 수 있다

 

그리고 페이지 id 가 전과 후가 달라진 것도 이전엔 Heap Rid로 heap table 을 찾는 형식이였지만

이젠 직접적으로 찾게 되니 PagePid 또한 달라지게 된 것

 

clustered index 를 생성할때 OrderID 에 대해 만들었는데

중복된 OrderID 를 볼 수 있는데 이것은 같은데이터에 한하여 동일한 ID 가 붙는 것이고 동일한 데이터를 구분하기 위하여

UNIQUIFIER 필드가 추가 되어 이들을 구분하게 끔 되어 있다

 

OrderID + UNIQUIFIER 조합으로 식별한다

 

 

정리하자면 Non clustered index 에서 Clustered index 를 추가 하면 기존 Heap RID 가 날라가게 된다는 것이다

 

 

 

 

위에서 본건 Non clusteered 인덱스 가 있었던건 본것이였는데

이번엔 그에 반해 위에서 새로 추가 했던 clustered 를 보면

--TestORderDetails 테이블에 있는 Index_id 보기
select index_id, name
from sys.indexes
where object_id = object_id('TestORderDetails');

 

테이블에 있는 인덱스 중에서 인덱스 1번은 검색

--Index_OrderDetails Index_id 가 2 임으로 2를 인저로 넣어 페이지들을 보기
DBCC IND('Northwind', 'TestORderDetails', 1);

 

 

                                                  9184

9144  9152  9153  9154  9155  9156  9157  9158  9159  9160

이렇게 구성 되어 있다 즉 여기서 알수 있는건 

 

DBCC  로 페이지 정보를 볼때 나오는 PageType 

  • 1 : Data Page
  • 2 : Index Page

였기 때문에 PageType 을 보면 PagePID 가 갖고 있는것이 바로 데이터 페이지가 된다는 걸 알수 있다

 

 

 

 

정리하자면

  • Clustered index 있으면 leaf  page 가 바로 데이터가 되는것이고, Heap Table 또한 없다
  • Clustered index 가 없다면 Heap RID로 Heap Table 을 검색해서 데이터를 찾는 한번 경유하는 형태가 된다는 것이다
    이때는 Heap Table 또한 생성되게 된다

 

 

반응형

'서버(Server) > DB' 카테고리의 다른 글

[DB] 쓰기와 읽기, 스래드와 캐시 & 대기와 락, 트랜잭션  (0) 2023.04.03
[MSSQL] 예상 실행계획  (0) 2023.04.02
DB : 복합 인덱스  (0) 2023.03.02
DB : INDEX  (0) 2023.03.01
DB : 윈도우함수  (0) 2023.02.28

 

use Northwind;



SELECT *
FROM [Order Details]
ORDER BY OrderID;


select *
into TestORderDetails 
from [Order Details];


select *
from TestORderDetails;


--복합 인덱스 추가
create index Index_TestOrderDetails
ON TestOrderDetails(orderID, ProductID);


--인덱스 정보 보기
exec sp_helpindex 'TestORderDetails';


--Index Seek 이건 인덱스를 활용해 빨리 찾는 것인데
--Index Scan 은 Index Full Scan 으로 전체 다 찾는 거라 느리다
--아래 처럼 and 를 쓰면서 인덱스통하여 검색을 하면 Index Seek 가 일어난 다는 걸 알 수 있다
select *
from TestORderDetails
where OrderID  = 10248 and ProductID = 11;



--index seek 으로 검색
select *
from TestORderDetails
where OrderID  = 10248;



--table scan 으로 찾음
--이유는 ON TestOrderDetails(orderID, ProductID) 이렇게 생성했을대 orderID 가 첫번째에 있었기 때문에
--orderID 로 찾기를 시작할땐 index seek 로 1차적으로 찾는데 
--그렇지 않으면 ProductID 로 찾게 되면 2차적으로 정렬하여 table scan 으로 찾게 된다
select *
from TestORderDetails
where ProductID  = 10248;


--index 정보 보기
DBCC IND('Northwind', 'TestORderDetails', 2);

DBCC PAGE('Northwind', 1 , 9160, 3);

 

 

 


복합 인덱스를 두개에대해 추가(orderID, ProductID) 했다
create index Index_TestOrderDetails
ON TestOrderDetails(orderID, ProductID);

 

이렇게 하면 데이터를 찾을때 성능에 대한 차이가 발생 하는 이유는 데이터를 정렬 하는데 있어서 차이가 있어서 그런것인데 인덱스가 두개라서 어떻게 검색에 대한 처리를 하는지 보면 

 

 

 

--index 정보 보기
DBCC IND('Northwind', 'TestORderDetails', 2);

9200이 가장 상단이고 나머지는 모두 자식 즉 Leaf 노드 인 것을 알 수 있다(IndexLevel 이 0 임으로)

 

Leaf 노드의 순서가 트리상 동일한 레벨에서 9168 -> 9169 -> 9170->  이런 순으로 나가기 때문에

9160에 대한 노드 정보를 보면

 

OrderID 와  ProductID 두개를 보면 우선 OrderID 로 정렬을 하는데 만약 같은 ID 라면 그다음 ProductID로 비교하는 걸 알 수있다 

 

OrderID 는 정렬이 되어 있는 반면 ProductID 는 첫번째 것을 기준으로 정렬 되어 있어서

바로 ProductID로 찾으려 하면 정렬이 안되어 있는것과 마찬가지 임으로

ProductID 로 검색 기준을 삼으면 Scan 이 되는 것 => 느림

 

 

인덱스(A, B) 를 글었다면 인덱스 A 에 대해 따로 인덱스를 걸어줄 필요는 없는데

B로도 검색이 필요하다면 인덱스(B) 에 대해 별도로 걸어줘야 빨라지게 된다

주의 : A,B 둘다 인덱스가 독립적으로 걸려있는게 아니다

 

 

 


페이지 분할(SPLIT) : 정리하면 인덱스를 생성하면 원소들이 페이지 단위로 관리 되는데 이 페이지 단위마다 관리 개수를 넘어가면 추가 페이지를 만들어 원소들을 관리하는 구조가 된다

 

데이터 50개 강제로 추가 해보면
인덱스 데이터 추가 /갱신/ 삭제시 그 중에서 추가 하는 경우를 보자

DECLARE @i INT = 0;
WHILE @i < 50
BEGIN
INSERT INTO TestORderDetails
VALUES (10248, 100 + @i, 10, 1, 0);
SET @i = @i +1;
END


이렇게 하면 추가 페이지가 만들어지는데 그 이유는 한 페이지에 내용이 너무 많아 지면 기존 페이지에 있던 요소 를 두개,세개 로 분할하여 담기 때문이 새로 페이지가 추가된것을 알 수 있고 이것을 페이지 Split 이라 한다

 

 

주의 : 인덱스를 Name 에 대해 걸어 놓았을때 SUBSTRING(NAME,1 ,2) 을 하게 되면 인덱스를 사용하는 최적화 사용이 불가능함으로 Index Scan 을 하게 되는 경우가 발생할 수 있다

SUBSTRING 으로 문자를 일부 가져와 어떤 문자를 찾는 것이 아닌

WHERE Name LIKE 'Ba%' ; 식으로 찾으면 Name 에 대해 최적화를 적용 받을 수 있다

 

실행 할때 Ctrl + L 로 Index Seek 인디 Index Scan 인지 확인하는 것이 좋다

 

 

 

반응형

테이블과 데이터들을 추가한다

USE Northwind;

--db 정보 보기
EXEC sp_helpdb 'Northwind';

create table Test
(
	EmployeeID INT NOT NULL,
	LastName NVARCHAR(20) NULL,
	FirstName NVARCHAR(20) NULL,
	HireDate DATETIME NULL,

);

SELECT *
FROM Test;

--Employees 데이터를 Test 에 추가한다
INSERT INTO Test
SELECT EmployeeID, LastName, FirstName, HireDate
FROM Employees;

RESULT

 

 

 

 

--index 를 걸 컬럼= LastName
--FILLFACTOR 리프 페이지 공간 1%만 사용 , 전체 사용 공간 중에 1%만 사용 하겠다는 것, 이러면 데이터가 다 안들어가기 때문에 별도 트리구조로 데이터를 저장함
--PAD_INDEX (FILFACTOR 가 중간 페이지에도 적용되게 하는 것) => 결과적으로 공간을 비효율적으로 사용하게끔 하는 것인데 목적이 테스트 하는 것임
CREATE INDEX Test_Index ON Test(LastName)
WITH (FILLFACTOR = 1, PAD_INDEX = ON)


--인덱스가 만들어진 sys.indexes 에서 index_id와 name 을 출력하는데 조건이 
--Test 에 만든 인덱스 id 와 같은것만 출력한다
SELECT index_id, name
FROM sys.indexes
WHERE object_id = object_id('Test');

 

결과 화면은 이런데 여기서 인덱스 Test_Index 를 조사해보면

 

--2번 인덱스 정보 살펴보기
DBCC IND('Northwind','Test', 2);

빨간색 박스의 IndexLevel 이

 

가장 높은 숫자가 트리의 Root 이고

2 -> 1 -> 0 

순으로 자식을 이루고 있는 인덱스 트리를 생각 하면 된다

 

2 가 가장 상단 그다음에 1에 해당 하는 것이 PagePID 보면 1008, 984 두개가 있는데

이 중에서 NextPagePID 를 1 레벨에서 다음을 말하는 것이 984 라고 나와 있는 것

즉 순서가 985 -> 1008 -> 984  로 되어 있다는 것을 알 수 있다

 

 트리 형태로 보면 가장 상단 레벨 1에 1개 2 레벨에 2개 3 레벨에 3개의 노드가 있다고 생각하면 된다

그런데 각 노드는 페이지들인데 이 정보들 또한 볼 수 있다

 

끝단 3개의 노드를 출력해보면

--1 파일번호, 968 페이지 번호, 3 출력 옵션
DBCC PAGE('Northwind',1, 968, 3);
DBCC PAGE('Northwind',1, 976, 3);
DBCC PAGE('Northwind',1, 977, 3);

 

 

위 처럼 되고 

원래 추가된 9개 와 비교해보면 3개씩 나뉘어져 들어가 있는 것을 알 수 있다

 

HEAP RID 라는 걸 볼 수 있는데

HEAP RID = 페이지주소(4바이트) , 파일 ID(2), 슬롯번호(2), 로 조합된 8바이트 ROW 식별자이고 이걸로

테이블에서 정보를 추출한다

 

TABLE [{PAGE} {PAGE} {PAGE} ....]  여기서 찾는 형태이다

 

 

RANDOM ACCESS (한건을 읽기 위해 한 페이지씩 접근 하는것 으로 트리 위에서 부터 아래로 노드를 찾아가는 과정)

BOOKMARK LOOKUP : 노드를 찾은다음 RID를 통해 행을 실제 TABLE 에서 찾는 것을 말함 

반응형

함수명을 쓰고 OVER 쓴다음 범위를 지정해주면 된다

OVER( [PARTITION] [ORDER BY] [ROWS] ) : 이걸로 서브집합을 선택해주는 것

 

ROW_NUMBER : 맨 왼쪽 인덱스 번호

RANK : 순위인데 중복되면 중복된 것 만큼 순위는 건너 띔

DENSE_RANK : 만약 1등이 두명이 나오면 그다음 3등이 2등이 되는 RANK

NTILE : 백분율로 가장 상위가 1% 로 1 로 나옴 , 가장 하위가 100

 

 

 

파티션의 경우 playerID로 Group by 와 유사하게 할수 있는데 다른 점은 Group by 는 하나로 묶어 버리지만 Partition 의 경우에는 각 행별로 모두 보이게 된다

결과

 

PlayerID 별로 랭킹이 매겨져 있는 걸 볼 수가 있다

 

 

 

LAG(바로 이전 : 나열된것의 바로 위) ,LEAD(바로 다음 : 나열된 것을 바로 아래)

 

 

 

결과

 

playerID 기준으로 salary 값 위아래를 보면 prevSalary 와 nextSalary 값이 있다는 것을 알 수 있다

 

 

FIRST_VALUE : 가장 처음 값 : 여금 여기선 큰 

LAST_VALUE : 가장 마지막 값 : 지금 여기선 작은 값

 

 

결과를 보면 WORST 가 제대로된 작은 값이 아닌데 

그 이유는 Desc 로 정렬하여 큰 값은 나오게 되는데 나오는 검색 과정이

동일 아이디의 가장 위에서 부터 하나씩 증가 시키면서 그 중에 큰걸 보게 되는 순서라

4500000 

4500000 , 2750000

4500000 , 2750000, 500000

이런순을 검색하면서 그 중 가장 큰걸 뽑아오는게 FIRST_VALUE 라서 best 는 제대로 되지만 worst 는 제대로 되지 않는다는걸 알 수 있다

 

 

 

 

 

 

그래서 LAST_VALUE 의 경우에는 제일 처음부터 증가하는 형태인 키워드 (UNBOUNDED PRECEDING) 를 넣어주고 현재 까지의 진행라인에 대한  현재 CURRENT_ROW 까지 는 BEST 라인이 범위가 되도록 ROWS 를 지정해주면 되고 

 

그다음 LAST_VALUE 에대해선 현재 라인 CURRENT_ROW 부터 동일 아이디에 대해서 마지막 라인을 얘기하는 UNBOUNDED FOLLOWING 을 넣어주면제대로된 WORST 값이 나오게 된다

 

제대로된 결과

 

 

 

오라클에서 OVER 절에 WINDOWING 절을 처음 사용할 때 ROWS와 RANGE가 어떤 차이점이 있는지 많이 헷갈릴 수 있다. 간단히 설명하면 ROWS는 각 행의 위치고, RANGE는 값의 범위라고 생각하면 된다. 아래의 예제를 여러 번 반복해서 보면 많이 어렵지 않게 이해할 수 있을 것이다.

 

아래의 키워드 의미부터 숙지를 하고 예제를 보면 더욱 이해하기 쉬울 것이다.

키워드 설명
 ROWS  물리적인 행 단위
 RANGE  논리적인 행 집합
 CURRENT ROW  현재 행
 UNBOUNDED PRECEDING  첫 번째 행
 UNBOUNDED FOLLOWING  마지막 행
 [위치] PRECEDING  [위치] 이전 행
 [위치] FOLLOWING  [위치] 다음 행

 

 

REF : https://gent.tistory.com/473

반응형

'서버(Server) > DB' 카테고리의 다른 글

DB : 복합 인덱스  (0) 2023.03.02
DB : INDEX  (0) 2023.03.01
Northwind and pubs sample databases for Microsoft SQL Server  (0) 2023.02.23
DB : 테이블을 변수에, IF 문, WHILE 문, BREAK , CONTINUE  (0) 2023.02.20
DB : BATCH : GO  (0) 2023.02.19

Northwind  Database 인데 오리지널 버전은 SQL Server 2000 으로 만들어졌었지만 

최근 MS Server 에서도 파일을 집적 복붙하여 사용가능하다

instnwnd.sql 파일

 

생성하고 나면 웹사이트 같은 느낌이라 테스트해보기에 좋다 

고개 정보, 주문, 제품, 지역, 직원 등등의 정보들이 있다

 

Northwind and pubs sample databases for Microsoft SQL Server

This folder contains scripts to create and load the Northwind (instnwnd.sql) and pubs (instpubs.sql) sample databases.

These scripts were originally created for SQL Server 2000.

 

 

Before you begin

To run this sample, you need a tool that can run Transact-SQL scripts. You can run the scripts in the following tools:

Run the scripts in SSMS

 

 

https://github.com/microsoft/sql-server-samples/tree/master/samples/databases/northwind-pubs

 

GitHub - microsoft/sql-server-samples: Azure Data SQL Samples - Official Microsoft GitHub Repository containing code samples for

Azure Data SQL Samples - Official Microsoft GitHub Repository containing code samples for SQL Server, Azure SQL, Azure Synapse, and Azure SQL Edge - GitHub - microsoft/sql-server-samples: Azure Dat...

github.com

https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/databases/northwind-pubs/instnwnd.sql

반응형

'서버(Server) > DB' 카테고리의 다른 글

DB : INDEX  (0) 2023.03.01
DB : 윈도우함수  (0) 2023.02.28
DB : 테이블을 변수에, IF 문, WHILE 문, BREAK , CONTINUE  (0) 2023.02.20
DB : BATCH : GO  (0) 2023.02.19
DB : 변수  (0) 2023.02.18

DB 에서도 조건문 사용이 가능하다

IF ELSE 문

DECLARE @i AS INT =100;

IF @i = 100
	PRINT('100')
ELSE
	PRINT('NOT')

 

여러줄 묶을땐 BEGIN END 로 묶어야 한다

 

DECLARE @i AS INT =100;

IF @i = 100
	BEGIN
		PRINT('100')
		PRINT('101')
	END
ELSE
	PRINT('NOT')

 

 

WHILE 문 또한 사용가능하고 CONTINUE 와 BREAK 또한 있다

GO
DECLARE @i AS INT =0;
WHILE @i <= 10
BEGIN 
	SET @i = @i + 1;
	IF @i = 6 CONTINUE;
	PRINT @i;
END

 

 

 

 

원래 CREATE TABEL 명령어는 이런 형태였다

EX)

--테이블 만들기
create table accounts(
	accountId integer not null,
	accountName varchar(10) not null,
	coins integer default 0,
	createdTime DATETIME
);

 

 

그런데 테이블도 변수로 만들 수 있다
create table accounts 과 비슷하지만 다른건 tempDB 라는 곳에 임시로 데이터 베이스가 저장된다

--테이블도 변수로 만들 수 있다
--create table accounts( 과 비슷하지만 다른건 tempDB 라는 곳에 임시로 데이터 베이스가 저장된다
--

GO
DECLARE @test TABLE
(
	name VARCHAR(50) NOT NULL,
	salary	INT NOT NULL
);

INSERT INTO @test
SELECT p.nameFirst + ' ' + p.nameLast, s.salary
FROM players AS p
		INNER JOIN salaries AS s
		ON p.playerID = s.playerID;


SELECT *
FROM @test;

다음은 실행 결과다

반응형

'서버(Server) > DB' 카테고리의 다른 글

DB : 윈도우함수  (0) 2023.02.28
Northwind and pubs sample databases for Microsoft SQL Server  (0) 2023.02.23
DB : BATCH : GO  (0) 2023.02.19
DB : 변수  (0) 2023.02.18
DB : TRANSACTION  (0) 2023.02.17

변수의 유효범위 설정 키워드는 배치명령어인 GO 이다

GO 영역 전후로 별도의 영역인데

--변수 선언 , 생성함과 초기화 할수도있고 
DECLARE @i as INT = 10;

--생성만 한다음, 나중에 넣을 수도 있다
DECLARE @j as INT;
SET @j = 20;

SELECT @i,  @j;



---배치---
--이전에 썼던 변수는 없는걸로 치고 다시 변수를 선언할수 있는 명령어 go 
GO
DECLARE @i AS INT =100;

SELECT @i;

 

 

 


--배치는 하나의 묶음으로 분석 실행된다

에러가 나도 go 다음 묶음 구문은 실행된다 별도 영역이라서

 

SELECT *
FO PLAYERS;

메세지에 보면 다음 처럼 에러지만

 

 

SELECT *
FO PLAYERS;

GO

SELECT * 
FROM salaries;

이 로직의 경우 go 이후 하단은 정상적이라서 에러 메세지가 뜨긴 하지만 다음 처럼

result 탭에서는 select 구문이 나온걸 알수 있다 즉 별도로 실행된다

반응형

 

프로그램 랭귀지 처럼 변수를 만들어서 결과를 임시로 보관할 수가 있다

 

--변수 선언 , 생성함과 초기화 할수도있고 
DECLARE @i as INT = 10;

--생성만 한다음, 나중에 넣을 수도 있다
DECLARE @j as INT;
SET @j = 20;

SELECT @i,  @j;

 

실행결과 

 

 

 

 

가장 많은 역봉을 받은 사람의 이름을 담는 구문

 

결과화면

 

SELECT ~ DESC 까지 결과를 firstName 에 담고 이것을 질의한 결과다

 

 

아래 구문은 sql 서버에 한정된 문법인데 다음 처럼 편하게 여러 변수에 담을 수도 있다

 

 

 

 

 

반응형

 

 

거래의 경우

  • A 의 인벤토리에서 아이템 제거
  • B의 인벤토리에 아이템 추가
  • A의 골드 감소
    이렇게 모두 처리되야 하는데 중간에 실패가 난다면 완전히 거래가 처리 되는것이 아니고 오류가 되어버리는데
    이렇게 되면 테이블 데이터가 잘못되게 된다, 강화 하는 경우에도 비슷한 케이스
    All or Nothing 
    이런걸 해결 하기위해 TRANSACTION 이 있다
    아무것도 쓰지 않으면 기본 적으로 TRANSACTION 이 있고 그 뒤에 COMMIT 이 있는 것인데 (EX : INSERT INTO ...)
    BEGIN TRAN; 을 명시하면 뒤에 COMMIT 또는 ROLLBACK 을 적어 처리할지 되돌릴지를 정할 수 있다
INSERT INTO accounts VALUES(1, 'TESET STR', 100, GETUTCDATE());

BEGIN TRAN;
	INSERT INTO accounts VALUES(2, 'TESET STR', 100, GETUTCDATE());
ROLLBACK;

 

 

결과를 보면 두번째 것은 추가 안된것을 알수 있다 ROLLBACK 되었음으로

 

 

 

 

INSERT INTO accounts VALUES(1, 'TESET STR', 100, GETUTCDATE());

BEGIN TRAN;
	INSERT INTO accounts VALUES(2, 'TESET STR', 100, GETUTCDATE());
COMMIT;

추가된 경우

 

 

 

 

 

 

아래 구문을 실행하기 전 데이터

 

--TRY CATCH 와 비슷한 구문
BEGIN TRY
		BEGIN TRAN;
			INSERT INTO accounts VALUES(1, 'T1', 100, GETUTCDATE());
			INSERT INTO accounts VALUES(2, 'T2', 100, GETUTCDATE());
		COMMIT;
END TRY
BEGIN CATCH
	IF @@TRANCOUNT > 0
		ROLLBACK;
END CATCH

@@TRANCOUNT 는 TRAN 이 몇개 인지 알수 있는 매크로인데

BEGIN TRAN;

       TRAN;

 

이렇게 TRAN 을 중첩시키면 1이상이 될 수가 있는데 이때 이 개수를 리턴해주는게 @@TRANCOUNT 이다

 

그리고 INSERT 는 accountId 가 primary key 임으로 이미 존재하는 키가 있을 경우 또다시 추가 하려고 하면 에러가 발생되어 catch 로 잡히게 된다

 

실행후 상황

아무 영향이 없었다는 걸 알 수 있다

 

PRINT('TTT') 를 ROLLBACK 구문 쪽에 써서 ROLLBACK 된 이유를 적어줄 수도 있다

 

중요한건 TRAN  으로 묶어놓은건 한번에 다 실행하거나 아니면 중간에 오류/예외가 발생하면 모두 실행되지 않는 다는 것이다

그리고 TRANSACTION 은 보통 두개 이상의 테이블에 어떤 변경이나 영향을 줄때 사용된다

 

 

사용시 주의 할점은

TRAN 안에는 꼭 원자적으로 실행될 애들만 넣어야 한다

즉 성능적으로 문제가 될 수 있기 때문인데

LOCK이 되기 때문

 

 

만약

BEGIN TRAN;
	INSERT INTO accounts VALUES(2, 'TESET STR', 100, GETUTCDATE());

이렇게 까지 되어 있으면 위코드는 COMMIT 이나 ROLLBACK 을 만나기 전까지 계속 LOCK 리 걸린 상태가 되며

 

다른 구문에서 accounts 를 조회하려는 구문을 실행한다 해도 select 구문은 실행 되지 않고 계속 대기하게 된다

대기상태에 빠지게 됨 commit 이나 rollback 을 만나지 않는다면 원자적 특성때문에

 

 

같은 얘기지만 TRAN  과 COMMIT/ROLLBACK 사이의 구문은 길지 않게 작성하는 것이 좋다

 

 

반응형

'서버(Server) > DB' 카테고리의 다른 글

DB : BATCH : GO  (0) 2023.02.19
DB : 변수  (0) 2023.02.18
DB : INNER JOIN, CROSS JOIN  (0) 2023.02.16
DB : UNION : 합치면서 중복제거, INTERSECT 교집합, EXCEPT 차집합  (0) 2023.02.15
DB : 인덱스(Index)  (0) 2023.02.13

CROSS JOIN (교차 결합)
서로 교차를 하면서 하나씩 결합을 한다는 것
(1,A), (1,B), (1,C), (2,A)... 총 9개

CREATE TABLE testA
(
	a INTEGER
)

CREATE TABLE testB
(
	B VARCHAR(10)
)

INSERT INTO testA VALUES(1);
INSERT INTO testA VALUES(2);
INSERT INTO testA VALUES(3);

INSERT INTO testB VALUES('A');
INSERT INTO testB VALUES('B');
INSERT INTO testB VALUES('C');


SELECT *
FROM testA;

SELECT *
FROM testB;


--CROSS JOIN (교차 결합)
--서로 교차를 하면서 하나씩 결합을 한다는 것
--(1,A), (1,B), (1,C), (2,A)... 총 9개

SELECT *
FROM testA
	CROSS JOIN testB;

SELECT *
FROM testA, testB;

결과화면

 

 

 

 

 

 

 

 

 

기본 데이터 보기

USE BaseballData;


SELECT *
FROM players
ORDER BY playerID;

SELECT *
FROM salaries
ORDER BY playerID;

 

 

 


INNER JOIN(두개의 테이블을 가로로 결합 + 결합 기준을 ON 으로 한다)
UNION 은 세로 즉 위아래로 합치는 것이였다면 INNER JOIN 은 옆으로 합치는 것

SELECT *
FROM players AS P
	INNER JOIN salaries AS S
	ON P.playerID = S.playerID;

 

players 의 playerID 와 salaries 의 playerID 가 같은 행 끼리 합치는 것

주의 할점은 조건이 = 인데 양쪽 모두에 playerID 가 있어야 붙여지게 되지 한쪽이라도 id 값이 없다면 해당 행은 걸러진다

즉 양쪽에 모두 정보가 있을때만 나온다

 

결과를 보면 뒤에 추가 된걸 볼 수 있다

 

inner join 을 한다는 건 새로운 테이블을 만든 것

 

 

 

 

 

 

-- outer join (외부 결합)
--어느 한쪽에만 존재하는 데이터가 있을때 정책을 어떻게 할것인지에 대한 것
-- left join 인경우로 예를 들어보면 두개를 조인 할때 왼쪽에만 있고 오른쪽에는 없다면
--왼쪽 정보를 그대로 채워 넣고 없는 오른쪽 정보는 null 로 채워 넣어서 join 을 한다는 것으로 
--inner join 과 유사한데 비어 있는 것을 어떻게 처리 할것인가에 대한 내용이다

SELECT *
FROM players AS P
	LEFT JOIN salaries AS S
	ON P.playerID = S.playerID
	ORDER BY P.playerID;

 

 

아래는 playerID 로 정렬하여 두 테이블(players과 salaries )을 본것이고

 

 

LEFT JOIN 한다음의 모습이다 

adairbi99m 의 줄에서 끝을 보면 

 

 

salaries 에는 adairbi99m  이 없기 때문에 끝에 NULL 로 채워진것을 볼 수 있다

 

 

 

RIGHT JOIN 은 반대의 개념이 된다

정보가 오른쪽에 있다면 표시되고 그 이후에 같은 행에 왼쪽(plyaer)에 없으면 왼쪽 정보는 NULL 로 채워진다

예시 이미지

 

오른쪽에 정보는 있지만

 

왼쪽이 null 로 채워진 경우 

 

 

그런데 left 나 right 나 테이블 순서를 바꿔주면 동일한 효과가 된다

 

 

 

 

정리하자면 

cross join 은 * 이고

inner join, left join right 조인은 같은 행에 추가 하여 테이블을 만드는 것이다

 

 

반응형

 

union 시 주의할 점은 열이 같아야지 합처진다 그런데 A , B 중에서 중복은제거

UNION 은 || or 연산과 비슷한데 중복은 제거 한다

select playerID, AVG(salary)
from salaries
group by playerID
having AVG(salary) >= 3000000

UNION

--12월에 태어난 선수들의 playerID
select playerID, birthMonth
from players
where birthMonth = 12
order by playerID asc
;

 

아래는 위 결과를 실행했을때의 결과인데 avg 와 birthmonth 때문에 합쳐지지 않아

silvaca01 이 별도 있는 거을 볼 수 있다

 

 

 

 

 

 

union 열을 같게끔 해주면 중복은제거된다

 

--커리어 평균 연봉이 3000000 이상인 선수들의 playerID
select playerID
from salaries

group by playerID
having AVG(salary) >= 300000 

UNION

--12월에 태어난 선수들의 playerID
select playerID
from players
where birthMonth = 12
order by playerID asc
;

이렇게 하면 합쳐진 하나만 나오는 것을 알수 있다 ( 중복 제거 )

 

 

 

 

union all 은 중복을 허용한다

select playerID
from salaries

group by playerID
having AVG(salary) >= 300000 

UNION all

--12월에 태어난 선수들의 playerID
select playerID
from players
where birthMonth = 12
order by playerID asc
;

 

 

union 을 쓰게 되면 order by 는 가장 하단에 와야 한다

 

 

 

 

교집합(intersect) 을 구한다 즉 양쪽 모두 만족하고 존재하는것을 구한다

--교집합(intersect) 을 구한다 즉 양쪽 모두 만족하고 존재하는것을 구한다
--커리어 평균 연봉이 3000000 이상이거나 (&&) 12월에 태어난 선수들
select playerID
from salaries

group by playerID
having AVG(salary) >= 300000 

intersect

--12월에 태어난 선수들의 playerID
select playerID
from players
where birthMonth = 12
order by playerID asc
;

 

 

 

 

--차집합
--커리어 평균 연봉이 3000000 이상이거나 (-) 12월에 태어난 선수들
select playerID
from salaries

group by playerID
having AVG(salary) >= 300000 

except

--12월에 태어난 선수들의 playerID
select playerID
from players
where birthMonth = 12
order by playerID asc
;

위는 차집합으로 A - B 가 된다

명령어는 except 가 된다

 

반응형

'서버(Server) > DB' 카테고리의 다른 글

DB : TRANSACTION  (0) 2023.02.17
DB : INNER JOIN, CROSS JOIN  (0) 2023.02.16
DB : 인덱스(Index)  (0) 2023.02.13
DB : DB(스키마) 만들기, 테이블 만들기와 Primary Key 의 성능  (0) 2023.02.12
DB : SUBQUERY  (0) 2023.02.10

DB 에선 2진 검색 트리를 사용한다, 균형잡힌 트리등 각 DB 마다 다를 순 있다

 

어떤 게임에서 특정 유저 ABC 에게 귓말을 날린다 하면 다른 방법을 쓰지 않는다면 모든 유저중에서 ABC 를 찾아야 하지만 이때 index 를 사용하면 빠르다

 

유저명순으로 이름들을 정렬한 다음 여기에  index 를 매긴다

즉 트리종류의 검색으로 빠르게 찾는것이 index 의 방식이다

이때 유저명에다가 index 를 걸어 찾기를 더 빠르게 한다는 개념

 

 

 INDEX 는 두가지 종류가 있다

  1. CLUSTERED INDEX  : 테이블당 1개만 존재하고 제일 빠르다, 공간도 적게 차지함
    Primary key 대부분이 clustered index 이다
    영한사전 처럼 알파벳 순서처럼 이미 데이터가 정렬이 되어 있고 여기서 찾는 것

  2. NON-CLUSTERED INDEX : 별다른 제한 없음
    별도의 공간에 색인목록을 만들어 색인 목록으로 한번 간다음 여기서 다시 데이터를 찾는 방식
    즉 따로 관리하는 Lookup테이블로 색인을 먼저 한다음 찾는다

 

디폴트로는 Primary key 로 지정하면 Clustered Index 인데, 지정을 Non - Clustered Index  로 한다면 이것도 가능은 하지만 이렇게 사용할일은 거의 없다

 

 

 

인덱스 지정하기

CREATE INDEX i1 ON accounts(accountName);

 

 

 

 

 

인덱스를 accountname 에 지정한다음 위 그림처럼 i1 으로 accountname  에 대한 인덱스가 지정된 것을 알 수있다

 

 

DROP INDEX accounts.i1;  

이렇게 인덱스를 삭제 할 수 있다

 

accountname 을 인덱스로 지정하는 상황은 이름으로 검색을 하는 경우를 예로 들 수 있다

 

 

CREATE UNIQUE INDEX i1 ON accounts(accountName);

--중복 되는 것이 없는 인덱스

 

 

CREATE CLUSTERED INDEX i1 ON accounts(accountName);

이렇게 지정하면 CLUSTERED 인덱스로 지정을 하려고 하지만 테이블에 하나만 클러스터 인덱스만 존재 함으로 추가로 지정하려 하면 오류가 난다

 

 

 

CREATE INDEX i1 ON accounts(accountName, ballCount);

이렇게 여러개를  조합하여 묶어 인덱스로 지정하는 것도 가능하다

 

 

 

 

 

 

반응형
--DB 만들기, 스키마
create database GameDB;

--db 사용
use GameDB;


--테이블 만들기
create table accounts(
	accountId integer not null,
	accountName varchar(10) not null,
	coins integer default 0,
	createdTime DATETIME
);

select *
from accounts;

 

 

 

--테이블 삭제
--drop table accounts;

--열추가
ALTER TABLE accounts
ADD lastEnterTime DATETIME;

 

 

 

 

 

--accounts 에 accountId 를 primary 로 설정한다
 ALTER TABLE accounts
 ADD PRIMARY KEY (accountId);

 

 

Primary key 로 설정하면 

 

위 처럼 Clustered Index Seek 라고 표기 된걸 볼수 있는데 이것은 map 또는 dictionary 같은 성능을 보인다

 

하지만 Primary key 를 제거하면 

이 처럼 Table Scan 으로 바뀌게 되어 테이블을 뒤지는 형태로 느린 성능을 보이게 된다

 

 

 

반응형

'서버(Server) > DB' 카테고리의 다른 글

DB : UNION : 합치면서 중복제거, INTERSECT 교집합, EXCEPT 차집합  (0) 2023.02.15
DB : 인덱스(Index)  (0) 2023.02.13
DB : SUBQUERY  (0) 2023.02.10
DB : subquery  (0) 2023.02.04
DB : Insert into , Delete, Update  (0) 2023.02.03

--exists 존재한다면 진행하고 없다면 스킵한다
--not exists exists 와 반대

 

select *
from players
where exists (select playerID from battingpost where battingpost.playerID = players.playerID );

(select playerID from battingpost where battingpost.playerID = players.playerID )

서브 쿼리를 보면 battingpost.playerID = players.playerID 두 조건이 같은것이 존재 할때만(exists) players 의 정보를 보여주며 그렇지 않으면 스킵한다


결과

반응형

'서버(Server) > DB' 카테고리의 다른 글

DB : 인덱스(Index)  (0) 2023.02.13
DB : DB(스키마) 만들기, 테이블 만들기와 Primary Key 의 성능  (0) 2023.02.12
DB : subquery  (0) 2023.02.04
DB : Insert into , Delete, Update  (0) 2023.02.03
DB : group by  (0) 2023.02.02
select *
from players
where playerID = (select top 1 playerID from salaries order by salary desc );

playerID 에 해당 하는 내용을 하단과 같이 select 문을 다시 넣어 검색하여 이것의 결과를 활용하는 것을 보고 subquery 라 하고 두번에 나누어서 처리 할것은 한번에 처리 할 수 있다

 

주의 할것은 위 처럼 단일행은 동작 가능하지만 다중행에 대해선 동작하지 않는다

 

 

 

select *
from players
where playerID in (select top 10 playerID from salaries order by salary desc );

하지만 in 을 사용하게 되면 서브쿼리에 있는 내용을 모두 상위 where player 와 매칭 되는것을 모두 보여준다

결과 화면에 3개만 보여지는 이유는  IN 으로 처리 하면 중복되는것은 하나만 보여주기 때문이다

 

 

서브쿼리는 where 에서 많이 사용 되지만 다른 구문에서도 사용 가능하다 

 

다음 처럼 insert into 에도 서브쿼리를 넣을 수도 있다

insert into salaries
values (2023, 'KOR', 'NL', 'kkk', (select max(salary) + 100 from salaries));

 

 

 

 

테이블의 모든 모든 요소들을 다른 테이블에서 새로운 테이블에 일부요소들에 대한 복사하기를 서브쿼리와 유사한 형태로 쓸 수 있다

 

salaries_temp 를 복사를 받을 테이블

--INSERT SELECT 구문

insert into salaries_temp
select  yearID, playerID, salary from salaries;

위는 salaries 내용을 salaries_temp  에 복사하는 코드다

 

 

 

select *
from salaries_temp;

위와 같이 복사 된것을 알수 있다

 

 

원래 salaries 는 다음 처럼 요소들이 배치되어 있다

반응형

'서버(Server) > DB' 카테고리의 다른 글

DB : DB(스키마) 만들기, 테이블 만들기와 Primary Key 의 성능  (0) 2023.02.12
DB : SUBQUERY  (0) 2023.02.10
DB : Insert into , Delete, Update  (0) 2023.02.03
DB : group by  (0) 2023.02.02
DB : COUNT, DISTINCT 각종 함수들  (0) 2023.02.01
select * 
from salaries;

 

 

insert into salaries
values (2023, 'KOR', 'NL', 'killer', 100000000)

insert 할때

이렇게 컬럼 명을 쓰고 그거에 맞게 values 를 넣어도 가능하다(이때 순서가 달라고 가능하다)

 

 

delete from salaries;

테이블을 삭제한다

 

 

 

 

 

 

조건에 맞는 열을 지운다

delete from salaries
where playerID ='barkele01';

주의 할점은 조건에 맞는것을 모두 삭제한 다는 것이다

salary 중에 null 을 삭제 한다고 하면 모든 열중 null 인걸 전부 삭제한다

 

 

 

 

 

 

update 하기 전 원래 데이터

 

 

update salaries
set salary = salary * 2
where teamID = 'ATL';

update 테이블명

salary 에 두배로 곱한 쿼리문 적용 후의 결과

 

 

 

콤마(,) 로 연속적으로 값을 업데이트 할 수 있다

update salaries
set salary = salary * 2, yearID = yearID +1
where teamID = 'ATL';

 

delete, update 등 실제 쿼리를 sql server 에디터에서 실행하면 테이블 값들에 실제 값이 적용 되어 있는 것임으로

테스트 할때는 원래 데이터를 빽업해놓는것이 좋다

 

그리고 실제 데이터를 삭제 할때는 실제 삭제하지 않고 delete 열을 하나 두어 삭제할때 delete 열에 체크만해서 삭제 하는 케이스들이 많다(ex 계정 같은 경우들, 복구를 위해서)

 

 

 

반응형

'서버(Server) > DB' 카테고리의 다른 글

DB : SUBQUERY  (0) 2023.02.10
DB : subquery  (0) 2023.02.04
DB : group by  (0) 2023.02.02
DB : COUNT, DISTINCT 각종 함수들  (0) 2023.02.01
DB : Case, where  (0) 2023.01.31

원래 데이터는 이렇게 있는데

 

2004년 도에 가장 많은 홈런을 날린 팀은?

select  teamID, sum(HR) as homeRuns
from batting
where yearID=2004
group by teamID
order by homeRuns desc;

 

group by 는 공통된 것을 하나의 단위로 묶는 것인데

이 묶음으로 하나로 보려 하는 것이 group by 라서 

group by 한 것을 select * 할 수는 없다

 

즉 group 된 것의 정보에서 뭔가 SUM 이나 계량적인 데이터를 종합해 보려고 할때 유용하다

 

 

 

2004년 도에 가장 많은 홈런을 날린 팀은?

select teamID, sum(HR) as homeRuns
from batting
where yearID=2004 
group by teamID
having SUM(HR) >= 200
order by homeRuns desc;

여기서 having 을 볼 수 있는데 having 은 group by 다음에 조건을 걸 수 있는 키워드 이다

group 으로 묶은 목록들 중에서 다시 조건을 걸기 위해선 where 로는 충족되지 못하기 때문에 하나 더 있다고 볼 수 있다

 

 

 

명령문은 다음 순서대로 실행 되기 때문에 select 를 가장 최상단에 쓰는 쿼리 문에서는  select 다음에 오는 컬럼명에 올 수 있는 것인지에 대한 판단은 아래 순서를 고려해야 한다 (as 별칭 포함)

  1. from
  2. where
  3. group by
  4. having
  5. select
  6. order by

 

 

단일년도에 가장 많은 홈런을 날린 팀은?

select teamID, sum(HR) as homeRuns
from batting
group by teamID
order by homeRuns desc;

 

이렇게 볼 수 잇는데 이때는 같은 팀은 맞는데 연도가 섞여 있으면서 각 연도별에 대한 홈런을 모두 합한 것이 됨으로

 

 

 

 

만약 위 상황에서 같은 팀에서도 연도별 분류 한다면?

select teamID, yearID, sum(HR) as homeRuns
from batting
group by teamID, yearID
order by homeRuns desc;

같은 팀에서도 단일 연도로 분류하여 구 할 수 있다

 

NYA 에 대한 결과는 하단에 더 있지만 생략..

반응형

'서버(Server) > DB' 카테고리의 다른 글

DB : subquery  (0) 2023.02.04
DB : Insert into , Delete, Update  (0) 2023.02.03
DB : COUNT, DISTINCT 각종 함수들  (0) 2023.02.01
DB : Case, where  (0) 2023.01.31
DB : 날짜와 관련된 기능들 GETUTCDATE()  (0) 2023.01.30

 

 

COUNT 는 NULL 인 것은 제외하여 개수를 센다

 

DISTINCT 중복은 제거하고 나열한다

 

 

select count(birthMonth)
from players;

select distinct birthMonth
from players;

 

원래 이렇게 생긴 테이블에서 

위 코드를 실행하면 다음 처럼 된다

 

NULL 또한 distinct 대상이 된다 => 중복만 제거하는 것임으로

 

 

 

 

 

위의 코드에선 3개가 모두다 같아야 중복 처리가 된다

그렇지 않다면 위 처럼 중복 분기처리가 된다

 

 

 

그 밖의 함수들

집계 함수들에선 NULL 은 처리 하지 않고 무시한다

몸무게의 평균이 된다

 

 

 

다음 처럼 NULL 일대는 0 으로 취급하여 처리 할 수도 있다

0 이 추가 되어 평균이 낮아졌다

 

 

 

MIN, MAX 는 문자와 날짜에도 사용이 가능하다

 

 

 

 

 

 

팀이 보스턴이면서 단일 년도 최다 홈런 친 사람의 정보

select top 1 *
from batting
where teamID = 'BOS' 
order by HR DESC;

이렇게 batting 테이블에서  id 를 알아온 다음 플레이어 정보에서 playerid 를 통하여 정보를 가져와 뿌려주면 된다

 

 

반응형

'서버(Server) > DB' 카테고리의 다른 글

DB : Insert into , Delete, Update  (0) 2023.02.03
DB : group by  (0) 2023.02.02
DB : Case, where  (0) 2023.01.31
DB : 날짜와 관련된 기능들 GETUTCDATE()  (0) 2023.01.30
DB : DATETIME 날짜 넣기, 시간 관련 함수와 기능들  (0) 2023.01.28
use BaseballData;

select birthMonth
from players;

select *,
	case birthMonth
		when 1 then N'겨울'
		when 2 then N'봄'
		when 3 then N'가을'
		when 8 then N'8이다'
		else N'그밖에'
	end as birthSeason
from players;

 

switch case 와 비슷한걸 알 수 있다

 

위에서 end as birthSeason  끝에 새로 추가된 컬럼의 이름을 birthSeason 으로 지정하겠다는 얘기다

 

case 의 where 조건에 맞춰 문자로 변환되어 추가 된것을 볼 수 있다

 

 

 

 

아래 처럼 조건문을 추가 하는 구문 또한 있다

select *,
	case 
		when birthMonth <=1 then N'back'
		when birthMonth <=3 then  N'나이스'
		when birthMonth <=6 then  N'앜'
		when birthMonth <=9 then  N'9이하'
		when birthMonth <=12 then  N'12이하'
		else N'그밖에'
	end as birthSeason
from players;

 

위 구문들에서 else 구문이 없다면 else 에 에 해당 하는것ㅇ느 birthSeason 에서 NULL 이 된다

주의 할점  birthMonth = NULL 이렇게 조건문을 쓸 수 없고 birthMont is NULL 이렇게 비교를 해야한다

 

 

 

 

반응형

시간을 얻어올때 UTC 로 통일된 시간으로 처리하면 어느 나라든지 상관 없이 기준이 되는 UTC 시간으로 처리 할수 있기 때문에 시간계산에 혼선을 줄일수 있다

 

select GETUTCDATE();

 

 

아래는 날짜와 관련된 기능들이다

select * 
from DateTimeTest
where time >= '20100101'

select GETUTCDATE();

select DATEADD(YEAR, 1, '20230101');
select DATEADD(DAY, 1, '20230101');

select GETUTCDATE();
--빼기도 가능하다
select DATEADD(SECOND, -30, '20230101');

--시간 차이
select DATEDIFF( SECOND, '20230103','20230102');

--문자 에서 특정 날자 등을 갖고 오고 싶을때
select DATEPART(DAY, '20230507');

--위의 결과와 동일하다
select DAY('20230507');

 

위 실행 결과 화면

 

반응형

SELECT CAST('20230124' AS DATETIME)

 

위 구문은 이미지처럼 결과가 나타나게 되고

컬럼 타입은 DATETIME 이다

DATETIME  = 날짜와 시분초가 같이 있는 타입이다

 

 

SELECT CAST('20230124 05:03' AS DATETIME)

 

 

DATE 를 넣는 문자 형태는 다음과 같은 유형들이있다

YYYYMMDD

YYYYMMDD hh:mm:ss.nnn

YYY-MM-DDThh:mm

 

위 예제는 두번째 포맷에 맞춰 넣은 예시이다

 

 

  SELECT GETDATE();
  SELECT CURRENT_TIMESTAMP;

 

 

 

날차 추가하기

USE [BaseballData]
GO

INSERT INTO [dbo].[DateTimeTest]
           ([time])
     VALUES
		--('20090909')
          (CURRENT_TIMESTAMP)
GO






use BaseballData;

SELECT * 
FROM DateTimeTest;

-- 은 주석이다

 

 

 

SELECT * 
FROM DateTimeTest;

몇번 추가한 모습

 

 

조건식으로 비교할때 다음 처럼 할 수 있다 두개의 결과는 같다

use BaseballData;

SELECT * 
FROM DateTimeTest
where time >= CAST('20200101' as DATETIME);


SELECT * 
FROM DateTimeTest
where time >= '20200101';

CAST 로  DATETIME 으로 변홚을 하나 그냥 문자로 넣으나 결과는 같다

 

 

 

UTC TIME 은 어느 나라에서나 표준으로 사용 하는 시간이다

나라마다 시간이 다른데 각 로컬국가의 시간대로 하면 안되고 UTC 로 시간을 계산해야한다

 

SELECT GETUTCDATE();

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

 

원래 데이터

나이 구하기

select 2023-birthYear as koreanAge 
from players
where deathYear is null and birthYear is not null
order by koreanAge

 

 

 

쿼리 순서는 

 

from

where

select

orderby 

순 이기 때문에 위에서 쓰여진 네이밍을 해당 명령 포함 하단에서 쓸 수 있다

 

이런 경우엔 에러가 나는것을 알 수 있다

 

 

 

그래서 이렇게 다시 한번 birthYear 를 써서 연산해야한다

select 2023-birthYear as koreanAge 
from players
where deathYear is null and birthYear is not null and (2023-birthYear <= 80 )
order by koreanAge

 

 

 

 

 

 

그 외 일반적인 규칙들

  1. select 3-NULL 의 결과는 NULL 이다
  2. 정수 나누기 정수는 수학적으로 소수로 떨어진다해도 정수고
  3. 분모를 소수로 .0 처리해주면 소수로 나온다
  4. 0 으로 나누면 오류가 난다
  5. ROUND, POWER, COS 함수등들도 제공된다

 

그 외 연산들 참고 

https://learn.microsoft.com/en-us/sql/t-sql/functions/mathematical-functions-transact-sql?view=sql-server-ver16 

 

Mathematical Functions (Transact-SQL) - SQL Server

Mathematical Functions (Transact-SQL)

learn.microsoft.com

 

반응형
USE BaseballData;

select *
from players
where birthYear is not null
ORDER BY birthYear ASC;

기본이 asc 오름차순이고
desc 는 내림 차순을 의미한다

 

 

아래 코드는 앞선 정렬 순서가 같다면 그다음 순의 정렬 순으로 정렬 되는 것의 반복이다

select *
from players
where birthYear is not null
ORDER BY birthYear DESC, birthMonth desc, birthDay desc;

 

 

is null 같은 null 은 구현이 각각 다를 수 있어서 db를 옮길 일이 있다면 없는 것으로 생각하고 구현하는 것이 좋다

 

 

 

상위 10명을 보여주기 

select TOP(10) *
from players
where birthYear is not null
ORDER BY birthYear DESC, birthMonth desc, birthDay desc;

 

 

전체 데이터 중에서 상위(top) percent 로 해당하는 분포의 데이터를 가져올 수 도 있다

select TOP 0.07 percent *
from players
where birthYear is not null
ORDER BY birthYear DESC, birthMonth desc, birthDay desc;

 

top 은 ms sql 에서 있는데 다른 db 에서는 구현이 좀 다를 수 있다

 

 

 

 

 

offset 은 나온 결과에서 10 개를 건너 뛴 다음의 fetch next 로 3개만 출력 할때 아래처럼 쓸 수 있다

select *
from players
where birthYear is not null
ORDER BY birthYear DESC, birthMonth desc, birthDay desc
OFFSET 10 rows fetch next 3 rows only;

offset 이 구문은 다른 db 에서도 존재하는 구문이다

반응형
select *
from players
where birthCity LIKE 'New%';

% 는 뒤로 모든 문자가 다 올수 있고

_ 는 한문자만 올 수 있다

 

패턴 매칭을 시작할땐 LIKE 키워드를 넣어준다

 

 

 

 

 

아래 처럼 _ 만 하면 New 다음 한문자가 오는 케이스가 없어서 아무것도 조회가 안되는것을 알 수 있다

반응형

기본 사칙 연산이 select 에서 가능하다

select 33-30

 

 

 

from 이 select 보다 먼저 실행 된다, 영어 순서를 생각하면 이해하기에 좀더 편하다

SELECT nameFirst as name, nameLast, birthYear, birthCountry
FROM players
WHERE birthYear = 1974 OR birthCountry ='USA'​

 

 

SELECT nameFirst as name, nameLast, birthYear
FROM players
where birthYear != 1866

 

 

 

요소에 null 이 있는 경우는 is null

null 이 없는 경우만 볼려면 is not null 로 조건을 넣어주면 된다

 

select *
from players
where deathYear is not null

 

 

 

select *
from players
where deathYear is null

 

반응형

+ Recent posts