(JAVA) 자바 플랫폼 3대 구성요소 (JDK, JRE, JVM)

자바, 스프링 강의를 듣거나 책을 보다보면 JDK, JRE, JVM에 대한 내용이 가끔 나온다.
강의에서 나올때마다 자바의 필수요소인가보다 하며 지나쳤었지만 이번 포스팅을 통해 짚어보고 넘어가려 한다.

JDK (자바 개발 키트, Java Development Kit)


JDK란

자바 플랫폼의 등장 이래 지금까지 가장 널리 사용되고 있는 소프트웨어 개발 키트(SDK) - 위키백과

즉, Java로 소프트웨어를 개발할 수 있도록 여러 기능들을 제공하는 패키지이다.

JDK의 구성

Java로의 개발을 담당하는 패키지답게 매우 많다. 자주 들어본것만 간추려보자면

  • javac : 자바 컴파일러, 자바 소스파일(.java)을 바이트코드(.class)로 변환한다.
  • java : javac가 만든 클래스 파일을 해석 및 실행한다.
  • jar : 서로 관련있는 클래스 라이브러리들과 리소스를 하나의 파일로 묶어주는 도구이다.
  • JDB : Java Debugger, 자바 디버깅 툴
  • JRE (Java Runtime Environment) : Java가 동작하는데 필요한 JVM, 라이브러리 등 다양한 파일들을 포함한다. Java를 실행시키기 위해필요하다.
  • JVM(Java Virtual Machine) : Java가 실제로 동작하는 가상환경. JVM 덕분에 하나의 소스파일을 만들더라도 여러 환경(OS) 에서 원활히 동작이 가능하다.

JDK의 종류

  1. Java SE : Standard Edition
    표준 자바 플랫폼으로 표준적인 컴퓨팅 환경을 지원하기 위한 자바 가성머신 규격 및 API 집합을 포함한다.
    이후의 Java EE, Java ME는 구체적인 목적에 따라 Java SE를 기반으로 API를 추가하거나 자바 가상머신 규격 및 API의 일부를 택하여 정의 된다.
  2. Java EE : Enterprise Edition
    Java SE에 웹 어플리케이션 서버에서 동작하는 기능을 추가한 플랫폼
    이 스펙에 따라 제품을 구현한 것을 웹 어플리케이션 서버( WAS )라 한다.(톰캣 등)
  3. Java ME : Micro Edition
    제한된 자원을 가진 휴대전화, PDA 등에서 Java 프로그래밍 언어를 지원하기 위해 만든 플랫폼 중 하나이다.

JRE (자바 런타임 환경, Java Runtime Environment)


컴파일된 자바 프로그램을 실행시킬 수 있는 자바 환경을 말한다.
자바 프로그램을 실행시키기 위한 라이브러리, JVM, 기타 파일들을 포함하고있다.
자바 프로그램을 실행시키기 위해서는 JRE를 반드시 설치해야하고 JRE에는 개발과 관련된 도구는 포함되어 있지 않다.

JVM (자바 가상 머신, Java Virtual Machine)


JVM은 Java Virtual Machine(자바 가상머신)의 약자로 자바 소스코드로 만들어지는 자바 바이트코드 파일을 실행할 수 있다.
JVM은 자바와 다르게 플랫폼에 의존적므로 맥, 윈도우, 리눅스의 JVM은 각각 다르다.
하지만 컴파일된 바이트코드 파일은 어떤 JVM에서도 동작시킬 수 있다. 즉, 코드를 작성하면 JVM이 설치된 어떤 플랫폼에서도 동작시킬수 있다.

JVM의 역할은 다음과 같다.

  • 바이트코드를 읽는다.
  • 바이트코드를 검증한다.
  • 바이트코드를 실행한다.
  • 실행환경(Runtime Environment)의 규격을 제공한다. (필요한 라이브러리 및 기타파일)

마지막으로 각각의 관계를 살펴보면 다음 그림과 같다.
JDK, JRE, JVM의 관계

Reference.

자바 개발키트 위키백과
[Java] Java SE, JDK, JRE

SQL리뷰 수업 코드정리-5

5일차 코드


Discus_Gold_Medal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 성별, 연도 (2004, 2008, 2012), 현재 국가 (as Champion), 이전 국가
-- 조건 : Event명 'Javelin Throw', Medal = Gold
WITH Discus_Gold_Medal AS ( -- 아래 서브쿼리의 이름
SELECT
gender -- 성별, 연도, 종목, 국가(as 챔피언)
, year
, event
, country AS champion
FROM summer_medals -- 조회 테이블
WHERE
Year IN (2000, 2004, 2008, 2012) -- year컬럼이 2000, 2004, 2008, 2012 중에 하나이며
AND Medal = 'Gold' -- medal컬럼이 Gold이며
AND Event = ('Javelin Throw')) -- event컬럼이 Javelin Throw 인것

SELECT
gender -- 성별, 연도, 종목, 현재 1위국가,
, year
, event
, champion,
LAG(Champion) OVER -- LAG(컬럼, 숫자(기본값1)) = 괄호안의 컬럼의 이전값(숫자만큼)을 건너뛰고 가져와 컬럼을 새로 만듦,
(PARTITION BY gender ORDER BY Event ASC, Year ASC) AS -- 파티션을 gender로 분류, event와 year의 오름차순 정렬
Last_Champion -- as Last_Champion
FROM Discus_Gold_Medal -- 위에서 생성한 Discus_Gold_Medal 테이블에서 조회
ORDER BY gender asc, year ASC; -- gender, year의 오름차순 정렬

