Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
176 changes: 176 additions & 0 deletions queries.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
==================================================
🐼 Panda Market - queries.sql
==================================================
*/

/*
1️⃣ 내 정보 업데이트 하기
- 닉네임을 "test"로 업데이트
- 현재 로그인한 유저 id =1
*/
UPDATE users
SET nickname = 'test'
WHERE id = 1;


/*
2️⃣ 내가 생성한 상품 조회
- user_id = 1
- 최신순 정렬
- 10개씩 페이지네이션 (3페이지 → OFFSET 20)
*/
SELECT id, name, price, created_at
FROM products
WHERE user_id = 1
ORDER BY created_at DESC
LIMIT 10 OFFSET 20;


/*
3️⃣ 내가 생성한 상품의 총 개수
- user_id = 1
*/
SELECT COUNT(*) AS total_products
FROM products
WHERE user_id = 1;


/*
4️⃣ 내가 좋아요 누른 상품 조회
- user_id = 1
- 최신순 정렬
- 10개씩 페이지네이션 (3페이지 → OFFSET 20)
*/
SELECT
p.id,
p.name,
p.price,
l.created_at AS liked_at
FROM likes l
JOIN products p ON p.id = l.product_id
WHERE l.user_id = 1
ORDER BY l.created_at DESC
LIMIT 10 OFFSET 20;


/*
5️⃣ 내가 좋아요 누른 상품의 총 개수
- user_id = 1
*/
SELECT COUNT(*) AS total_liked_products
FROM likes
WHERE user_id = 1 AND product_id IS NOT NULL;


/*
6️⃣ 상품 생성
- user_id = 1
*/
INSERT INTO products (user_id, name, description, price)
VALUES (1, '테스트 상품', '테스트용 상품입니다.', 15000);


/*
7️⃣ 상품 목록 조회
- 상품명에 "test"가 포함된 상품
- 최신순 정렬
- 10개씩 페이지네이션 (1페이지 → OFFSET = 0)
- 각 상품의 좋아요 개수를 포함
*/
SELECT
p.id,
p.name,
p.price,
COUNT(l.id) AS like_count,
p.created_at
FROM products p
LEFT JOIN likes l ON l.product_id = p.id
WHERE p.name ILIKE '%test%'
GROUP BY p.id
ORDER BY p.created_at DESC
LIMIT 10 OFFSET 0;


/*
8️⃣ 상품 상세 조회
- 1번 상품 조회
- 좋아요 수 포함
*/
SELECT
p.id,
p.name,
p.description,
p.price,
p.created_at,
COUNT(l.id) AS like_count
FROM products p
LEFT JOIN likes l ON l.product_id = p.id
WHERE p.id = 1
GROUP BY p.id;


/*
9️⃣ 상품 정보 수정
- 1번 상품 수정
- user_id = 1 (본인 상품만 수정 가능)
*/
UPDATE products
SET
name = '수정된 상품명',
description = '상품 설명이 수정되었습니다.',
price = 18000
WHERE id = 1 AND user_id = 1;


/*
🔟 상품 삭제
- 1번 상품 삭제
- user_id = 1 (본인 상품만)
*/
DELETE FROM products
WHERE id = 1 AND user_id = 1;


/*
11️⃣ 상품 좋아요
- 1번 유저가 2번 상품 좋아요
*/
INSERT INTO likes (user_id, product_id)
VALUES (1, 2)
ON CONFLICT (user_id, product_id) DO NOTHING;


/*
12️⃣ 상품 좋아요 취소
- 1번 유저가 2번 상품 좋아요 취소
*/
DELETE FROM likes
WHERE user_id = 1 AND product_id = 2;


/*
13️⃣ 상품 댓글 작성
- 1번 유저가 2번 상품에 댓글 작성
*/
INSERT INTO comments (user_id, product_id, content)
VALUES (1, 2, '좋은 상품이네요!');


/*
14️⃣ 상품 댓글 조회
- 1번 상품에 달린 댓글 목록
- 최신 순
- 댓글 날짜 2025-03-25 이전 데이터 10개
*/
SELECT
c.id,
u.nickname AS author,
c.content,
c.created_at
FROM comments c
JOIN users u ON u.id = c.user_id
WHERE c.product_id = 1
AND c.created_at < '2025-03-25'
ORDER BY c.created_at DESC
LIMIT 10;
198 changes: 198 additions & 0 deletions schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@

CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- ===========================================
-- USERS
-- ===========================================
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(50) UNIQUE NOT NULL,
nickname VARCHAR(255) NOT NULL,
password VARCHAR(100) NOT NULL,
image VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
);

CREATE TRIGGER trg_users_updated_at
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();

-- ===========================================
-- PRODUCTS
-- ===========================================
CREATE TABLE products (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
name VARCHAR(50) NOT NULL,
description VARCHAR(255),
price INT NOT NULL CHECK (price >= 0),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT fk_products_user FOREIGN KEY (user_id)
REFERENCES users(id) ON DELETE CASCADE
);

