join์ผ๋ก ์นดํ ๊ณ ๋ฆฌ ์์ด๋-์ด๋ฆ ๋งคํ
1. fk ์ถ๊ฐ ํ
2. join ์ฟผ๋ฆฌ ์คํ
SELECT * FROM books LEFT
JOIN category ON books.category_id = category.id;
3. api์์ join ์ฟผ๋ฆฌ ์คํ
const conn = require("../mariadb");
const { StatusCodes } = require("http-status-codes");
const getAllBooks = (req, res) => {
let { category_id } = req.query;
if (category_id) {
let sql = `SELECT * FROM books LEFT JOIN category ON books.category_id = category.id WHERE books.category_id=?`;
conn.query(sql, category_id, (err, result) => {
if (err) {
return res.status(StatusCodes.BAD_REQUEST).end();
}
if (result.length) return res.status(StatusCodes.OK).json(result);
else return res.status(StatusCodes.NOT_FOUND).end();
});
} else {
let sql = `SELECT * FROM books LEFT JOIN category ON books.category_id = category.id`;
conn.query(sql, (err, result) => {
if (err) {
return res.status(StatusCodes.BAD_REQUEST).end();
}
return res.status(StatusCodes.OK).json(result);
});
}
};
const getBookById = (req, res) => {
//parseInt ์ ์ฉ ์, id ์์ฑ์ ๊ตฌ์กฐ ๋ถํด ์๋
//parseInt๋ ์ซ์๋ฅผ ๋ฐํํ๋ฏ๋ก, ๊ตฌ์กฐ ๋ถํด ๋ถ๊ฐ. '
//parseInt๋ ๋ฌธ์์ด์ ์ ์๋ก ๋ณํํ๋๋ฐ, ๊ฐ์ฒด์ธ req.parmas ์ ์ฒด๋ฅผ ์ ๋ฌํ๋ ์ค๋ฅ๊ฐ ์์๋ค.
let { id } = req.params;
let sql = `SELECT * FROM books LEFT JOIN category ON books.category_id = category.id WHERE books.id=?`;
conn.query(sql, id, (err, result) => {
if (err) {
return res.status(StatusCodes.BAD_REQUEST).end();
}
if (result[0]) return res.status(StatusCodes.OK).json(result[0]);
else return res.status(StatusCodes.NOT_FOUND).end();
});
};
module.exports = {
getAllBooks,
getBookById,
};
๊ธฐ๊ฐ ์กฐ๊ฑด ์ถ๊ฐํ๊ธฐ
๋ฐ์ดํฐ์ด์ค ์๊ฐ ๋ฒ์๋ฅผ ๊ตฌํ๊ธฐ ์ํด์๋ DATE_ADD()์ DATE_SUB()๋ฅผ ์ฌ์ฉํ๋ค
- DATE_ADD(๊ธฐ์ค๋ ์ง, INTERVAL)
- DATE_SUB(๊ธฐ์ค๋ ์ง, INTERVAL)
SELECT DATE_ADD(NOW(), INTERVAL 1 MONTH);
์๊ฐ ๋ฒ์ ์ง์ , ๋ฒ์ ์ง์ ์ BETWEEN์ ์ฌ์ฉํ๋ค.
SELECT * FROM books WHERE pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 10 DAY) AND NOW();
๊ธฐ์กด์ ๋ณต์กํ๋ if-else ๋ฌธ์ sql ๋ฌธ ์กฐ๊ฑด๋ฌธ ์ฒ๋ฆฌ๋ก ๋ถ๋ฆฌํ์ฌ ๊ตฌ์กฐ ๊ฐ์
//๋ณ๊ฒฝ ์
if (category_id) {
let sql = `SELECT * FROM books LEFT JOIN category ON books.category_id = category.id WHERE books.category_id=?`;
conn.query(sql, category_id, (err, result) => {
if (err) {
return res.status(StatusCodes.BAD_REQUEST).end();
}
if (result.length) return res.status(StatusCodes.OK).json(result);
else return res.status(StatusCodes.NOT_FOUND).end();
});
} else {
let sql = `SELECT * FROM books LEFT JOIN category ON books.category_id = category.id`;
conn.query(sql, (err, result) => {
if (err) {
return res.status(StatusCodes.BAD_REQUEST).end();
}
return res.status(StatusCodes.OK).json(result);
});
}
//๋ณ๊ฒฝ ํ
let sql = "SELECT * FROM books";
let values = [];
if (category_id && news) {
sql +=
" WHERE category_id=? AND pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()";
values = [category_id, news];
} else if (category_id) {
sql += " WHERE category_id=?";
values = category_id;
} else if (news) {
sql +=
" WHERE pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()";
values = news;
}
conn.query(sql, values, (err, result) => {
if (err) {
return res.status(StatusCodes.BAD_REQUEST).end();
}
if (result.length) {
return res.status(StatusCodes.OK).json(result);
} else {
return res.status(StatusCodes.NOT_FOUND).end();
}
});
์ด์ ์ฟผ๋ฆฌ๊ฐ ์ถ๊ฐ๋ ๋๋ง๋ค conn.query๋ฅผ ํธ์ถํ์ฌ ์ฒ๋ฆฌํ์ง ์๊ณ , sql ๋ฌธ ์กฐ๊ฑด ๋ฌธ๋ด์์ SQL ์ฟผ๋ฆฌ์ ๋ํ ๋ถ๊ธฐ๋ง ์ฒ๋ฆฌํ ํ, conn.query์์ ์์์ ์ฒ๋ฆฌํ sql๊ณผ values๋ฅผ ๋ฐ์ ์ฒ๋ฆฌํ ์ ์๋ค.
์กฐ๊ฑด๋ฌธ ์์ฑ ์, ์กฐ๊ฑด์ ์์๋ฅผ ํญ์ ์ ์ํด์ผ ํจ!
์ค๋ฅ: ๊ฐ๋ณ์กฐํ ์ id๊ฐ ๋ฌด์กฐ๊ฑด 0์ผ๋ก ๋์ค๋ ๋ฌธ์
์์ธ: book ํ ์ด๋ธ์ id์, category์ id๊ฐ join ์ ์ถฉ๋ํ์ฌ ๋ฐ์ํ๋ ๋ฌธ์ ์์
๊ธฐ์กด์ ์๋์ฒ๋ผ ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉ์ค์ด์์
let sql = `SELECT * FROM books LEFT JOIN category ON books.category_id = category.id WHERE books.id=?`;
SELECT *๋ฅผ ์ฌ์ฉํ์ฌ books์ category ํ ์ด๋ธ ๋ชจ๋ id ์ปฌ๋ผ์ ๊ฐ์ ธ, JOIN ๊ฒฐ๊ณผ์์๋ ๋ id๊ฐ ์ถฉ๋ ํ ใฑ๊ฒ. mariadb์์๋ ๋์ค์ ์ค๋ ํ ์ด๋ธ๋ก id ๊ฐ์ด ๋ฎ์ด์จ์ง๊ฑฐ๋, ์ผ๋ถ ๊ฒฝ์ฐ์๋ ๊ธฐ๋ณธ๊ฐ์ธ 0์ผ๋ก ์ค์ ๋ ์ ์๋ค.
ํ์ธ ๊ฒฐ๊ณผ, ๋ฌด์กฐ๊ฑด 0 ์ด ์๋ category์ id ๊ฐ์ผ๋ก ์ถ๋ ฅ๋๊ณ ์์๋ค.
์ธ๋ํค ๊ด๊ณ๋ฅผ ์ด์ฉํด, ํ์ํ category_name๋ง ๊ฐ์ ธ์ค๋๋ก ์์ ํ๋ค.
let sql = `SELECT books.*, (SELECT category_name FROM category WHERE id = books.category_id) as category_name
FROM books
WHERE books.id=?`;
JOIN ๋์ ์๋ธ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ category_name ๋ง ๊ฐ์ ธ์ค๋๋ก ๋ณ๊ฒฝ
books ํ ์ด๋ธ ๋ชจ๋ ์ปฌ๋ผ์ ์ ์งํ๊ณ , category ํ ์ด๋ธ๊ณผ์ ๋ถํ์ํ JOIN์ ์ ๊ฑฐํ์๋ค
์ด์ books ํ ์ด๋ธ์ ๋ฐ์ดํฐ๋ ์จ์ ํ ์ ์ง๋๋ฉด์(id ํฌํจ), category_name๋ง ์ถ๊ฐ๋ก ๊ฐ์ ธ์ ์ ์์ ์ผ๋ก id๊ฐ ์ถ๋ ฅ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ฐ.
ํ์ด์ง ์ ์ฉ
์ฟผ๋ฆฌ๋ฌธ์ผ๋ก ์ฒ๋ฆฌ
SELECT * FROM books LIMIT 4 OFFSET 8
- LIMIT ์ถ๋ ฅํ ํ์ ์
- OFFSET: ์์ ์ง์
๊ณ ์ ํ์ง ์๊ณ , ๋์ ์ผ๋ก ๋ฐ์ ์ฒ๋ฆฌํ๋๋ก
-limit์ url๋ก ๋ฐ์์ ์ฒ๋ฆฌ
/books?limit={page ๋น ๋์ ์}¤tPage={ํ์ฌ ํ์ด์ง}
let { category_id, news, limit, currentPage } = req.query;
let offset = (currentPage - 1) * limit;
let sql = "SELECT * FROM books LIMIT ? OFFSET ?";
let values = [limit, offset];
if (category_id && news) {
sql +=
" WHERE category_id=? AND pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()";
values = values.push(category_id, news);
} else if (category_id) {
sql += " WHERE category_id=?";
values = values.push(category_id);
} else if (news) {
sql +=
" WHERE pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()";
values = values.push(news);
}
์ค๋ฅ: ER_PARSE_ERROR(1064)
sql ๊ตฌ๋ฌธ ์ค๋ฅ๊ฐ ๋ฐ์
1.
```
code: 'ER_PARSE_ERROR',
errno: 1064,
sqlState: '42000',
sqlMessage: "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '? WHERE category_id=? AND pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) ...' at line 1",
sql: 'SELECT * FROM books LIMIT 4 OFFSET ? WHERE category_id=? AND pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()'
}
```
2.
```
code: 'ER_PARSE_ERROR',
errno: 1064,
sqlState: '42000',
sqlMessage: "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''0'' at line 1",
sql: "SELECT * FROM books WHERE category_id=4 AND pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW() LIMIT 0 OFFSET '0'"
}
```
3.
```
code: 'ER_PARSE_ERROR',
errno: 1064,
sqlState: '42000',
sqlMessage: "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''true' OFFSET 4' at line 1",
sql: "SELECT * FROM books WHERE category_id='0' AND pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW() LIMIT 'true' OFFSET 4"
}
```
์์ธ:
1. sql ๋ฌธ๋ฒ์ ์์. limit๊ณผ offset์ ๋ชจ๋ ์ฟผ๋ฆฌ์ ์ ์ฉํ๊ธฐ ์ํด where ์ ์์ ๋ฐฐ์นํ์๋๋ฐ, ์ฌ๋ฐ๋ฅธ ์์๊ฐ ์๋์ด์ ๋ฐ์ํ ๋ฌธ์ ์๋ค.
sql ๋ฌธ์ ์ฌ๋ฐ๋ฅธ ์์:
์ (Clause) ์ค๋ช
SELECT | ์กฐํํ ์ปฌ๋ผ ์ง์ |
FROM | ํ ์ด๋ธ ์ง์ |
WHERE | ์กฐ๊ฑด ์ง์ (ํํฐ๋ง) |
GROUP BY | ๊ทธ๋ฃนํ (์ง๊ณ์ฉ) |
HAVING | ๊ทธ๋ฃน ํํฐ๋ง |
ORDER BY | ์ ๋ ฌ |
LIMIT / OFFSET | ํ ๊ฐ์ ์ ํ, ์์ ์์น ์ง์ |
๋ฐ๋ผ์ SELECT * FROM ์์น์์ limit, offset์ ์ค์ ํ๋ฉด ใ
์๋๊ณ , ์กฐ๊ฑด ๋ฌธ ์ข
๋ฃ ํ ์ตํ์ sql += ํ์ฌ limit, offset ์กฐ๊ฑด์ ์ถ๊ฐํด์ฃผ์ด์ผ ํ๋ค.
2. offset ๊ฐ์ด ๋ฌธ์์ด 0์ผ๋ก ์ ๋ฌ๋์๋ค.
์ซ์ ํ์ ์ด์ด์ผ ํ๋๋ฐ, ๋ฌธ์์ด์ด ์ฌ์ฉ๋์ด ๋ฐ์ํ ์ค๋ฅ. parseInt๋ก ์ซ์ ๋ณํ
3. ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ ์์ ๋ฌธ์
values ๋ฐฐ์ด์ ๊ฐ์ด sql์ ? ์์น์ ์์๋๋ก ๋งค์นญ๋์ด์ผ ํ๋ค.
where ์ ์ ์กฐ๊ฑด ํ๋ผ๋ฏธํฐ๊ฐ ๋จผ์ ์ค๊ณ , limit.offset์ด ๋์ค์ ์์ผ ํจ
ํด๊ฒฐ
```
let sql = "SELECT * FROM books"; // ๊ธฐ๋ณธ ์ฟผ๋ฆฌ
if (์กฐ๊ฑด) {
sql += " WHERE ..."; // WHERE ์ ์ถ๊ฐ
}
sql += " LIMIT ? OFFSET ?"; // ๋ง์ง๋ง์ LIMIT/OFFSET ์ถ๊ฐ
```
```
let values = [];
// WHERE ์ ํ๋ผ๋ฏธํฐ ๋จผ์ ์ถ๊ฐ
if (category_id) values.push(parseInt(category_id));
// LIMIT/OFFSET ํ๋ผ๋ฏธํฐ๋ ๋ง์ง๋ง์ ์ถ๊ฐ
values.push(parseInt(limit), parseInt(offset));
```
news ์กฐ๊ฑด ์ฒ๋ฆฌ๋ก ๋ณ๊ฒฝ
api ์ค๊ณ ๋ฐฉ์ ์ค, ํ๋ผ๋ฏธํฐ ์ ๋ฌ ๋ฐฉ์๊ณผ ์กฐ๊ฑด ์ฒ๋ฆฌ ๋ฐฉ์์ด ์๋ค. ๊ธฐ์กด์๋ news๋ฅผ ํ๋ผ๋ฏธํฐ ์ ๋ฌ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํ๊ณ ์์๋๋ฐ, ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
```
-- ๋ฐ์ํ ์ค๋ฅ ์ฟผ๋ฆฌ
SELECT * FROM books WHERE category_id='0' AND pub_date BETWEEN ... LIMIT 'true' OFFSET 4
```
๋ฌธ์ ์ :
- news ๊ฐ์ด where ์ ์ด ์๋ limit ์ ์ ๋ฐ์ธ๋ฉ๋์ด limit true์ ๊ฐ์ ์๋ชป๋ ์ฟผ๋ฆฌ ์์ฑ
- values ๋ฐฐ์ด์ news ๊ฐ์ ์ฌ์ฉํ๋ฉด์ ํ๋ผ๋ฏธํฐ ์์๊ฐ ๊ผฌ์
- ๋ถํ์ํ ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ์ผ๋ก sql ์ค๋ฅ ๋ฐ์
```
// ๋ณ๊ฒฝ ์ : ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ ๋ฐฉ์
if (news) {
sql += " WHERE pub_date BETWEEN ... AND NOW()";
values.push(news); // ๋ฌธ์ ๋ฐ์
}
// ๋ณ๊ฒฝ ํ: ์กฐ๊ฑด ์ฒ๋ฆฌ ๋ฐฉ์
if (news === "true") {
sql += " WHERE pub_date BETWEEN ... AND NOW()";
// ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ ์์ด ์กฐ๊ฑด๋ง ์ฒ๋ฆฌ
}
```
- ์์ ์ฑ: sql ์ธ์ ์ ์ํ ์ ๊ฑฐ, ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ ์ค๋ฅ ๋ฐฉ์ง, ์๋ชป๋ ์ ๋ ฅ ๊ฐ ์ฐจ๋จ
- ๋ช ํ์ฑ:์ต์ ๋์ ์ฌ๋ถ๋ผ๋ ์๋๊ฐ ์ฝ๋์ ๋ช ํํ ๋๋ฌ๋จ- true/false๋ก ๋จ์ํ๋ ์ฒ๋ฆฌ
- ํจ์จ์ฑ: ๋ถํ์ํ ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ ์ ๊ฑฐ, sql ์ฟผ๋ฆฌ ์คํ ์ฑ๋ฅ ํฅ์
์ง๊ธ์ true, false๋ก ์ ๊ฐ ๋์ ์ฌ๋ถ๋ง ํ๋ณํ์ฌ ๊ฐ๋ฅํ ๊ตฌ์กฐ. ๋ง์ฝ ๊ธฐ๊ฐ๋ณ ์กฐํ ๋ฑ์ ๊ตฌ์กฐ ๊ฐ์ ์, ์๋ ๋ฐฉํฅ์ผ๋ก ํ์ฅ ๊ฐ๋ฅ
```
//๊ธฐ๊ฐ๋ณ ์กฐํ
// /books?timeRange=1m|3m|6m
const timeRangeMap = {
'1m': 1,
'3m': 3,
'6m': 6
};
if (timeRange && timeRangeMap[timeRange]) {
sql += " WHERE pub_date BETWEEN DATE_SUB(NOW(), INTERVAL ? MONTH) AND NOW()";
values.push(timeRangeMap[timeRange]);
}
```
```
//์ปค์คํ ๋ ์ง ์กฐํ
// /books?dateFrom=2024-01-01&dateTo=2024-03-31
if (dateFrom && dateTo) {
sql += " WHERE pub_date BETWEEN ? AND ?";
values.push(dateFrom, dateTo);
}
```
๊ฐ์ฌ๋์ ๋๋ฌด ์ค๋ฅ ์์ด ์ ํด๋ณด์ฌ์ ํ ์๊ฐ๋์ ๊ณ ๋ฏผํ๋ค๊ฐ ์ง๋ฌธ๊ธ๊น์ง ๋จ๊ฒผ๋๋ฐ ๋ฐ๋ก ๋ค์ ์์์ ์์ด์ ๊ฐํ๋งํ๊ณ ๋ถ๋๋ฌ์๋น. ๋๋ช ๋ดค๋๋ฐ,,,. ์ญ์ ๊ฐ์๋ ์ ๋ ์ ๋ค์ด์ผ ํจ
'๐๏ธํ๋ก๊ทธ๋๋จธ์ค ๋ฐ๋ธ์ฝ์ค > ํ๋ก์ ํธ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๋ฐ๋ธ์ฝ์ค] ์ฅ๋ฐ๊ตฌ๋ ์กฐํ api ๊ตฌํ (1) | 2025.05.19 |
---|---|
[๋ฐ๋ธ์ฝ์ค] ์ข์์ api ๊ตฌํ (0) | 2025.05.19 |
[๋ฐ๋ธ์ฝ์ค] ๋์ ์กฐํ API (0) | 2025.05.16 |
[๋ฐ๋ธ์ฝ์ค] ํ์๊ฐ์ , ๋ก๊ทธ์ธ ๊ตฌํ (0) | 2025.05.15 |
[๋ฐ๋ธ์ฝ์ค] ๋ถ์คํ ์ด ํ๋ก์ ํธ #1. app.js ๋ฐ ์ ์ api ๋ผ์ฐํฐ ํ ํ๋ฆฟ (0) | 2025.05.13 |