위 쿼리의 출력

서브쿼리가 정렬되어 출력되고, last_champion이 바로 전 대회의 우승국을 출력하는것을 볼 수 있다.

Athletics_Gold

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 경기종목을 2개로 추가 ('100M', '10000M')

WITH Athletics_Gold AS ( -- 이하 서브쿼리의 이름
SELECT
gender -- 성별, 연도, 종목, 국가(as champion) 조회
, year
, event
, country AS champion
FROM summer_medals -- 조회 테이블
WHERE
Year IN (2000, 2004, 2008, 2012) -- year컬럼이 2000, 2004, 2008, 2012 중에 하나이며
AND Medal = 'Gold' -- medal컬럼은 Gold
AND Event IN ('100M', '10000M')) -- 100M 또는 10000M 종목인것

SELECT
gender -- 성별, 연도, 종목, 현재 1위국가
, year
, event
, champion,
LAG(Champion) OVER
(PARTITION BY gender, event ORDER BY Year ASC) AS -- 파티션을 gender와 event로 분류하고 year의 오름차순으로 정렬
Last_Champion -- as Last_Champion
FROM Athletics_Gold -- 위 쿼리에서 생성한 Athletics_Gold 테이블에서 조회
ORDER BY gender asc, event ASC, year ASC; -- gender, event, year의 순서대로 오름차순 정렬

위 쿼리의 출력

DiscusThrow_Gold

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- year, athlete, future_champion(3회 이후 챔피언)
-- 조건 : Medal =Gold / event = discus Throw / gender women / year >= 1992
-- lead(컬럼명, 3) over()
WITH DiscusThrow_Gold AS ( -- 이하 서브쿼리의 이름
select
year -- 연도, 선수 조회
, athlete
from summer_medals -- 조회 테이블
where
medal = 'Gold' -- 조건들 : medal컬럼이 Gold이며,
and event = 'Discus Throw' -- event컬럼이 Discus Throw,
and gender = 'Women' -- gender컬럼이 Women,
and year >= 1992 -- year컬럼이 1992 년 이후인것
)

select
year -- 연도, 선수, future_champion
, athlete
, lead(athlete, 3) over -- lead(컬럼, 숫자(기본값1)) = 괄호안의 컬럼의 이후값(숫자만큼)을 건너뛰고 가져와 컬럼을 새로 만듦
() as future_champion -- as future_champion
from DiscusThrow_Gold; -- DiscusThrow_Gold 테이블에서 조회

위 쿼리의 출력

이전까지 쿼리에서 사용된 LAG함수와 LEAD함수는 다음 절에서 설명한다.

LAG() 함수와 LEAD() 함수


LAG() 함수

LAG 함수의 사용 예

LAG함수는 보통 LAG(column, n(기본값1))의 형태인데 이는 현재 행 앞의 행에 있는 열의 값을 반환한다.

그렇기 때문에 위 사진에서 last_champion의 첫번째 결과는 null이 된다(앞의 결과가 없기때문)

이후 부터는 champion컬럼의 결과가 차례로 출력된다.

참고로 5번 열에서의 null은 gender를 partition by로 나누었고 현재 행의 앞의 열을 분리시킨상태이기 때문에 null값이 조회된다.


LEAD() 함수

LEAD 함수의 사용 예

기본적인형태는 LEAD(column, n(기본값1))의 형태이며,

LEAD 함수는 LAG 함수와는 반대로 현재 행 뒤의 행에 있는 열의 값을 반환한다.

사진에서 사용한 코드는 LEAD(athlete,3) 이므로 3칸 뒤의 열의 값을 반환한다.

이후 athlete컬럼의 결과가 차례로 출력되며 3번열 이후의 값은 존재하지 않기때문에 null이 반환된다.

SQL리뷰 수업 코드정리-4

4일차 코드


summer_medals 테이블

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
select * from summer_medals;

-- row_number()
-- 각 행에 숫자를 1, 2, 3, ..., N 형태로 추가한다.
-- 오름차순으로 기준을 진행한다.
-- 기본적 row_num만 추가
select
row_number() over() as row_num
, *
from summer_medals;

-- 올림픽 연도를 오름차순 순번대로 작성을 한다.
-- 연도 중복값 제거
-- 서브쿼리 : select distinct year from summer_medals order by year asc;
select
row_number() over() as row_num -- 각 행에 오름차순으로 숫자 추가 as row_num, year행 출력
, year
from
(select distinct year from summer_medals order by year asc) as years -- 중복값을 제거한 year 컬럼을 오름차순으로 출력 as years
order by year asc; -- select절의 컬럼들을 year컬럼의 오름차순으로 정렬

select * from summer_medals;

-- 운동선수 메달 갯수 쿼리 작성
with athlete_medals as (
select
athlete -- athlete, 전체 컬럼을 count하고 athlete로 묶음(group by절) as medal_counts
, count(*) medal_counts
from summer_medals
group by athlete
)
select
athlete -- athlete, medal_counts, medal_counts의 내림차순으로 숫자를 붙인 row_num 출력
, medal_counts
, row_number() over(order by medal_counts desc) as row_num
from athlete_medals
order by medal_counts desc -- select절의 컬럼들을 medal_counts의 내림차순으로 정렬
limit 10; -- 상위 10개만 출력

