企業內部新聞彙整與分析系統 - 自動新聞抓取 (Digitimes, 經濟日報, 工商時報) - AI 智慧摘要 (OpenAI/Claude/Ollama) - 群組管理與訂閱通知 - 已清理 Python 快取檔案 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
426 lines
17 KiB
SQL
426 lines
17 KiB
SQL
-- ============================================================
|
||
-- 每日報導 APP - 資料庫 Schema 設計
|
||
-- Database: MySQL 8.0+
|
||
-- Charset: utf8mb4
|
||
-- ============================================================
|
||
|
||
-- 建立資料庫
|
||
CREATE DATABASE IF NOT EXISTS daily_news_app
|
||
CHARACTER SET utf8mb4
|
||
COLLATE utf8mb4_unicode_ci;
|
||
|
||
USE daily_news_app;
|
||
|
||
-- ============================================================
|
||
-- 1. 用戶與權限相關
|
||
-- ============================================================
|
||
|
||
-- 1.1 角色表
|
||
CREATE TABLE roles (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
code VARCHAR(20) NOT NULL UNIQUE COMMENT '角色代碼: admin, editor, reader',
|
||
name VARCHAR(50) NOT NULL COMMENT '角色名稱',
|
||
description VARCHAR(200) COMMENT '角色描述',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||
) COMMENT='系統角色表';
|
||
|
||
-- 預設角色資料
|
||
INSERT INTO roles (code, name, description) VALUES
|
||
('admin', '系統管理員', 'LLM設定、AD整合、群組管理、用戶管理、系統設定'),
|
||
('editor', '市場分析專員', '新聞抓取管理、篩選編輯、報告發布、群組內容設定'),
|
||
('reader', '讀者', '訂閱群組、閱讀報告、留言討論、個人收藏、匯出PDF');
|
||
|
||
-- 1.2 用戶表
|
||
CREATE TABLE users (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
username VARCHAR(50) NOT NULL UNIQUE COMMENT '用戶帳號',
|
||
password_hash VARCHAR(255) COMMENT '密碼雜湊(本地帳號使用)',
|
||
display_name VARCHAR(100) NOT NULL COMMENT '顯示名稱',
|
||
email VARCHAR(100) COMMENT '電子郵件',
|
||
auth_type ENUM('ad', 'local') NOT NULL DEFAULT 'local' COMMENT '認證類型',
|
||
role_id INT NOT NULL COMMENT '角色ID',
|
||
is_active BOOLEAN DEFAULT TRUE COMMENT '是否啟用',
|
||
last_login_at TIMESTAMP NULL COMMENT '最後登入時間',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (role_id) REFERENCES roles(id)
|
||
) COMMENT='用戶表';
|
||
|
||
CREATE INDEX idx_users_username ON users(username);
|
||
CREATE INDEX idx_users_auth_type ON users(auth_type);
|
||
|
||
-- ============================================================
|
||
-- 2. 新聞來源與抓取相關
|
||
-- ============================================================
|
||
|
||
-- 2.1 新聞來源表
|
||
CREATE TABLE news_sources (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
code VARCHAR(30) NOT NULL UNIQUE COMMENT '來源代碼',
|
||
name VARCHAR(100) NOT NULL COMMENT '來源名稱',
|
||
base_url VARCHAR(255) NOT NULL COMMENT '網站基礎URL',
|
||
source_type ENUM('subscription', 'public') NOT NULL COMMENT '來源類型:付費訂閱/公開',
|
||
login_username VARCHAR(100) COMMENT '登入帳號(付費訂閱用)',
|
||
login_password_encrypted VARCHAR(255) COMMENT '加密後密碼',
|
||
is_active BOOLEAN DEFAULT TRUE COMMENT '是否啟用',
|
||
crawl_config JSON COMMENT '爬蟲設定(選擇器、間隔等)',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||
) COMMENT='新聞來源表';
|
||
|
||
-- 預設新聞來源
|
||
INSERT INTO news_sources (code, name, base_url, source_type) VALUES
|
||
('digitimes', 'Digitimes', 'https://www.digitimes.com.tw', 'subscription'),
|
||
('udn', '經濟日報', 'https://money.udn.com', 'public'),
|
||
('ctee', '工商時報', 'https://ctee.com.tw', 'public');
|
||
|
||
-- 2.2 新聞文章表
|
||
CREATE TABLE news_articles (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
source_id INT NOT NULL COMMENT '來源ID',
|
||
external_id VARCHAR(100) COMMENT '外部文章ID(防重複抓取)',
|
||
title VARCHAR(500) NOT NULL COMMENT '文章標題',
|
||
content LONGTEXT COMMENT '文章全文',
|
||
summary TEXT COMMENT '原文摘要',
|
||
url VARCHAR(500) NOT NULL COMMENT '原文連結',
|
||
author VARCHAR(100) COMMENT '作者',
|
||
published_at TIMESTAMP NULL COMMENT '發布時間',
|
||
crawled_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '抓取時間',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (source_id) REFERENCES news_sources(id),
|
||
UNIQUE KEY uk_source_external (source_id, external_id)
|
||
) COMMENT='新聞文章表';
|
||
|
||
CREATE INDEX idx_articles_published ON news_articles(published_at);
|
||
CREATE INDEX idx_articles_crawled ON news_articles(crawled_at);
|
||
CREATE FULLTEXT INDEX ft_articles_content ON news_articles(title, content);
|
||
|
||
-- 2.3 抓取任務記錄表
|
||
CREATE TABLE crawl_jobs (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
source_id INT NOT NULL COMMENT '來源ID',
|
||
status ENUM('pending', 'running', 'completed', 'failed') DEFAULT 'pending',
|
||
scheduled_at TIMESTAMP NOT NULL COMMENT '排程時間',
|
||
started_at TIMESTAMP NULL COMMENT '開始時間',
|
||
completed_at TIMESTAMP NULL COMMENT '完成時間',
|
||
articles_count INT DEFAULT 0 COMMENT '抓取文章數',
|
||
error_message TEXT COMMENT '錯誤訊息',
|
||
retry_count INT DEFAULT 0 COMMENT '重試次數',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (source_id) REFERENCES news_sources(id)
|
||
) COMMENT='抓取任務記錄表';
|
||
|
||
CREATE INDEX idx_crawl_jobs_status ON crawl_jobs(status);
|
||
CREATE INDEX idx_crawl_jobs_scheduled ON crawl_jobs(scheduled_at);
|
||
|
||
-- ============================================================
|
||
-- 3. 群組與關鍵字相關
|
||
-- ============================================================
|
||
|
||
-- 3.1 群組表
|
||
CREATE TABLE groups (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
name VARCHAR(100) NOT NULL COMMENT '群組名稱',
|
||
description TEXT COMMENT '群組描述',
|
||
category ENUM('industry', 'topic') NOT NULL COMMENT '分類:產業別/議題',
|
||
ai_background TEXT COMMENT 'AI背景資訊設定',
|
||
ai_prompt TEXT COMMENT 'AI摘要方向提示',
|
||
is_active BOOLEAN DEFAULT TRUE COMMENT '是否啟用',
|
||
created_by INT COMMENT '建立者ID',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (created_by) REFERENCES users(id)
|
||
) COMMENT='群組表';
|
||
|
||
-- 3.2 關鍵字表
|
||
CREATE TABLE keywords (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
group_id INT NOT NULL COMMENT '所屬群組ID',
|
||
keyword VARCHAR(100) NOT NULL COMMENT '關鍵字',
|
||
is_active BOOLEAN DEFAULT TRUE,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE,
|
||
UNIQUE KEY uk_group_keyword (group_id, keyword)
|
||
) COMMENT='關鍵字表';
|
||
|
||
CREATE INDEX idx_keywords_keyword ON keywords(keyword);
|
||
|
||
-- 3.3 新聞-群組關聯表(根據關鍵字匹配)
|
||
CREATE TABLE article_group_matches (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
article_id BIGINT NOT NULL,
|
||
group_id INT NOT NULL,
|
||
matched_keywords JSON COMMENT '匹配到的關鍵字列表',
|
||
match_score DECIMAL(5,2) COMMENT '匹配分數',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (article_id) REFERENCES news_articles(id) ON DELETE CASCADE,
|
||
FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE,
|
||
UNIQUE KEY uk_article_group (article_id, group_id)
|
||
) COMMENT='新聞-群組匹配關聯表';
|
||
|
||
CREATE INDEX idx_matches_group ON article_group_matches(group_id);
|
||
|
||
-- ============================================================
|
||
-- 4. 報告相關
|
||
-- ============================================================
|
||
|
||
-- 4.1 報告表
|
||
CREATE TABLE reports (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
group_id INT NOT NULL COMMENT '所屬群組ID',
|
||
title VARCHAR(200) NOT NULL COMMENT '報告標題',
|
||
report_date DATE NOT NULL COMMENT '報告日期',
|
||
ai_summary LONGTEXT COMMENT 'AI綜合摘要',
|
||
edited_summary LONGTEXT COMMENT '編輯後摘要(專員修改版)',
|
||
status ENUM('draft', 'pending', 'published', 'delayed') DEFAULT 'draft' COMMENT '狀態',
|
||
published_at TIMESTAMP NULL COMMENT '發布時間',
|
||
published_by INT COMMENT '發布者ID',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (group_id) REFERENCES groups(id),
|
||
FOREIGN KEY (published_by) REFERENCES users(id),
|
||
UNIQUE KEY uk_group_date (group_id, report_date)
|
||
) COMMENT='報告表';
|
||
|
||
CREATE INDEX idx_reports_status ON reports(status);
|
||
CREATE INDEX idx_reports_date ON reports(report_date);
|
||
|
||
-- 4.2 報告-新聞關聯表
|
||
CREATE TABLE report_articles (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
report_id BIGINT NOT NULL,
|
||
article_id BIGINT NOT NULL,
|
||
is_included BOOLEAN DEFAULT TRUE COMMENT '是否納入報告(專員篩選)',
|
||
display_order INT DEFAULT 0 COMMENT '顯示順序',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (report_id) REFERENCES reports(id) ON DELETE CASCADE,
|
||
FOREIGN KEY (article_id) REFERENCES news_articles(id),
|
||
UNIQUE KEY uk_report_article (report_id, article_id)
|
||
) COMMENT='報告-新聞關聯表';
|
||
|
||
-- ============================================================
|
||
-- 5. 讀者互動相關
|
||
-- ============================================================
|
||
|
||
-- 5.1 訂閱表
|
||
CREATE TABLE subscriptions (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
user_id INT NOT NULL,
|
||
group_id INT NOT NULL,
|
||
email_notify BOOLEAN DEFAULT TRUE COMMENT '是否Email通知',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||
FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE,
|
||
UNIQUE KEY uk_user_group (user_id, group_id)
|
||
) COMMENT='訂閱表';
|
||
|
||
-- 5.2 收藏表
|
||
CREATE TABLE favorites (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
user_id INT NOT NULL,
|
||
report_id BIGINT NOT NULL,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||
FOREIGN KEY (report_id) REFERENCES reports(id) ON DELETE CASCADE,
|
||
UNIQUE KEY uk_user_report (user_id, report_id)
|
||
) COMMENT='收藏表';
|
||
|
||
-- 5.3 留言表
|
||
CREATE TABLE comments (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
report_id BIGINT NOT NULL,
|
||
user_id INT NOT NULL,
|
||
content TEXT NOT NULL COMMENT '留言內容',
|
||
parent_id BIGINT COMMENT '父留言ID(回覆用)',
|
||
is_deleted BOOLEAN DEFAULT FALSE,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (report_id) REFERENCES reports(id) ON DELETE CASCADE,
|
||
FOREIGN KEY (user_id) REFERENCES users(id),
|
||
FOREIGN KEY (parent_id) REFERENCES comments(id)
|
||
) COMMENT='留言表';
|
||
|
||
CREATE INDEX idx_comments_report ON comments(report_id);
|
||
|
||
-- 5.4 個人筆記表
|
||
CREATE TABLE notes (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
user_id INT NOT NULL,
|
||
report_id BIGINT NOT NULL,
|
||
content TEXT NOT NULL COMMENT '筆記內容',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||
FOREIGN KEY (report_id) REFERENCES reports(id) ON DELETE CASCADE
|
||
) COMMENT='個人筆記表';
|
||
|
||
CREATE INDEX idx_notes_user_report ON notes(user_id, report_id);
|
||
|
||
-- ============================================================
|
||
-- 6. 系統設定相關
|
||
-- ============================================================
|
||
|
||
-- 6.1 系統設定表
|
||
CREATE TABLE system_settings (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
setting_key VARCHAR(50) NOT NULL UNIQUE COMMENT '設定鍵',
|
||
setting_value TEXT COMMENT '設定值',
|
||
setting_type ENUM('string', 'number', 'boolean', 'json') DEFAULT 'string',
|
||
description VARCHAR(200) COMMENT '設定描述',
|
||
updated_by INT COMMENT '更新者ID',
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (updated_by) REFERENCES users(id)
|
||
) COMMENT='系統設定表';
|
||
|
||
-- 預設系統設定
|
||
INSERT INTO system_settings (setting_key, setting_value, setting_type, description) VALUES
|
||
('crawl_schedule_time', '08:00', 'string', '每日抓取排程時間'),
|
||
('publish_deadline', '09:00', 'string', '報告發布截止時間'),
|
||
('llm_provider', 'claude', 'string', 'LLM提供者: openai/claude/ollama'),
|
||
('llm_api_key_encrypted', '', 'string', '加密後的API Key'),
|
||
('llm_model', 'claude-3-sonnet', 'string', '使用的模型名稱'),
|
||
('llm_ollama_endpoint', 'http://localhost:11434', 'string', 'Ollama端點'),
|
||
('data_retention_days', '60', 'number', '資料保留天數'),
|
||
('pdf_logo_path', '', 'string', 'PDF Logo檔案路徑'),
|
||
('pdf_header_text', '', 'string', 'PDF頁首文字'),
|
||
('pdf_footer_text', '', 'string', 'PDF頁尾文字'),
|
||
('smtp_host', '', 'string', 'SMTP伺服器'),
|
||
('smtp_port', '587', 'number', 'SMTP埠號'),
|
||
('smtp_username', '', 'string', 'SMTP帳號'),
|
||
('smtp_password_encrypted', '', 'string', '加密後SMTP密碼'),
|
||
('smtp_from_email', '', 'string', '寄件者Email'),
|
||
('smtp_from_name', '每日報導系統', 'string', '寄件者名稱');
|
||
|
||
-- 6.2 操作日誌表
|
||
CREATE TABLE audit_logs (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
user_id INT COMMENT '操作用戶ID',
|
||
action VARCHAR(50) NOT NULL COMMENT '操作類型',
|
||
target_type VARCHAR(50) COMMENT '目標類型',
|
||
target_id VARCHAR(50) COMMENT '目標ID',
|
||
details JSON COMMENT '操作詳情',
|
||
ip_address VARCHAR(45) COMMENT 'IP地址',
|
||
user_agent VARCHAR(500) COMMENT 'User Agent',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (user_id) REFERENCES users(id)
|
||
) COMMENT='操作日誌表';
|
||
|
||
CREATE INDEX idx_audit_user ON audit_logs(user_id);
|
||
CREATE INDEX idx_audit_action ON audit_logs(action);
|
||
CREATE INDEX idx_audit_created ON audit_logs(created_at);
|
||
|
||
-- 6.3 通知記錄表
|
||
CREATE TABLE notification_logs (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
user_id INT NOT NULL,
|
||
report_id BIGINT COMMENT '關聯報告ID',
|
||
notification_type ENUM('email', 'system') DEFAULT 'email',
|
||
subject VARCHAR(200) COMMENT '通知標題',
|
||
content TEXT COMMENT '通知內容',
|
||
status ENUM('pending', 'sent', 'failed') DEFAULT 'pending',
|
||
sent_at TIMESTAMP NULL,
|
||
error_message TEXT,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (user_id) REFERENCES users(id),
|
||
FOREIGN KEY (report_id) REFERENCES reports(id)
|
||
) COMMENT='通知記錄表';
|
||
|
||
CREATE INDEX idx_notification_status ON notification_logs(status);
|
||
|
||
-- ============================================================
|
||
-- 7. 資料清理事件(60天保留)
|
||
-- ============================================================
|
||
|
||
-- 建立事件排程器(需確保 event_scheduler=ON)
|
||
DELIMITER //
|
||
|
||
CREATE EVENT IF NOT EXISTS cleanup_old_data
|
||
ON SCHEDULE EVERY 1 DAY
|
||
STARTS CURRENT_TIMESTAMP
|
||
DO
|
||
BEGIN
|
||
DECLARE retention_days INT DEFAULT 60;
|
||
|
||
-- 取得設定的保留天數
|
||
SELECT CAST(setting_value AS UNSIGNED) INTO retention_days
|
||
FROM system_settings
|
||
WHERE setting_key = 'data_retention_days';
|
||
|
||
-- 刪除過期的新聞文章(會連帶刪除關聯資料)
|
||
DELETE FROM news_articles
|
||
WHERE crawled_at < DATE_SUB(NOW(), INTERVAL retention_days DAY);
|
||
|
||
-- 刪除過期的抓取任務記錄
|
||
DELETE FROM crawl_jobs
|
||
WHERE created_at < DATE_SUB(NOW(), INTERVAL retention_days DAY);
|
||
|
||
-- 刪除過期的操作日誌
|
||
DELETE FROM audit_logs
|
||
WHERE created_at < DATE_SUB(NOW(), INTERVAL retention_days DAY);
|
||
|
||
-- 刪除過期的通知記錄
|
||
DELETE FROM notification_logs
|
||
WHERE created_at < DATE_SUB(NOW(), INTERVAL retention_days DAY);
|
||
END//
|
||
|
||
DELIMITER ;
|
||
|
||
-- ============================================================
|
||
-- 8. 視圖(View)- 常用查詢
|
||
-- ============================================================
|
||
|
||
-- 8.1 今日待審核報告視圖
|
||
CREATE VIEW v_pending_reports AS
|
||
SELECT
|
||
r.id,
|
||
r.title,
|
||
r.report_date,
|
||
r.status,
|
||
g.name AS group_name,
|
||
g.category,
|
||
COUNT(ra.id) AS article_count,
|
||
SUM(CASE WHEN ra.is_included = TRUE THEN 1 ELSE 0 END) AS included_count
|
||
FROM reports r
|
||
JOIN groups g ON r.group_id = g.id
|
||
LEFT JOIN report_articles ra ON r.id = ra.report_id
|
||
WHERE r.report_date = CURDATE()
|
||
GROUP BY r.id;
|
||
|
||
-- 8.2 用戶訂閱群組視圖
|
||
CREATE VIEW v_user_subscriptions AS
|
||
SELECT
|
||
u.id AS user_id,
|
||
u.display_name,
|
||
u.email,
|
||
g.id AS group_id,
|
||
g.name AS group_name,
|
||
g.category,
|
||
s.email_notify
|
||
FROM users u
|
||
JOIN subscriptions s ON u.id = s.user_id
|
||
JOIN groups g ON s.group_id = g.id
|
||
WHERE u.is_active = TRUE AND g.is_active = TRUE;
|
||
|
||
-- 8.3 報告統計視圖
|
||
CREATE VIEW v_report_stats AS
|
||
SELECT
|
||
r.id AS report_id,
|
||
r.title,
|
||
r.report_date,
|
||
r.status,
|
||
g.name AS group_name,
|
||
COUNT(DISTINCT f.user_id) AS favorite_count,
|
||
COUNT(DISTINCT c.id) AS comment_count,
|
||
COUNT(DISTINCT s.user_id) AS subscriber_count
|
||
FROM reports r
|
||
JOIN groups g ON r.group_id = g.id
|
||
LEFT JOIN favorites f ON r.id = f.report_id
|
||
LEFT JOIN comments c ON r.id = c.report_id AND c.is_deleted = FALSE
|
||
LEFT JOIN subscriptions s ON g.id = s.group_id
|
||
GROUP BY r.id;
|
||
|
||
-- ============================================================
|
||
-- END OF SCHEMA
|
||
-- ============================================================
|