gitlink-cli/skills/gitlink-health/references/queries.md

10 KiB
Raw Blame History

SQL 查询参考

所有查询使用 SQLite通过命令行逐条执行。将 <repo_id> 等占位符替换为实际值。

每个查询都标注了它对应报告模板中的哪些字段。按照底部的组装清单逐项执行,确保不遗漏。

表结构

users

CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_name TEXT NOT NULL UNIQUE
);

repos

CREATE TABLE repos (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    repo_name TEXT NOT NULL,
    owner_id INTEGER NOT NULL,
    FOREIGN KEY (owner_id) REFERENCES users(id),
    UNIQUE(repo_name, owner_id)
);

issues

CREATE TABLE issues (
    id INTEGER PRIMARY KEY,
    repo_id INTEGER NOT NULL,
    number INTEGER,          -- 仓库内 Issue 编号 (project_issues_index)
    creater_id INTEGER,      -- 创建者 → users.id
    processor_id INTEGER,    -- 处理人 → users.idnullable
    create_time TIMESTAMP,   -- 创建时间,格式 "YYYY-MM-DD HH:MM"
    close_time TIMESTAMP,    -- 关闭时间nullable
    status TEXT CHECK(status IN ('close', 'open')),
    FOREIGN KEY (repo_id) REFERENCES repos(id),
    FOREIGN KEY (creater_id) REFERENCES users(id),
    FOREIGN KEY (processor_id) REFERENCES users(id)
);

API 字段映射:creater_idauthor.logindetailauthor_loginliststatusstatus.namedetail等于"关闭"→close。

pulls

CREATE TABLE pulls (
    id INTEGER PRIMARY KEY,
    repo_id INTEGER NOT NULL,
    number INTEGER NOT NULL,    -- PR 编号
    creater_id INTEGER,         -- 创建者 → users.id
    status TEXT CHECK(status IN ('merged', 'closed', 'open')),
    processor_id INTEGER,       -- 指派人 → users.idnullable来自 list 的 assign_user_login
    create_time TIMESTAMP,      -- 创建时间ISO 格式
    close_time TIMESTAMP,       -- 始终为 NULLAPI 不提供)
    FOREIGN KEY (repo_id) REFERENCES repos(id),
    FOREIGN KEY (creater_id) REFERENCES users(id),
    FOREIGN KEY (processor_id) REFERENCES users(id)
);

API 字段映射:statuspull_request_status0=open, 1=merged, 2=closedcreater_idauthor_login

1. 确定目标仓库

数据库可能包含多个仓库的数据,查询前需先获取目标仓库的 repo_id

# 列出所有仓库
sqlite3 data/gitlink_health.db "SELECT r.id, u.user_name AS owner, r.repo_name FROM repos r JOIN users u ON r.owner_id = u.id;"

# 根据 owner/repo 精确查找
sqlite3 data/gitlink_health.db "SELECT r.id FROM repos r JOIN users u ON r.owner_id = u.id WHERE u.user_name = '<owner>' AND r.repo_name = '<repo>';"

2. Issue 解决时长

2.1 单个 Issue 解决时长(天)

(补充查询,报告模板不使用)

SELECT
    i.id,
    i.number,
    (julianday(i.close_time) - julianday(i.create_time)) as resolution_days
FROM issues i
WHERE i.id = <issue_id>
  AND i.status = 'close';

2.2 已关闭 Issue 数 + 平均/中位数/最短/最长解决天数

对应模板字段:已关闭 Issue 数平均天数中位数最短最长

SELECT
    COUNT(*) as closed_issues_count,
    AVG(resolution_days) as avg_days,
    -- 中位数:排序后取中间值
    (SELECT resolution_days FROM (
        SELECT (julianday(close_time) - julianday(create_time)) as resolution_days,
               ROW_NUMBER() OVER (ORDER BY julianday(close_time) - julianday(create_time)) as rn,
               COUNT(*) OVER () as cnt
        FROM issues
        WHERE repo_id = <repo_id>
          AND status = 'close'
          AND close_time IS NOT NULL
          AND create_time IS NOT NULL
    ) WHERE rn IN ((cnt + 1) / 2, (cnt + 2) / 2)
    ORDER BY rn LIMIT 1) as median_days,
    MIN(resolution_days) as min_days,
    MAX(resolution_days) as max_days