-- 남자 69 KG 역도 경기에서 금메달 리스트 추출.
-- Discipline = 'Weightlifting'
-- Event 69KG,
-- Gender
-- Medal
select * from summer_medals;
select distinct event, discipline, athlete, gender from summer_medals where event = '200M' and gender = 'Women' and medal = 'gold';

select
year -- 연도, 국가 as champion 출력
, country as champion
from
summer_medals
where
discipline = 'Weightlifting' and -- 종목 = 역도,
event = '69KG' and -- 세부종목 = 69KG,
gender = 'Men' and -- 성별 = 남자,
medal = 'Gold'; -- 금메달만, 상기 4개 조건 모두 만족하는결과만 출력

-- LAG

with weightligting_69_men_gold as (
select
year
, country as champion
from
summer_medals
where
discipline = 'Weightlifting' and
event = '69KG' and
gender = 'Men' and
medal = 'Gold'
)

select
year
, champion
, LAG(champion) over(order by year asc) as last_champion
from weightligting_69_men_gold
order by year asc;

-- Athletics, 200미터, 여자, 금메달 목록 가져오기
-- 나라 대신 선수이름 출력 year, 현재 챔피언 이름, 이전 챔피언 이름

with Athletics_200_Women_Gold as (
select
year
, athlete as champion
from
summer_medals
where
discipline = 'Athletics' and
event = '200M' and
gender = 'Women' and
medal = 'Gold'
)

select
year
, champion
, lag(champion) over(order by year asc) as last_champion
from Athletics_200_Women_Gold
order by year asc;

-- partition by 함수
-- partition by 미적용
WITH Discus_Gold_Medal AS (
SELECT
Year, Event, Country AS Champion
FROM summer_medals
WHERE
Year IN (2004, 2008, 2012)
AND Gender = 'Men' AND Medal = 'Gold'
AND Event IN ('Discus Throw', 'Triple Jump')
AND Gender = 'Men')

SELECT
YEAR, Event, Champion,
LAG(Champion) OVER
(ORDER BY Event ASC, Year ASC) AS Last_Champion
FROM Discus_Gold_Medal
ORDER BY Event ASC, Year ASC;

-- partition by 적용
WITH Discus_Gold_Medal AS (
SELECT
Year, Event, Country AS Champion
FROM summer_medals
WHERE
Year IN (2004, 2008, 2012)
AND Gender = 'Men' AND Medal = 'Gold'
AND Event IN ('Discus Throw', 'Triple Jump')
AND Gender = 'Men')

SELECT
YEAR, Event, Champion,
LAG(Champion) OVER
(PARTITION BY Event ORDER BY Event ASC, Year ASC) AS
Last_Champion
FROM Discus_Gold_Medal
ORDER BY Event ASC, Year ASC;

자바스크립트(Javascript) 기록-4

태그 다루기


중간제목에서 말하는 태그를 다룬다는 것은 태그의 내부 속성을 수정한다는 것이다.

강의에서 나왔던 대로 h1태그를 사용하여 적어보면

1
h1.className = "";

가장먼저 클래스를 바꿀수 있는 속성인 .className이다.

“” 내부에 입력한 클래스로 바뀌게 되는데 문제는 원래 있던 클래스가 사라지고 입력한 클래스만 새로 추가되는 것이다.

1
h1.classList.(Element)

그래서 .classList를 불러와 클래스를 추가하는 방법이 있는데

추가는 h1.classList.add로 클래스를 추가 할 수 있으며,

삭제는 h1.classList.remove로 삭제가 가능하다.

여기에 if문을 추가해준다면 특정 이벤트(클릭 등)에 따라 클래스의 추가와 삭제가 반복되게 만들수도 있다.

그런데 이렇게 반복을 하게 할때는 addremove를 쓰면 코드가 길어지게 되는데 이럴때를 위해 있는게 toggle 속성이다.

1
2
3
4
5
if (h1.classList.contains("clicked")) { // .contains()는 괄호 내부의 클래스가 존재하는지 확인
h1.classList.remove("clicked");
} else {
h1.classList.add("clicked");
}

addremove 를 쓰면 다섯줄이였던 코드가

1
h1.classList.toggle("clicked");

toggle을 사용하면 이정도로 줄어들게 된다.

설명에 생략이 매우 많지만 사용법은 대략 이렇다.

이외에도 태그별로 많은 속성이 있으며, MDN Web Docs 에서 찾아볼 수 있다.

.preventDefault


.preventDefault는 이벤트가 발생했을때 그 이벤트의 기본동작을 막는다.

예를들어 ‘submit’ 이벤트가 발생했을때 브라우저는 기본적으로 페이지를 새로고침한다.

이런것들이 기본동작인데 이를 막아주는것이 .preventDefault 이다.

사용 예는 다음과 같다.

1
2
3
4
function func(event) {
event.preventDefault();
console.log(event);
}

이렇게 이벤트의 동작을 막고 콘솔에서 이벤트의 로그를 볼 수 있다.

새로고침을 막는등의 기능 이외에도 클릭시 링크로의 이동을 막거나, form의 제출을 막는등 여러가지를 할 수 있다.

백틱(``)으로 문자열 작성


문자열과 변수를 합쳐서 출력하려면 언어를 처음 배우기 시작한 사람들은 보통 다음과 같이 출력할 것이다

1
2
const a = "world";
console.log("hello " + a;);

그런데 파이썬의 포맷함수처럼 사용할수 있는 기능이 JS에도 있다.

사용법은 다음과 같다.

1
2
const a = "world";
console.log(`hello ${a}`);

