1. 고양이와 개는 몇 마리 있을까 - GROUP BY

동물 보호소에 들어온 동물 중 고양이와 개가 각각 몇 마리인지 조회하는 SQL문을 작성해주세요. 이때 고양이를 개보다 먼저 조회해주세요.

SELECT ANIMAL_TYPE, COUNT(ANIMAL_TYPE) AS count
FROM ANIMAL_INS
GROUP BY ANIMAL_TYPE
ORDER BY ANIMAL_TYPE

1. SELECT ANIMAL_TYPE, count 인데, count라는 컬럼이 없으므로 어떤 식 AS count 가 되어야 한다.

즉, 어떤 식의 결과값을 count로 정의!

ANIMAL_TYPE 별 개수를 구하는 것이므로 COUNT(ANIMAL_TYPE) AS count

 

2. FROM ANIMAL_INS(테이블명)

 

3. GROUP BY ** 이 문제의 핵심!

* GROUP BY : 특정 컬럼을 그룹화하여 데이터 조회!

GROUP BY 특정컬럼명

말 그대로 특정컬럼을 그룹화 한다는 의미인데, 

그룹화를 하면 조회된 데이터를 통계를 내기 위한 집계함수( avg, sum,...)를 사용하기 쉬워진다!

GROUP BY ANIMAL_TYPE == ANIMAL_TYPE으로 그룹화 == cat끼리, dog끼리 그룹

 

4. ORDER BY ANIMAL_TYPE : Cat 먼저 조회해야하므로, ORDER BY (ASC) 사용 ( C < D)

 

 

2. 동명 동물 수 찾기

동물 보호소에 들어온 동물 이름 중 두 번 이상 쓰인 이름과 해당 이름이 쓰인 횟수를 조회하는 SQL문을 작성해주세요. 이때 결과는 이름이 없는 동물은 집계에서 제외하며, 결과는 이름 순으로 조회해주세요.

SELECT NAME, COUNT(NAME) AS COUNT
FROM ANIMAL_INS
WHERE NAME IS NOT NULL
GROUP BY NAME
HAVING COUNT > 1
ORDER BY NAME

1.  SELECT  NAME, COUNT 인데, COUNT 라는 컬럼이 없으므로 어떤 식 AS COUNT 가 되어야 한다.

즉, 어떤 식의 결과값을 count로 정의!

NAME별 개수를 구하는 것이므로 COUNT(NAME) AS COUNT

 

2. FROM ANIMAL_INS(테이블명)

 

3. ** GROUP BY를 쓸 때 WHERE과 HAVING의 사용에 주의해야한다! ** 이 문제의 핵심!!

 

참고로, mysql 문법 작성순서는 다음과 같다

SELECT 컬럼명
FROM 테이블명
WHERE 조건식
GROUP BY 칼럼명
HAVING 조건식
ORDER BY 칼럼명

하지만, 실행작동순서는 작성 순서와 다르다!!

위의 경우로만 보면,

FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY

 

여기서 WHERE 과 HAVING 의 차이가 드러난다

WHERE : 그룹화하기 전의 조건

HAVING : 그룹화 후의 조건

 

따라서, 문제를 보면,

이름이 없는 동물은 집계에서 제외

-> 집계(GROUP BY)를 하기 전에 미리 걸러주어라! 하는 의미이므로

WHERE NAME IS NOT NULL 을 사용

 

동물 이름 중 두 번 이상 쓰인 이름과 해당 이름이 쓰인 횟수를 조회

동물 이름으로 GROUP 화를 먼저 한 후에  (GROUP BY NAME)

"두번 이상" 이라는 조건을 걸어주면 된다! 

따라서 HAVING COUNT > 1  을 사용

 

4. 마지막으로 결과는 이름순으로 조회하라 했으므로,

ORDER BY NAME

 

 

 

 

1. 최댓값구하기

가장 최근에 들어온 동물은 언제 들어왔는지 조회하는 SQL 문을 작성해주세요.

 

sol (1) ORDER BY를 사용

SELECT DATETIME
FROM ANIMAL_INS
ORDER BY DATETIME DESC LIMIT 1

<SELECT문>에서 풀었듯이,

DATETIME을 내림차순으로 정렬하면 가장 최근 날짜가 가장 위에 오게 됨

따라서, "LIMIT 1"을 사용함으로써 하나!만 

 

sol (2) MAX 함수 사용 

