SELECT* FROM orders WHERE user_id = :user_id ORDERBY created_at DESC OFFSET :offsetROWSFETCH NEXT :page_size ROWSONLY;
2.2 MERGE:经典 UPSERT(存在则更新,不存在则插入)
1 2 3 4 5 6 7 8
MERGEINTO user_profile t USING (SELECT :user_id AS user_id, :nickname AS nickname FROM dual) s ON (t.user_id = s.user_id) WHEN MATCHED THEN UPDATESET t.nickname = s.nickname, t.updated_at = SYSTIMESTAMP WHENNOT MATCHED THEN INSERT (user_id, nickname, created_at, updated_at) VALUES (s.user_id, s.nickname, SYSTIMESTAMP, SYSTIMESTAMP);
2.3 不可见索引(Invisible Index):安全做索引灰度
适合“想验证删索引/改索引会不会影响查询计划”:
1 2
ALTER INDEX idx_orders_user_id INVISIBLE; ALTER INDEX idx_orders_user_id VISIBLE;
3) 查询分析能力(Oracle 的强项):分析函数
3.1 每组 Top N:每个用户最近 3 笔支付
1 2 3 4 5 6 7 8 9 10
WITH ranked AS ( SELECT p.*, ROW_NUMBER() OVER (PARTITIONBY user_id ORDERBY paid_at DESC) AS rn FROM payments p ) SELECT* FROM ranked WHERE rn <=3 ORDERBY user_id, rn;
3.2 环比/同比:用 LAG/LEAD 做对比
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
WITH m AS ( SELECT TRUNC(paid_at, 'MM') AS month_start, SUM(amount) AS total FROM orders WHERE status ='PAID' GROUPBY TRUNC(paid_at, 'MM') ) SELECT month_start, total, LAG(total, 1) OVER (ORDERBY month_start) AS prev_month_total, total -LAG(total, 1) OVER (ORDERBY month_start) AS mom_delta FROM m ORDERBY month_start;
3.3 累计值(running total)
1 2 3 4 5 6
SELECT dt, amount, SUM(amount) OVER (ORDERBY dt) AS running_total FROM daily_sales ORDERBY dt;
4) 层级数据:CONNECT BY 与递归 CTE
4.1 CONNECT BY(经典写法,查组织树/分类树)
1 2 3 4 5 6 7 8 9
SELECT id, parent_id, name, LEVEL AS depth FROM categories STARTWITH id = :root_id CONNECTBY PRIOR id = parent_id ORDER SIBLINGS BY name;
4.2 递归 CTE(WITH …,结构更像标准 SQL)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
WITH category_tree (id, parent_id, name, depth) AS ( SELECT id, parent_id, name, 0 FROM categories WHERE id = :root_id
UNIONALL
SELECT c.id, c.parent_id, c.name, t.depth +1 FROM categories c JOIN category_tree t ON c.parent_id = t.id ) SELECT* FROM category_tree ORDERBY depth, id;