FROM (
    SELECT (julianday(close_time) - julianday(create_time)) as resolution_days
    FROM issues
    WHERE repo_id = <repo_id>
      AND status = 'close'
      AND close_time IS NOT NULL
      AND create_time IS NOT NULL
);

2.3 解决时长分布

对应模板字段:解决时长分布1天内 x1周内 x1个月内 x

SELECT
    CASE
        WHEN resolution_days < 1 THEN '< 1天'
        WHEN resolution_days < 3 THEN '1-3天'
        WHEN resolution_days < 7 THEN '3-7天'
        WHEN resolution_days < 30 THEN '7-30天'
        ELSE '> 30天'
    END as duration_range,
    COUNT(*) as issue_count
FROM (
    SELECT (julianday(close_time) - julianday(create_time)) as resolution_days
    FROM issues
    WHERE repo_id = <repo_id>
      AND status = 'close'
      AND close_time IS NOT NULL
      AND create_time IS NOT NULL
)
GROUP BY duration_range
ORDER BY MIN(resolution_days);

填入模板时:1天内 = '< 1天' 的数量,1周内 = '1-3天' + '3-7天' 的数量之和,1个月内 = '7-30天' 的数量。

2.4 按时间段统计 Issue 解决时长

(补充查询,报告模板不使用)

SELECT
    strftime('%Y-%m', create_time) as month,
    AVG(julianday(close_time) - julianday(create_time)) as avg_resolution_days,
    COUNT(*) as closed_count
FROM issues
WHERE repo_id = <repo_id>
  AND status = 'close'
  AND close_time IS NOT NULL
  AND create_time IS NOT NULL
GROUP BY month
ORDER BY month;

3. PR 合并效率

3.1 PR 合并率(整体)

对应模板字段:合并率总数已合并开放已关闭

SELECT
    CAST(SUM(CASE WHEN status = 'merged' THEN 1 ELSE 0 END) AS REAL) /
    NULLIF(COUNT(*), 0) as merge_rate,
    COUNT(*) as total_prs,
    SUM(CASE WHEN status = 'merged' THEN 1 ELSE 0 END) as merged_count,
    SUM(CASE WHEN status = 'closed' THEN 1 ELSE 0 END) as closed_count,
    SUM(CASE WHEN status = 'open' THEN 1 ELSE 0 END) as open_count
FROM pulls
WHERE repo_id = <repo_id>;

填入模板时:合并率 = merge_rate * 100(保留整数百分比)。

3.2 按时间段统计 PR 合并率

(补充查询,报告模板不使用)

SELECT
    strftime('%Y-%m', create_time) as month,
    CAST(SUM(CASE WHEN status = 'merged' THEN 1 ELSE 0 END) AS REAL) /
    NULLIF(COUNT(*), 0) as merge_rate,
    COUNT(*) as total_prs
FROM pulls
WHERE repo_id = <repo_id>
GROUP BY month
ORDER BY month;

3.3 PR 关闭率

(补充查询,报告模板不使用)

SELECT
    CAST(COUNT(CASE WHEN status IN ('closed', 'merged') THEN 1 END) AS REAL) /
    NULLIF(COUNT(*), 0) as closure_rate
FROM pulls
WHERE repo_id = <repo_id>;

4. 贡献者活跃度

4.1 活跃贡献者数量

对应模板字段:活跃贡献者(最近一个月)

SELECT
    COUNT(DISTINCT creater_id) as active_contributors
FROM pulls
WHERE repo_id = <repo_id>
  AND create_time BETWEEN '<start_date>' AND '<end_date>';