SELECT MAX(DATETIME)
FROM ANIMAL_INS

최댓값 : SELECT MAX(컬럼) FROM 테이블

참고로, AS(Alias)를 이용하여 컬럼명 정의할 수 있음

ex) SELECT MAX(DATETIME) AS date FROM ANIMAL_INS 라 쓰면, 출력할 컬럼의 명을 date로 지정한다는 의미!

 

2. 최솟값 구하기

동물 보호소에 가장 먼저 들어온 동물은 언제 들어왔는지 조회하는 SQL 문을 작성해주세요.

 

sol (1) ORDER BY를 사용

SELECT DATETIME
FROM ANIMAL_INS
ORDER BY DATETIME LIMIT 1

DATETIME을 ORDER BY해주면, 기본 설정이 오름차순이므로 오름차순 정렬

따라서 가장 먼저 들어온 날짜(맨 처음 날짜)가 맨 위에 오게 된다!

따라서 LIMIT 1 을 사용함으로써 하나!만

 

sol (2) MAX 함수 사용 

SELECT MIN(DATETIME)
FROM ANIMAL_INS

최소값 : SELECT MIN(컬럼) FROM 테이블

 

3. 동물 수 구하기 => 집계함수 (COUNT)

동물 보호소에 동물이 몇 마리 들어왔는지 조회하는 SQL 문을 작성해주세요.

SELECT COUNT
FROM ANIMAL_INS

수를 세는 함수 : COUNT

 

4. 중복 제거하기 - DISTINCT

동물 보호소에 들어온 동물의 이름은 몇 개인지 조회하는 SQL 문을 작성해주세요. 이때 이름이 NULL인 경우는 집계하지 않으며 중복되는 이름은 하나로 칩니다.

SELECT COUNT(DISTINCT NAME)
FROM ANIMAL_INS
WHERE NAME IS NOT NULL

몇 개인지? => COUNT

중복된 이름은 하나로 친다 == 중복 제거 => DISTINCT 함수 사용

  • DISTINCT 칼럼명 : 해당 칼럼에서 중복된 값 제거 

NAME이 NULL인 경우는 집계하지 않으므로, 조건문 사용

1. 모든 레코드 조회하기 

동물 보호소에 들어온 모든 동물의 정보를 ANIMAL_ID순으로 조회하는 SQL문을 작성해주세요. 

SELECT *
FROM ANIMAL_INS
ORDER BY ANIMAL_ID

SELECT(조회) * (모든 정보)

FROM ANIMAL_INS (ANIMAL_INS 테이블에서)

ORDER BY ANIMAL_ID ( ANIMAL_ID를 오름차순으로 정렬)

 

Order by는 "ASC" (오름차순)이 기본적으로 설정되어 있어서 굳이 작성하지 않아도 된다

 

2. 역순 정렬하기

동물 보호소에 들어온 모든 동물의 이름과 보호 시작일을 조회하는 SQL문을 작성해주세요. 이때 결과는 ANIMAL_ID 역순으로 보여주세요. 

SELECT NAME, DATETIME
FROM ANIMAL_INS
ORDER BY ANIMAL_ID DESC

SELECT 옆에는 조회하고자하는 컬럼 이름을 작성해주면 된다. 

 

"역순"으로 정렬 이므로, DESC를 사용!

 

3. 아픈 동물 찾기 - 조건문

동물 보호소에 들어온 동물 중 아픈 동물의 아이디와 이름을 조회하는 SQL 문을 작성해주세요. 이때 결과는 아이디 순으로 조회해주세요.

SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
WHERE INTAKE_CONDITION = "Sick"
ORDER BY ANIMAL_ID

아픈 동물을 조회해야하므로 "조건문"을 사용해야한다

조건문 : WHERE 조건

이때, 아픈 동물은 INTAKE_CONDITION이 "Sick"인 경우이므로 위와 같은 코드가 완성된다!

 

더보기

아픈동물이 "Normal이 아닌 경우" 인줄 알고 계속 제출했다가 엄청 틀렸다

다음부턴 문제를 잘 읽어야겠다..

 

4. 어린 동물 찾기 - 조건문

동물 보호소에 들어온 동물 중 젊은 동물의 아이디와 이름을 조회하는 SQL 문을 작성해주세요. 이때 결과는 아이디 순으로 조회해주세요.

SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
WHERE INTAKE_CONDITION != "Aged"
ORDER BY ANIMAL_ID