띄어쓰기를 따로 생각하지 않아도 되고 + 부호가 지저분해보였기 때문에 이 방법이 필자에게는 더욱 깔끔해 보였다.

SQL리뷰 수업 코드정리-3

3일차 코드


languages 테이블

couintries 테이블

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
-- 서브쿼리 쓰는 방식
-- where 절 서브쿼리
-- select 절 서브쿼리
-- from 절 서브쿼리

select * from languages;
select * from countries;

-- 질문 : 각 나라별 언어의 갯수 구하기
-- Table: languages
select code, count(*) as lang_num -- 국가 코드, 모든행을 카운트해 lang_num 으로 출력
from languages -- 사용한 테이블
group by code; -- 국가 코드로 묶을것
-- 결과 : 각각의 국가 코드로 묶인 lang_num 출력

-- 질문, country로 변경하고, 언어의 갯수 구하기
-- lang_num을 내림차순으로 정렬함.
-- 이 쿼리서 from절 서브쿼리 사용
select local_name, subquery.lang_num -- countries 테이블의 local_name, (as)subquery 에서 lang_num을 각각 출력
from countries -- 테이블은 countries 와 다음의 서브쿼리
, (select code, count(*) as lang_num -- 전 질문의 쿼리를 가져와 'subquery' 명칭을 붙임
from languages
group by code) as subquery
where countries.code = subquery.code -- countries.code 와 subquery.code가 매칭이 될 경우만 조회
order by lang_num desc; -- lang_num을 내림차순으로 정렬
-- 결과 : countries.local_name과 subquery.lang_num이 각각 lang_num의 내림차순으로 출력

--
select * from economies
where year = 2015;

-- 코드별 inflation_rate
-- 각 대륙별, 각 나라별 inflation_rate
-- 각 대륙에서 inflation_rate가 가장 높은, inflation_rate를 출력

SELECT name, continent, inflation_rate -- name, continet, inflation_rate 를 조회
FROM countries -- countries 테이블
INNER JOIN economies -- inner join = 기준테이블, 조인테이블 모두에 해당 값이 존재할 경우 메인쿼리 조회
on countries.code = economies.code -- economies 와 countries.code = economies.code 에 겹치는 값이 있는지
WHERE year = 2015 -- year항목이 2015이고
and inflation_rate in ( -- inflation_rate 항목에 다음 서브쿼리의 값이 있는지
SELECT MAX(inflation_rate) AS max_inf -- 가장 큰 inflation_rate를 조회
FROM ( -- 다음의 서브쿼리에서
SELECT name, continent, inflation_rate -- name, continent, inflation_rate 조회
FROM countries -- countries 테이블
INNER JOIN economies -- economies 와
on countries.code = economies.code -- countries.code = economies.code 에 겹치는 값이 있는지
WHERE year = 2015) AS subquery -- year = 2015인 것만 조회 ) subquery로 명명
GROUP BY continent); -- 바로 위에서 출력한 서브쿼리를 continent로 묶음
-- 결과 : countries테이블의 name, continent, inflation_rate 조회 group by 때문에 대륙별로 한 나라씩만 조회되었고 조회된 나라의 기준은 inflation_rate가 가장 높은 국가

마지막 쿼리의 출력 결과

첫번째와 두번째 쿼리는 직접 작성하지는 못해도 해석은 할 수 있었는데 마지막 쿼리는 정말이지 복잡했다.
강의 뿐만 아니라 책도 구매해서 SQL를 더 파야 할 듯.

자바스크립트(Javascript) 기록-3

document


자바스크립트는 기본적으로 HTML의 모든 항목을 읽고 변경이 가능하다.

HTML 파일의 모든것이 document 객체로 담겨있는데 자바스크립트는 document 객체를 object 타입으로 가져와 내부의 값을 변경 할 수 있다.

사용 예시는 다음과 같다.

1
document.title = "hello";

이렇게 한다면 HTML의 title태그에 내용이 있더라도 페이지의 제목이 hello로 바뀌게 된다.

document 내부에는 title, head, body 등 여러가지 태그가 object 타입으로 담겨있다.

getElementById


getElementById는 HTML의 특정 개체를 가져오는 기능이다.

사용예시를 먼저 보자.

1
<h1 id="title">hello</h1>

이런 HTML태그가 있다고 할 때

1
document.getElementById("title");

이라면 HTML에서 태그의 id값(태그값 자체가 아니다! <title>태그와 혼동하지 말자)이 title인 태그를 가져온다.

1
2
const h1Tag = document.getElementById("title");
h1Tag.innerText = "hi";

이처럼 변수에 저장해 객체처럼 사용 할 수도 있다.

console.dir


console.log가 console에 로그를 찍어주는 역할이라면 console.dir은 이를 통해 가져온 태그 내부의 모든 정보를 object 타입으로 가져온다.

1
console.dir(document);

이렇게 하면 document의 모든 정보가 object 타입으로 콘솔에 출력된다.

출력된 정보를 보고 수정, 추가, 삭제, 이벤트 등 여러방면으로 활용이 가능하다.

querySelector


querySelector 역시 태그를 가져올수 있는태그이다.

먼저 사용 예제를 보자

1
2
3
<div class="hello">
<h1>hello!</h1>
</div>
1
2
3
const h1 = document.querySelector(".hello h1");

console.log(h1)

각각의 HTML, JS코드가 있고 JS의 querySelector 를 통해 div태그 내부의 h1태그를 가져온 후 콘솔에 출력한 코드이다.