<start_date> 设为 30 天前的日期,<end_date> 设为当天。

4.2 新贡献者(首次 PR 在最近一个月内)

对应模板字段:新增贡献者(最近一个月)

SELECT
    u.user_name,
    MIN(p.create_time) as first_pr_time
FROM pulls p
JOIN users u ON p.creater_id = u.id
WHERE p.repo_id = <repo_id>
GROUP BY p.creater_id
HAVING first_pr_time BETWEEN '<start_date>' AND '<end_date>';

<start_date> 同上设为 30 天前。查询结果的行数 = 新增贡献者数user_name 列表可附在报告中。

4.3 TOP 贡献者(按 PR 数排名)

对应模板字段:TOP 贡献者(按 PR 数排名)

SELECT
    u.user_name,
    COUNT(*) as pr_count
FROM pulls p
JOIN users u ON p.creater_id = u.id
WHERE p.repo_id = <repo_id>
GROUP BY p.creater_id
ORDER BY pr_count DESC;

取前 5~10 名填入模板,格式:user1 x, user2 x, ...

4.4 指定时间段内贡献者活跃度

(补充查询,报告模板不使用)

SELECT
    u.user_name,
    COUNT(*) as pr_count
FROM pulls p
JOIN users u ON p.creater_id = u.id
WHERE p.repo_id = <repo_id>
  AND p.create_time BETWEEN '<start_date>' AND '<end_date>'
GROUP BY p.creater_id
ORDER BY pr_count DESC;

4.5 贡献者月度活跃度趋势

(补充查询,报告模板不使用)

SELECT
    strftime('%Y-%m', p.create_time) as month,
    u.user_name,
    COUNT(*) as pr_count
FROM pulls p
JOIN users u ON p.creater_id = u.id
WHERE p.repo_id = <repo_id>
GROUP BY month, p.creater_id
ORDER BY month, pr_count DESC;

5. 补充查询

(以下查询不对应报告模板字段,用于数据验证或扩展分析)

Issue 状态汇总

SELECT status, COUNT(*) as count
FROM issues WHERE repo_id = <repo_id>
GROUP BY status;

PR 状态汇总

SELECT status, COUNT(*) as count
FROM pulls WHERE repo_id = <repo_id>
GROUP BY status;

贡献者总数

SELECT COUNT(DISTINCT creater_id) as total_contributors
FROM (
    SELECT creater_id FROM pulls WHERE repo_id = <repo_id> AND creater_id IS NOT NULL
    UNION
    SELECT creater_id FROM issues WHERE repo_id = <repo_id> AND creater_id IS NOT NULL
);

报告组装清单

按以下顺序逐项执行查询、填入模板。每完成一项打勾,最终输出前核对所有 是否齐全。

  • 已关闭 Issue 数 → 执行 2.2,取 closed_issues_count
  • 平均天数 → 执行 2.2,取 avg_days(保留 1 位小数)
  • 中位数 → 执行 2.2,取 median_days(保留 1 位小数)
  • 最短 x 天 → 执行 2.2,取 min_days(保留 1 位小数)
  • 最长 x 天 → 执行 2.2,取 max_days(保留 1 位小数)
  • 解决时长分布 → 执行 2.3汇总1天内 = '< 1天'1周内 = 1-3天 + 3-7天1个月内 = 7-30天
  • 合并率 x% → 执行 3.1,取 merge_rate * 100(整数)
  • 总数 → 执行 3.1,取 total_prs
  • 已合并 → 执行 3.1,取 merged_count
  • 开放 → 执行 3.1,取 open_count
  • 已关闭 → 执行 3.1,取 closed_count
  • 活跃贡献者(最近一个月) → 执行 4.1,设 start_date = 30天前
  • 新增贡献者(最近一个月) → 执行 4.2,设 start_date = 30天前
  • TOP 贡献者 → 执行 4.3,取前 5~10 名

输出前核对:报告必须包含上述全部 14 个字段,不允许省略任何一个。