젊은 동물은 INTAKE_CONDITION이 "Aged"가 아닌경우이므로, 조건문에 위와 같이 작성

 

5. 동물 아이디와 이름

동물 보호소에 들어온 모든 동물의 아이디와 이름을 ANIMAL_ID순으로 조회하는 SQL문을 작성해주세요. 

SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
ORDER BY ANIMAL_ID

 

6. 여러 기준으로 정렬하기 

동물 보호소에 들어온 모든 동물의 아이디와 이름, 보호 시작일을 이름 순으로 조회하는 SQL문을 작성해주세요. 단, 이름이 같은 동물 중에서는 보호를 나중에 시작한 동물을 먼저 보여줘야 합니다.

SELECT ANIMAL_ID,NAME,DATETIME
FROM ANIMAL_INS
ORDER BY NAME ASC, DATETIME DESC

 

" ORDER BY A (ASC/DESC), B (ASC/DESC)" 의 의미는

A 기준으로 정렬하되, 동일한 A 발생시, B 기준으로 정렬한다는 의미

 

Q. A에 ASC를 생략해도 같은 결과가 나오는가? 

SELECT ANIMAL_ID,NAME,DATETIME
FROM ANIMAL_INS
ORDER BY NAME, DATETIME DESC

A. 같은 결과가 나온다.

A와 B 조건은 따로기때문에

"ORDER BY A, B DESC" 로 쓴다고 해서 A 내림차순, B 내림차순 절대! 아니다!!

 

7. 상위 n개 레코드 - MySQL(LIMIT 사용), ORACLE(rownum, 서브쿼리문 사용)

동물 보호소에 가장 먼저 들어온 동물의 이름을 조회하는 SQL 문을 작성해주세요.

 

* mysql

SELECT NAME
FROM ANIMAL_INS
ORDER BY DATETIME LIMIT 1

Mysql 에서는 ORDER BY에 "LIMIT n "를 사용해서 조회할 레코드 상위 n개를 설정해주면 된다

Limit를 사용하면 ~부터 ~까지도 조회할 수 있다

즉,

ORDER BY DATETIME LIMIT 5, 9  : DATAETIME으로 정렬한 후, 상위 5번째부터 9번째까지 조회! 

 

* oracle

SELECT NAME
FROM (SELECT *
      FROM ANIMAL_INS
      ORDER BY DATETIME)
WHERE rownum = 1;

oracle은 살짝 복잡하다 rownum을 써야한다는 거까지는 알았는데 

SELECT NAME FROM ANIMAL_INS ORDER BY DATETIME WHERE rownum = 1;

로 썼다가 계속 에러가 났었다;; 

 

Q. rownum을 사용할 때, subquery를 사용해야 하는 이유?

 

A. rownum은 각 행에 대한 일련번호를 의미하는데, 선택된 테이블의 레코드에 자동으로 순차적으로 번호가 부여된다. 

따라서, 테이블을 선택한 후에 특정 칼럼으로 정렬하여도, rownum은 정렬 전에 설정한대로 부여되어 있다.. 

즉, rownum은 테이블에 먼저 입력!(INSERT)된 순서대로 숫자가 부여되어서, 정렬을 하든 무슨짓을 하더라도 고유의 rownum을 가지고 있다..

따라서 원하는 테이블을 생성하여 사용해주면 되는데,, 그렇다고 새로운 테이블을 생성할 수도 없으니,, 

일시적으로 사용이 가능한 Inline view( from절에서 사용하는 subquery)를 사용한다!

생성된 테이블에 고유번호 rownum을 부여한 후에, 조건문을 사용하여 원하는 수 만큼 조회하면 된다!

 

 

프로그래머스 SQL 고득점 kit - SELECT

https://programmers.co.kr/learn/courses/30/parts/17042

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

database backup을 위한 코드

use madang;
DROP TABLE IF EXISTS Orders ;
DROP TABLE IF EXISTS Book;
DROP TABLE IF EXISTS Customer;
DROP TABLE IF EXISTS Imported_Book;

 

여기에서 "Error Code: 1049. Unknown database 'madang'"에러가 발생

 

해결방안..

use madang; 위에

CREATE DATABASE madang;

use madang;
-- ...

코딩테스트를 파이썬으로 준비해보려고 오랜만에 파이썬을 만지작만지작 해보는데 걸리는게 많다...

