첫날이라서 학생들이 데이터베이스 활용능력을 알아보려고 4개의 sql 문제를 준비하셔서 풀어보는 시간을 가졌다.
Q. 연봉이 최대 5,000만원을 넘지 않는 부서 ID가 17인 사원들 및 부서 ID가 5번인 모든 사원들 및 커미션을 받는 사원들의 목록을 찾고 싶습니다. 어떻게 쿼리문을 작성하면 될까요?
SELECT * FROM employees WHERE (salary ≤ 50000000 and department_id = 17) OR department_id = 5 OR comm > 0
Q. track이 “Node.js”이거나 “React”인 학생들 중 성이 “김”씨거나 끝의 이름이 “호”로 끝나는 학생들의 명단(student_name)을 알고 싶습니다. 어떻게 쿼리문을 작성하면 될까요?
SELECT student_name FROM students WHERE (track IN (’Node.js’, ‘React’) AND (student_name LIKE ‘김%’ OR student_name LIKE ‘%호’))
Q. rank_score가 1000 이하면 “IRON”, 1001 ~ 2000 사이면 “BRONZE”, 2001 ~ 3000 사이면 “SILVER” 3001 이상이면 “GOD”을 출력하는 rank_result라는 이름의 컬럼을 포함하여 name과 같이 결과를 알고 싶습니다. 어떻게 쿼리문을 작성하면 될까요?
Bonus Q. 위의 문제에서 rank라는 컬럼으로 결과를 알 수 있을 것 같은데 왜 굳이 제가 rank_result라는 이름의 컬럼으로 썼을까요?
A. rank라는 함수가 sql에 이미 존재하기 때문에 사용하게되면 ambiguous하기 때문!
SELECT name, CASE WHEN rank_score ≤ 1000 THEN ‘IRON’ WHEN rank_score ≤ 2000 THEN ‘BRONZE’ WHEN rank_score ≤ 3000 THEN ‘SILVER’ ELSE ‘GOD’ END AS rank_result FROM lol_players
PLACES
테이블은 공간 임대 서비스에 등록된 공간의 정보를 담은 테이블입니다. PLACES
테이블의 구조는 다음과 같으며 ID
, NAME
, HOST_ID
는 각각 공간의 아이디, 이름, 공간을 소유한 유저의 아이디를 나타냅니다. ID
는 기본키입니다.
Q. 이 서비스에서는 공간을 둘 이상 등록한 사람을 "헤비 유저"라고 부릅니다. 헤비 유저가 등록한 공간의 정보를 아이디 순으로 조회하는 SQL문을 작성해주세요.
SELECT ID, NAME, HOST_ID FROM PLACES WHERE HOST_ID IN (SELECT HOST_ID FROM PLACES GROUP BY HOST_ID HAVING COUNT(HOST_ID) > 1) ORDER BY ID
/index.html
<!-- 메시지 폼 -->
<form name="publish">
<input type="text" name="message">
<input type="submit" value="send">
</form>
<script>
let url ='ws://localhost:8080/ws';
let socket = new WebSocket(url);
// 폼에 있는 메세지 보내기
document.forms.publish.onsubmit = function() {
let outgoingMessage = this.message.value;
const obj = { "type": "message" , "params": { "value": outgoingMessage }}
socket.send(JSON.stringify(obj));
return false;
};
// 들어오는 메세지 핸들링
socket.onmessage = function(event) {
let incomingMessage = event.data;
showMessage(incomingMessage);
};
socket.onclose = event => console.log(`Closed ${event.code}`);
// dev에 메세지 더하기
function showMessage(message) {
let messageElem = document.createElement('div');
const obj = JSON.parse(message);
messageElem.textContent = obj.params.value;
document.getElementById('messages').prepend(messageElem);
}
</script>
<!-- 수신받을 메시지가 노출될 div -->
<div id="messages"></div>
/app.js
const http = require('http');
const fs = require('fs');
const ws = new require('ws');
const wss = new ws.Server({noServer: true});
const clients = new Set();
function accept(req, res) {
// 연결시에 헤더에 upgrade라는 문자열이 포함
if (req.url == '/ws' && req.headers.upgrade && req.headers.upgrade.toLowerCase() == 'websocket' && req.headers.connection.match(/\bupgrade\b/i))
{
wss.handleUpgrade(req, req.socket, Buffer.alloc(0), onSocketConnect);
} //안되어있고 /면 인덱스 페이지를
else if (req.url == '/')
{
// index.html
fs.createReadStream('./index.html').pipe(res);
}
else //없으면 404페이지
{
// page not found
res.writeHead(404);
res.end();
}
}
function onSocketConnect(ws) {
clients.add(ws);
console.log(`new connection`);
ws.on('message', function(message) {
const obj = JSON.parse(message);
console.log("message received: ", obj);
// 각각의 클라이언트에게 전달
for(let client of clients) {
// send로 클라이언트에 전송
client.send(JSON.stringify(obj));
}
});
ws.on('close', function() {
console.log(`connection closed`);
// 연결할때 add해 준 것을 배열에서 제거해줘야 쓸데없이 send보내는걸 막을 수 있음!
clients.delete(ws);
});
}
http.createServer(accept).listen(8080);