콘솔에 태그를 출력한 모습

만약 위 코드에 상응하는 값이 여러개라면 어떻게 되는지 한번 보자.

1
2
3
4
5
6
7
8
9
<div class="hello">
<h1>hello 1!</h1>
</div>
<div class="hello">
<h1>hello 2!</h1>
</div>
<div class="hello">
<h1>hello 3!</h1>
</div>
1
2
3
const h1 = document.querySelector(".hello h1");

console.log(h1)

첫번째 태그만 출력되는걸 볼 수 있다.

결과는 한개만 나오며 제일 앞의 것이 출력되는것으로 나왔다.

모두 출력하고 싶을경우 querySelectorAll을 사용하면 된다.

querySelectorAll을 사용하면 결과는 리스트로 반환된다.

결과가 리스트로 출력된다.

코드에서 살짝 알수 있었듯이 querySelector는 CSS선택자를 지원한다. (예시에서의 .hello)

그래서 title을 쓸때 #title을 쓸때 .title을 쓸때 모두 다르며 각각 태그, ID, 클래스를 의미한다.

addEventListener


addEventListener는 이벤트를 감지하는 역할을 한다.

여기서 이벤트란 마우스를 움직이거나 키를 입력하거나 브라우저 창 크기를 조정하거나 텍스트를 복사하거나 와이파이연결을 해제하는등 PC의 대부분의 IO에 관한 모든것을 말한다.

다음은 사용예시이다.

1
2
// 객체가 h1태그, 이름은 name, 함수이름은 func 라 가정
name.addEventListener("click", func);

위 코드가 뜻하는 바는 ‘name의 h1 태그를 클릭할 경우 func 함수를 실행한다.’ 이다.

코드에서 주의할 점이 있는데 func()가 아닌 그냥 func인 것이다.

func()를 하게되면 클릭이라는 조건이 갖춰지지 않아도 페이지 로딩중에 함수가 실행된다.

그렇기 때문에 함수는 괄호를 제외한 함수 이름만 입력해 주어야 한다.

여기서 click같은 조건을 더 많이 알고싶다면 구글링으로 (태그명) HTML event MDN 등을 검색하거나, console.dir(객체)를 통해 콘솔에서 더 찾아볼 수 있다. 객체의 내부 구성요소중 앞에 on이 붙은것들이 모두 이벤트라보면 된다.

이벤트 종류는 매우 많으니 다 외울수도 없을뿐더러 외울 필요도 없다.

파생형으로 name.onclick = func;이렇게 사용할 수도 있다.

그러나 addEventListener를 통해 이벤트를 감지한다면 이후 removeEventListener를 통해 event listener를 제거할 수도 있다.

필자는 addEventListener를 주로 사용할듯.

SQL리뷰 수업 코드정리-2

2일차 코드 (서브쿼리 기본)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
--실제 보유하고 있는 과일 데이터
select * from real_amount; -- 테이블값 있음, 위 이미지 첫번째 테이블

-- 카운터 컴퓨터에서 추정한 과일 데이터
select * from assumption_amount; -- 테이블값 있음, 두번째 테이블

-- 외상 데이터
select * from exception; -- 테이블값 없음, 세번째

-- 기본적으로 서브쿼리에서 true가 반환되어야 메인쿼리가 실행되는듯
-- exists(서브쿼리) == 서브쿼리의 결과가 한건이라도 존재할 경우 True 없으면 False 리턴
-- 카운터에는 데이터 존재 / 외상 데이터 현재 없음
select * from real_amount -- 현재 과일 데이터 출력
where exists ( -- 위의 exists 설명 참조
select * from assumption_amount -- 컴퓨터 추정 과일데이터
);
-- 결과 : 컴퓨터에서 추정한 과일 데이터가 존재하니 exists == true 반환, 그러므로 메인쿼리가 실행됨

select * from real_amount -- 현재 과일 데이터 출력
where exists ( -- 위의 exists 설명 참조
select * from exception -- 외상데이터
);
-- 결과 : 외상데이터 조회시 테이블값이 없기 때문에 exists == false 반환, 메인쿼리가 실행되지 않음
-- SQL의 아웃풋 창에는 select * from exception이 출력

-- IN 연산자 / NOT IN 연산자
-- IN 연산자 : 하나이상의 값이 도출이 되면 true
select * from real_amount -- 현재 과일 데이터 출력
where amount in ( -- amount(메인쿼리의 테이블에서 값을 받아오는 것으로 추정)값에 10, 20, 30 이 있을경우 true
10, 20, 30
);
-- 결과 : real_amount 테이블의 amount 컬럼에 10과 30이 존재하기 때문에 메인쿼리가 실행되어 현재 과일데이터가 출력됨

-- ANY 연산자
select * from real_amount -- 현재 과일 데이터 출력 (3)
where 10 = any ( -- 서브쿼리의 출력에 10이 있을 경우 (2)
select amount from assumption_amount
-- assumption_amount 테이블의 amount 컬럼을 출력 (1)
);
-- 결과 : assumption_amount 테이블의 amount 컬럼에 10이 존재하기 때문에 real_amount 출력

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
select * from populations; -- 위 테이블 이미지

-- 기본적인 집계함수
-- avg(*) NULL 값이 아닌 모든 입력 값의 평균

select avg(life_expectancy) from populations; -- 모든 life_expectancy의 평균값 출력

-- count(*) 입력한 행의 총 갯수
select count(*) from populations; -- populations 테이블의 모든 행 갯수 - 434