책이나 프로그래머스 문제를 파이썬으로 풀면서 막히던 문법을 차례로 정리할 예정!

 

가장 기본적이었던 것.. 입력

 

입력의 기본

# 숫자 입력받기

파이썬에서 데이터를 입력받는 방법 : input( )

정수형 데이터로 처리하기 위해서는 앞에 int( ) 함수를 사용

n = int(input())

 

# 공백을 기준으로 구분하여 변수에 각각 정수형으로 저장하기 

map( )함수를 사용하여 각각 매핑하기라고 생각하면 됨

split( )를 이용하여 공백으로 구분하고 int를 앞에 적음으로써 정수형으로 저장

n,m,k = map(int,input().split())

 

# 여러개의 숫자를 입력받아 공백으로 구분하여 리스트 형태로 저장하기 ★★

input( )으로 입력받은 문자열을 공백으로 구분하기 위해서 split( )함수를 사용

공백으로 나눈 리스트로 바꾼 뒤에(list( )함수 사용) map( )을 이용하여 리스트의 모든 원소에 int( )함수를 적용

입력 받은 문자열을 공백으로 구분하여 각각 숫자 자료형으로 저장할 수 있도록 한다.

data = list(map(int, input().split()))

더 빠른 입력!

input( ) 대신 sys 라이브러리에 정의되어 있는 sys.stdin.readline( )함수 사용

sys.stdin.readline( )함수를 통해 sys 라이브러리를 사용할 때는 한 줄 입력 받음

readline( )을 입력하면 Enter를 치면 줄 바꿈 기호로 입력이 되는데, 이를 제거하기 위해 rstrip( )를 사용

 

import sys
data = sys.stdin.readline().rstrip()

 

출력의 기본

출력할 때, 단순히 print()만 쓰면 됨

print( )쓰면 출력되면서 줄바꿈이 자동으로 수행됨

a = 1
print(a)

 

"TypeError : can only concatenate str (not "int") to str"

자바에서 처럼 + 연산자를 이용하여 문자열과 수를 더하려고 하면 오류가 발생!

 

해결 방안

1) str( )함수 이용 : 출력하고자 하는 변수 데이터를 문자열로 변경

2) 콤마(,) 이용 : 각 자료형을 콤마를 기준으로 구분하여 출력

3) f-string 이용 : 문자열 앞에 접두사 f를 붙임으로써 중괄호 안에 변수를 넣으면 됨

answer = 7

#해결방안 1
print("정답은 "+str(answer)+"입니다")

#해결방안 2
print("정답은",str(answer),"입니다")

#해결방안 3
print(f"정답은 {answer}입니다")

→ 참고로 해결방안 1의 경우, 두 문자열 사이에 공백을 넣기 위해서는 직접 코드에 넣어야 하지만, 해결방안 2의 경우에는 넣지 않아도 공백이 자동 입력 된다

 

 

static 메서드와 인스턴스 메서드

메서드 앞에 static이 붙으면 static 메서드라 함 (클래스 메서드라고도 함)

static이 안 붙으면 인스턴스 메서드라 함

두 메서드를 구별하는 기능적인 차이는 인스턴스 멤버의 사용 여부이다. 

 

인스턴스 메서드

인스턴스 생성 후 '참조변수.메서드 이름()'으로 호출함

인스턴스 변수(iv), 인스턴스 멤버(im)와 관련된 작업을 함

메서드 내에서 iv 사용 가능

 

static 메서드

객체 생성 X

'클래스 이름.메서드 이름()'으로 호출함

인스턴스 변수(iv), 인스턴스 멤버(im)와 관련되지 않은 작업을 함

메서드 내에서 iv 사용 불가능

 

 

예시1

class mymath{
	long a,b; //인스턴스 변수
    
    long add(){	//인스턴스 메서드
    	return a+b;
    }
    
    static long add(long a, long b){ 	//클래스 메서드(static 메서드)
    	return a+b; //지역변수 a,b
    }   
}

static메서드와 인스턴스 메서드 호출은 다음과 같다. 

class example{
	public static void main(Stringp[] args){
    
    	System.out.println(mymath.add(200L,100L); //클래스(static)메서드 호출
 
 
    	mymath mm = new mymath();	//인스턴스 생성
        mm.a = 200L;
        mm.b = 100L;
        System.out.println(mm.add()); // 인스턴스 메서드 호출
   }
}

 

예시2

class Test{
	int iv;	//인스턴스 변수
   	 static int cv; //클래스 변수
    