CREATE INDEX idx_products_user_id ON products(user_id);
CREATE INDEX idx_products_created_at ON products(created_at);

CREATE TRIGGER trg_products_updated_at
BEFORE UPDATE ON products
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();

-- ===========================================
-- IMAGES (상품 1:N)
-- ===========================================
CREATE TABLE images (
id SERIAL PRIMARY KEY,
product_id INT NOT NULL,
image_url VARCHAR(255) NOT NULL,
is_main BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT fk_images_product FOREIGN KEY (product_id)
REFERENCES products(id) ON DELETE CASCADE
);

CREATE INDEX idx_images_product_id ON images(product_id);

CREATE TRIGGER trg_images_updated_at
BEFORE UPDATE ON images
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();

-- ===========================================
-- ARTICLES (게시판)
-- ===========================================
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
title VARCHAR(100) NOT NULL,
content TEXT NOT NULL,
image VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT fk_articles_user FOREIGN KEY (user_id)
REFERENCES users(id) ON DELETE CASCADE
);

CREATE INDEX idx_articles_user_id ON articles(user_id);
CREATE INDEX idx_articles_created_at ON articles(created_at);

CREATE TRIGGER trg_articles_updated_at
BEFORE UPDATE ON articles
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();

-- ===========================================
-- COMMENTS (상품/게시글 둘 다 가능)
-- ===========================================
CREATE TABLE comments (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
product_id INT,
article_id INT,
content VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT fk_comments_user FOREIGN KEY (user_id)
REFERENCES users(id) ON DELETE CASCADE,
CONSTRAINT fk_comments_product FOREIGN KEY (product_id)
REFERENCES products(id) ON DELETE CASCADE,
CONSTRAINT fk_comments_article FOREIGN KEY (article_id)
REFERENCES articles(id) ON DELETE CASCADE,
CONSTRAINT chk_comment_target CHECK (
(product_id IS NOT NULL AND article_id IS NULL) OR
(product_id IS NULL AND article_id IS NOT NULL)
)
);

CREATE INDEX idx_comments_user_id ON comments(user_id);
CREATE INDEX idx_comments_product_id ON comments(product_id);
CREATE INDEX idx_comments_article_id ON comments(article_id);

CREATE TRIGGER trg_comments_updated_at
BEFORE UPDATE ON comments
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();

-- ===========================================
-- LIKES (상품/게시글 좋아요)
-- ===========================================
CREATE TABLE likes (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
product_id INT,
article_id INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT fk_likes_user FOREIGN KEY (user_id)
REFERENCES users(id) ON DELETE CASCADE,
CONSTRAINT fk_likes_product FOREIGN KEY (product_id)
REFERENCES products(id) ON DELETE CASCADE,
CONSTRAINT fk_likes_article FOREIGN KEY (article_id)
REFERENCES articles(id) ON DELETE CASCADE,
CONSTRAINT uq_like_product UNIQUE (user_id, product_id),
CONSTRAINT uq_like_article UNIQUE (user_id, article_id)
);

CREATE INDEX idx_likes_user_id ON likes(user_id);

CREATE TRIGGER trg_likes_updated_at
BEFORE UPDATE ON likes
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();

-- ===========================================
-- FAVORITES
-- ===========================================
CREATE TABLE favorites (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
product_id INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT fk_favorites_user FOREIGN KEY (user_id)
REFERENCES users(id) ON DELETE CASCADE,
CONSTRAINT fk_favorites_product FOREIGN KEY (product_id)
REFERENCES products(id) ON DELETE CASCADE,
CONSTRAINT uq_favorites UNIQUE (user_id, product_id)
);

CREATE INDEX idx_favorites_user_id ON favorites(user_id);
CREATE INDEX idx_favorites_product_id ON favorites(product_id);

CREATE TRIGGER trg_favorites_updated_at
BEFORE UPDATE ON favorites
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();

-- ===========================================
-- TAGS / PRODUCT_TAGS
-- ===========================================
CREATE TABLE tags (
id SERIAL PRIMARY KEY,
name VARCHAR(50) UNIQUE NOT NULL
);

CREATE TABLE product_tags (
id SERIAL PRIMARY KEY,
product_id INT NOT NULL,
tag_id INT NOT NULL,
CONSTRAINT fk_product_tags_product FOREIGN KEY (product_id)
REFERENCES products(id) ON DELETE CASCADE,
CONSTRAINT fk_product_tags_tag FOREIGN KEY (tag_id)
REFERENCES tags(id) ON DELETE CASCADE,
CONSTRAINT uq_product_tags UNIQUE (product_id, tag_id)
);

CREATE INDEX idx_product_tags_product_id ON product_tags(product_id);
CREATE INDEX idx_product_tags_tag_id ON product_tags(tag_id);