-- count(컬럼명) NULL 값이 아닌 해당 컬럼 행의 갯수
select count(life_expectancy) from populations; -- populations 테이블의 NULL이 있는 행을 제외한 life_expectancy 컬럼의 갯수 - 398

-- max, min, sum -- 모두NULL 값이 아닌 해당 컬럼 행만 계산
select max(life_expectancy) from populations;

select min(life_expectancy) from populations;

select sum(life_expectancy) from populations;

-- 기대수명이 가장 높은 country code
select country_code, life_expectancy -- country_code, life_expectancy 출력 (5)
from populations -- populations 테이블의(4)
where life_expectancy = ( -- (2)와 동일한 life_expectancy값을 가진 행의 (3)
select min(life_expectancy) -- life_expectancy컬럼의 최솟값(2)
from populations -- populations 테이블의 (1)
);
-- 결과 : populations 테이블의 life_expectancy컬럼의 최소값과 동일한 life_expectancy를 가진 country_code, life_expectancy를 populations 테이블에서 찾아 출력

-- 삼중쿼리
-- 집계함수는 where절에서 사용 불가이기 때문에 서브쿼리 사용
select country_code -- country_code 출력 (8)
from populations -- populations테이블의 (7)
where code = ( -- (5)에서 선택된 테이블의 행중에 code 컬럼과 같은값을 가진 행 (6)
select * -- (4)에서 선택된 테이블의 모든 컬럼 조회 (5)
from countries -- countries 테이블 (4)
where life_expectancy = ( -- (2)와 동일한 life_expectancy값을 가진 행 (3)
select min(life_expectancy) -- life_expectancy컬럼의 최솟값 (2)
from populations -- populations 테이블의 (1)
));
-- 복잡하다... 설명을 못해서 그렇기도 하지만, 차라리 SQL로 보는게 낫지 한글로 풀어설명하는게 더 복잡하다.

-- 조건 1. 2015년 전체 국가의 평균 수명 계산
-- 조건 2. 모든 데이터를 조회합니다.
-- 조건 3. 2015년 평균 기대수명의 1.15배보다 높도록 조건을 설정합니다.

-- 이번엔 거꾸로 과정 작성
select * -- 모든 컬럼 출력 (1)
from populations -- populations 테이블의 (2)
where life_expectancy > 1.15 * ( -- 단, life_expectancy가 서브쿼리 값의 1.15배보다 큰것만 출력 (3)
select avg(life_expectancy) -- life_expectancy의 평균값 출력(4)
from populations -- populations 테이블의 (5)
where year = 2015) -- year 컬럼이 2015인것들로만 평균값 출력(6)
and year = 2015; -- (3)의 and조건 추가절, year가 2015 일것.
-- 결론 : 2015년도의 평균life_expectancy * 1.15 보다 크고, year 가 2015인 행의 모든 컬럼 출력
-- 간단한 편..



select * from cities; -- name

select * from countries; -- capital

-- 메인쿼리
-- citi 테이블에서, name, country_code, urban_pop
-- urban_pop 내림차순 정렬
-- 상위 5개만 출력
-- 서브쿼리
-- city 테이블에 name과 countries capital 매칭이 되는 애들만 조회
select name, country_code, urbanarea_pop -- 각 컬럼 출력
from cities -- cities 테이블에서 조회
where name in (select capital from countries) -- name컬럼 내부에 서브쿼리의 값과 같은값이 있는 경우만
order by urbanarea_pop desc -- urbanarea_pop 컬럼 내림차순으로 정렬
limit 5; -- 상위 5개만

-- 결과물을 동일하게
-- 두개의 테이블을 JOIN
SELECT countries.name AS country, COUNT(*) AS cities_num
FROM cities
INNER JOIN countries
ON countries.code = cities.country_code -- 테이블 교집합
GROUP BY country -- country의 항목으로 묶어줌
ORDER BY cities_num DESC, country -- cities_num 컬럼을 내림차순으로 정렬, country 컬럼 출력
LIMIT 9; -- 상위 9개만

-- 서브쿼리를 where --> select 절로 옮긴 결과
select
countries.name as country
, (select
count(*)
from cities
where countries.code = cities.country_code) as cities_num
from countries
order by cities_num desc, country
limit 9;
-- 안보던 형식이라 그런지 더 복잡해 보인다.

자바스크립트(Javascript) 기록-2

prompt()


자바스크립트는 브라우저를 통해 사용자와 상호작용한다. 마우스의 위치가 어디인지, 어떤값을 받아오는지, 스크롤이 어디쯤인지에 따라 각각의 이벤트를 지정할 수 있다.
그런데 당연하게도 그런 값을 받아오는건 브라우저나 자바스크립트가 별도의 코딩없이 척척해주지는 않는다. (적어도 내가 아는선에서는)
그런 자바스크립트에는 값을 받아오는 명령어가 있는데 그것이 바로 prompt()이다.

1
ex) prompt("What your name?")

prompt()는 alert() 처럼 팝업창이 뜨는데 alert와 다르게 값을 입력받을수 있다.
한번쯤 본적 있지 않은가?
일단 입력은 모두 String타입으로 받아진다.
하지만 커스텀이 자유롭지못해서 요즘엔 잘 쓰이지 않고 있다고 한다.

typeof


파이썬에서의 type() 과 같은 역할을 한다.
typeof a또는 typeof(a)처럼 객체나 변수의 타입을 출력해준다.