    void instanceMethod1(){}
    static void staticMethod1(){}
    
    void instanceMethod(){
    	System.out.println(iv);
        System.out.println(cv);
        //iv,cv 모두 사용 가능
        
        instanceMethod1();
        staticMethod1();
        //인스턴스 메서드와 static메서드 모두 호출 가능
    }
    
    static void staticMethod(){
    	//System.out.println(iv);	//iv 사용 불가능!!
        System.out.println(cv);
        
       //instanceMethod1();			//인스턴스 메서드 호출 불가능!!
        staticMethod1();
        
    }
    
}

즉!! static 메서드는 인스턴스 변수와 인스턴스 메서드 모두 호출 불가능!! 나머지는 가능

 

 

메서드의 매개변수 

메서드의 매개변수 타입은 기본형, 참조형으로 나눌 수 있음

 

기본형 매개변수

변수의 값을 읽기만 하고 변경은 불가능함

class Data{
	int x;
}

class example{
	public static void main(String[] args){
    	Data d = new Data();	//객체 생성
        d.x = 10;
        System.out.println(" main() : x = "+ d.x);
        
        change(d.x);
        System.out.println(" main() : x = "+ d.x);
     }
     static void change(int x){		//기본형 매개변수
     	x = 1000;
        System.out.println("change() x : "+x);
}

"main() :  x = "에 대한 두개의 출력값은 모두 "10"이다. 

"change() x"는 1000이 출력된다. 

change( )호출이 되어서 x값을 1000으로 바꾸더라도 지역변수를 바꾼 것이기 때문에, 그대로 10만 출력되는 것

 

"기본형 매개변수"는 "읽기"만 가능함!!

 

참조형 매개변수

변수의 값을 읽고 변경 할 수 있음

class Data{
	int x;
}

class example{
	public static void main(String[] args){
    	Data d = new Data();	//객체 생성
        d.x = 10;
        System.out.println(" main() : x = "+ d.x);
        
        change(d);
        System.out.println(" main() : x = "+ d.x);
     }
     
     static void change(Data d){		//참조형 매개변수
     	d.x = 1000;
        System.out.println("change() x : "+d.x);
}

change() 이전 출력값은 10이고, change( ) 이후 출력되는 모든 값이 "1000"이다. 

change( )의 매개변수가 type이 기본형이 아니기 때문에 참조형 매개변수~! 

 

 main( )이 change( )에 객체 d에 대한 "리모콘"을 줬다고 생각하면 조금.. 쉽다!

 

참조형 반환타입

class Data{
	int x;
}

class example{
	public static void main(String[] args){
    	Data d = new Data();	//객체 생성
        d.x = 10;
        
        Data d2 = copy(d);
        System.out.println("d.x = "+ d.x);
        System.out.println("d2.x = "+d2.x); 
     }
     
     static Data copy(Data d){		//참조형 매개변수
     	Data tmp = new Data(); //새로운 객체 tmp 생성
        
        tmp.x = d.x //d.x의 값을 tmp.x에 복사
        
        return tmp;	//복사한 객체의 주소 반환
     }
}

출력값은 d.x와 d2.x 모두 10이다.

 

stack이란? 

밑이 막히고 위가 뚫린 상자라고 생각하면 된다. 위에 차곡 차곡 쌓인다. 

따라서 꺼낼때는 제일 위에있는 것부터 차례로 꺼낸다. 

★ 중간에 끼워 넣거나 아래 있는 것을 빼낼 수 없다

 

call stack이란?

메서드 수행에 필요한 메모리가 제공된 공간으로,

메서드가 호출되면 호출 스택에 메모리를 할당하고 종료 시 해제 한다. 

 

예시로 설명하자면.. 

1. 호출 스택에 main( )이 있음

2. main()이 println()을 호출

3. 호출 스택에 아래서부터 차례로 main( ) , println( )이 쌓여 있음

 이때, main( )은 대기상태, println( )은 실행상태 

4. println( )이 종료

5. 호출스택에 main( )만 남음

 

따라서.. 

→ 아래에 있는 메서드가 위에 있는 메서드를 호출한 것

→ 하나의 스택에서는 한개의 메서드만 실행, 나머지는 대기 상태

 

코드 분석 시, 단계별로 호출 스택을 직접 그려보면 프로그램의 실행과정을 정확히 이해할 수 있음!

 

 

+ Recent posts