parseInt()


변수 a 가 있고, a가 숫자로만 이루어진 문자열(string)일 경우 parseInt(a) 는 내용은 같으나 타입은 number인 a를 반환해준다.
그러나 a 가 만약 문자로 이루어져있다면 대신 NaN(Not a Number)이 반환 된다.

조건문 (if만)


1
2
3
4
5
6
7
if (a<0) {
console.log("a는 음수입니다.");
} else if (a=0) {
console.log("a는 0입니다.");
} else {
console.log("a는 양수입니다.);
}

기본적으로 자바와 크게 다르지 않아 패스….

비교연산자


다른부분만 빠르게 체크하겠다.
자바스크립트에는 같다 라는 뜻의 ==와 같지 않다 라는 뜻의 !=가 있다.
하지만 ===와 !== 도 존재하는데 이는 ‘엄격하게 같다’와 ‘엄격하게 같지 않다’이다.
‘엄격하게’가 뜻하는 바는 비교하는 변수의 타입까지 고려한다는 뜻이다.

굳이 예를 들자면 다음과 같다

1
2
3
4
5
6
7
8
const a = "10";
const b = 10;

a == b # true
a === b # false

a != b # false
a !== b # true

이처럼 ===와 !==는 변수의 타입까지 고려하며 비교를 하는 비교연산자이다.

SQL리뷰 수업 코드정리-1

1일차 코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
-- 전체 테이블 조회
select * from subway;

-- 테이블 생성
create table develop_book(
book_id integer
, date date
, name varchar(80)
);

-- 등록된 테이블 리스트 조회
-- CMD 창에서 \dt 실행하면 동일한 리스트 확인 가능
SELECT * FROM pg_catalog.pg_tables
WHERE schemaname != 'pg_catalog' AND
schemaname != 'information_schema';

-- 테이블 삭제
drop table develop_book;

-- 테이블 생성
create table develop_book(
book_id integer
, date date
, name varchar(80)
);

-- 데이터 자료 추가하기
insert into develop_book values(1, '2021-12-22', 'SQL 레시피');

-- 큰 따옴표 입력
insert into develop_book values(2, '2021-12-23', '"자바의 정석"');

-- 작은 따옴표 입력
insert into develop_book values(3, '2021-12-24', '''자바의 정석''');

-- Let's go 입력
insert into develop_book values(4, '2021-12-25', 'I''am book');

-- 조회 하기
select * from develop_book;

-- 테이블에 자료 여러 개 추가하기
insert into develop_book values
(5, '2021-12-30', '책1'),
(6, '2021-12-30', '책2'),
(7, '2021-12-30', '책3'),
(8, '2021-12-30', '책4');

-- 조회 하기
select * from develop_book;

-- 컬럼 선택 조회
select book_id, name from develop_book;

-- Limit 명령어
select * from develop_book limit 3;

-- OFFSET 명령어 추가
-- ~번째 인덱스부터 시작
select * from develop_book limit 5 offset 2;

-- ORDER BY
-- 오름차순
select * from develop_book
order by name asc;

select * from develop_book
order by name desc;

-- WHERE 조건문
select * from develop_book
where book_id = 5;

select * from develop_book
where book_id <> 5; -- 5 제외

-- AS 명령어
select name as 책제목 from develop_book;

-- Coalesc 함수
-- 데이터 조회 시, NULL 값을 다른 기본 값으로 치환
-- ex) NULL --> "데이터 없음"

insert into student_score(name, score)
values ('Hello', NULL), ('Hi', NULL);

-- 조회
select
id
, name
, score
, case
when score <= 100 and score >= 90 then 'A'
when score <= 89 and score >= 80 then 'B'
when score <= 79 and score >= 70 then 'C'
when coalesce (score,0) <= 69 then 'F'
end
from student_score;

-- 결측치 처리
select
students
, coalesce((12/nullif(students, 0))::char, '나눌 수 없음') as column8
from division_by_zero;

자바스크립트(Javascript) 기록-1

전에 만들어 놓았던 카카오톡 클론코딩을 배포 하던 중 HTML과 CSS만으로는 부족해보이므로 Javascript로 기능을 추가해 보라는 강사님의 피드백에 따라 JS로 기능을 추가하기 위해 JS가 주인 클론코딩 강의를 듣고 카카오톡 클론코딩에 잘 버무려 보기로 했다.

그런데 HTML의 스크립트태그는 몇번 접해본적 있었지만 JS는 초면인지라 다른 언어들의 기초보다 문법이 복잡한지, 어떤 부분이 다른지 전혀 모르고 있었기에 기록 겸 가끔 보려는 용도로 포스팅 한다.

하루 배우고 하루 기록하는 토막글 형식이기에 한두번 만에 끝날것 같지는 않으니, 귀찮아 하지말고 매일 기록할것.

변수 선언 방식


자바에 여러개의 변수 타입이 있듯이 자바스크립트에도 변수 타입이 존재한다. 그러나 다른점이라면 자바는 변수의 크기, 타입에 따라 분류한다면 자바스크립트는 이후에 값을 수정 가능한지 아닌지로 분류한다.
일단 기본적인 변수 선언 방식은 다음과 같다.

1
2
3
const a = 1;
let b = 2;
var c = 3;

기본적으로 변수 선언 방식 이후 변수에 값을 넣고 닫아주는 형태이다.

갑자기 잡설을 풀어보자면
파이썬, 자바등을 공부할때 해당하는 언어를 설치해주어야 했는데 자바스크립트는 그렇지 않다.
다른 언어의 경우에는 버전이 올라감에 따라 이전버전의 문법을 사용하지 못하는 경우가 있다.
그러나 자바스크립트는 이전버전의 문법(const,let이 있음에도 var가 사용 가능한경우)이 여전히 혼용 가능하다.(그러나 쓰지않는걸 추천하는것 같다.)

각설하고, 총 세 개의 방식이 있는데 각각의 특징은 이렇다.

const

ES6 이후에 추가되었고 가장 기본적으로 사용되는 변수형이다, 상수(변수인데 상수;;)이며 그렇기 때문에 선언 이후에 변경이 불가하다.(할당된개체가 Array와 Objects등의 개체라면 내부의 값을 변경할 수는 있다. ) 선언할때 반드시 값을 할당해주어야 한다.

let

ES6 이후에 추가되었고 현재 사용되고 있는 가변 변수형이다, 선언 이후에도 변경이 가능하다. 선언할때 값을 할당하지 않을수 있지만 그럴경우 값은 undefined가 된다.

var

자바스크립트 초기에 사용되었던 변수형이며, 선언 이후에도 변경이 가능하다. 역시나 선언할때 값을 할당하지 않을수 있고, 이 경우 값은 undefined가 된다.

왜 let은 쓰는데 var는 쓰지 않는지, 왜 기본적으로 let이 아닌 const를 쓰는지 의문이 생길수 있다.
전자의 의문의 답은 세가지이다.

첫째는 변수명이 같아도 선언이 가능하다는것. (재선언 가능)
누군가는 장점이 아니냐 할 수 있겠지만 변수의 양이 매우 많거나, 다른사람과 협업을 한다면 이는 단점이 된다.

둘째는 호이스팅(Hoisting).
이는 변수의 정의가 선언과 할당으로 분리되는것을 말한다, 이게 무슨뜻인지는 다음 코드를 보자

1
2
console.log(name);
var name = "WJ";

이렇게 코드가 있을때 자바스크립트는 다음과 같이 해석한다.

1
2
3
var name;
console.log(name);
name = "WJ";

결국 출력은 초기화가 되지않았다는 메시지가 나오는 대신 정의되지 않았다는 뜻인 undefined 가 나오게 된다.
이는 직관적이지 못하기때문에 var보다 let을 쓰는것이 권장된다.

셋째는 const,let은 ‘블럭’수준 var는 ‘함수’수준으로 적용되기 때문이다.
이게 무슨말인지 처음엔 이해가 잘 되지 않을수 있다. (나는 그랬음..)
그러니 바로 예시를 보면

1
2
3
4
5
6
7
8
9
var a = 5;              # 전역변수 a 선언후 5 할당
console.log(a); # 5 출력

function setA() {
var a = 10; # '함수 내부'에서 지역변수 a 선언후 10 할당
console.log(a); # 10 출력
}

console.log(a); # 5 출력

전혀 이상할것 없이 당연한 예시이다. 그럼 다음예시도 한번 보자

1
2
3
4
5
6
7
8
9
var a = 5;              # 전역변수 a 선언후 5 할당
console.log(a); # 5 출력

if (true) {
var a = 10; # 'if블럭 내부'에서 지역변수 a 선언후 10 할당
console.log(a); # 10 출력
}

console.log(a); # 10 출력 <-- ???

if블럭 내부에서 지역변수를 할당 했음에도 전역변수로 선언했던 a의 값이 바뀌어 10이 되었다.

이는 위에서 말했듯 var의 범위는 ‘함수’수준으로 적용되기 때문이다.
즉, 블럭{}으로 감싸더라도 함수로 감싸진것이 아니기때문에 if블럭 내에서 재할당된 값이 출력된 것이다.

쓰면 안되는 이유 1,3번의 콜라보..

결국 요약하자면 var는 함수내부에서 쓰는것이 아니라면 전역변수와 같다는 것이다.

안쓰는데는 이유가있다

Array (배열, 리스트)

파이썬으로 처음 접했던 리스트 역시 자바스크립트에도 있다.
다음은 array를 선언하는 기본적인 방법이다.

1
const a = [1, 2, null, true, "hello"];

인덱싱은 a[2]; 처럼 가능하고, 값을 추가하고 싶을 경우 a.push(추가할 값) 해주면 해당 값이 가장 마지막의 인덱스에 추가된다.

Objects (파이썬 딕셔너리)

제목에도 적었듯이 키와 값으로 이루어진 것이 파이썬의 딕셔너리와 닮았다. 세세한기능까지 같은지는 모른다
오브젝트를 선언하는 기본적인 방법을 보면

1
2
3
4
5
6
const a = {
name : "WJ",
contry : "KR",
lang : "Javascript",
num : 123
}

처럼 선언하는데 중괄호 내부의 프로퍼티 중 왼쪽을 이름, 오른쪽을 값이라 한다.

값 출력시엔 다음처럼 하면 된다.

1
2
a.name;
a["name"];

예시에서 배열과 오브젝트 둘다 const로 선언했지만 내부의 값은 바꿀 수 있다.

function (함수)

1
2
3
function a() {
console.log("Hello!");
}

문법만 조금 다를 뿐 전체적으로 파이썬의 사용자 지정 함수나 자바의 메소드와 비슷하다.

함수호출은 a() 로 할수 있으며 결과는 Hello! 가 출력되게 된다.





Reference.

ES6의 변수 선언, const와 let - nana_log