-- ON CONFLICT DO UPDATE(推荐,PostgreSQL 9.5+) INSERT INTO users (id, name, email) VALUES (1, '张三', 'zhangsan@example.com') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, email = EXCLUDED.email;
-- ON CONFLICT DO NOTHING(存在则忽略) INSERT INTO users (id, name, email) VALUES (1, '张三', 'zhangsan@example.com') ON CONFLICT (id) DO NOTHING;
SQL Server
1 2 3 4 5 6 7 8
-- MERGE 语句(SQL Server 2008+) MERGE users AS target USING (VALUES (1, '张三', 'zhangsan@example.com')) AS source (id, name, email) ON target.id = source.id WHEN MATCHED THEN UPDATESET name = source.name, email = source.email WHENNOT MATCHED THEN INSERT (id, name, email) VALUES (source.id, source.name, source.email);
Oracle
1 2 3 4 5 6 7 8
-- MERGE 语句(Oracle 9i+) MERGEINTO users t USING (SELECT1AS id, '张三'AS name, 'zhangsan@example.com'AS email FROM DUAL) s ON (t.id = s.id) WHEN MATCHED THEN UPDATESET t.name = s.name, t.email = s.email WHENNOT MATCHED THEN INSERT (id, name, email) VALUES (s.id, s.name, s.email);
SQLite
1 2 3 4 5 6 7 8
-- ON CONFLICT(SQLite 3.24+) INSERT INTO users (id, name, email) VALUES (1, '张三', 'zhangsan@example.com') ON CONFLICT(id) DO UPDATE SET name = EXCLUDED.name, email = EXCLUDED.email;
-- 旧版用 INSERT OR REPLACE(注意:会删除旧行再插入) INSERTOR REPLACE INTO users (id, name, email) VALUES (1, '张三', 'zhangsan@example.com');
-- MySQL: ALTER TABLE users MODIFY COLUMN name VARCHAR(100) NOT NULL; ALTER TABLE users CHANGE COLUMN old_name new_name VARCHAR(100);
-- PostgreSQL: ALTER TABLE users ALTERCOLUMN name TYPE VARCHAR(100); ALTER TABLE users ALTERCOLUMN name SETNOT NULL; ALTER TABLE users RENAME COLUMN old_name TO new_name;
-- SQL Server: ALTER TABLE users ALTERCOLUMN name VARCHAR(100) NOT NULL; EXEC sp_rename 'users.old_name', 'new_name', 'COLUMN';
-- Oracle: ALTER TABLE users MODIFY name VARCHAR2(100) NOT NULL; ALTER TABLE users RENAME COLUMN old_name TO new_name;
-- SQLite: -- SQLite 不支持直接修改列,需要重建表(3.35+ 支持 ALTER TABLE ... RENAME COLUMN) ALTER TABLE users RENAME COLUMN old_name TO new_name;
9.2 添加/删除列
1 2 3 4 5 6 7 8 9 10
-- 添加列(五家基本相同): ALTER TABLE users ADDCOLUMN age INT;
-- 删除列: -- MySQL: ALTER TABLE users DROP COLUMN age; -- PostgreSQL: ALTER TABLE users DROP COLUMN age; -- SQL Server: ALTER TABLE users DROP COLUMN age; -- Oracle: ALTER TABLE users DROP COLUMN age; -- SQLite: 不支持 DROP COLUMN(3.35+ 支持) ALTER TABLE users DROPCOLUMN age;
9.3 截断表
1 2 3 4 5 6 7 8 9
-- MySQL / PostgreSQL / SQL Server / Oracle / SQLite: TRUNCATETABLE users;
-- 普通索引(五家通用): CREATE INDEX idx_name ON users(name);
-- 唯一索引(五家通用): CREATEUNIQUE INDEX idx_email ON users(email);
-- 部分/条件索引(MySQL 不支持,PostgreSQL / SQL Server / Oracle / SQLite 支持): CREATE INDEX idx_active_users ON users(email) WHERE status =1; -- PostgreSQL / SQLite CREATE INDEX idx_active_users ON users(email) WHERE status =1; -- SQL Server: 用 Filtered Index
9.5 注释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
-- MySQL: COMMENT 关键字 CREATE TABLE t1 ( id INT COMMENT '主键ID', name VARCHAR(50) COMMENT '用户名' ) COMMENT='用户表';
-- CROSS APPLY:类似 INNER JOIN 子查询,但可以引用外部列 SELECT u.name, t.order_count FROM users u CROSS APPLY ( SELECTCOUNT(*) AS order_count FROM orders o WHERE o.user_id = u.id ) t;
-- OUTER APPLY:类似 LEFT JOIN 子查询 SELECT u.name, t.order_count FROM users u OUTER APPLY ( SELECTCOUNT(*) AS order_count FROM orders o WHERE o.user_id = u.id ) t;
-- 命名窗口(大多数数据库支持): SELECT name, salary, dept_id, ROW_NUMBER() OVER w AS rn, SUM(salary) OVER w AS running_total FROM employees WINDOW w AS (PARTITIONBY dept_id ORDERBY salary); -- 注意:SQL Server 不支持 WINDOW 子句,需要在每个 OVER 中重复定义
-- ========== MySQL ========== DELIMITER $$ CREATEPROCEDURE get_users_by_status(IN p_status INT) BEGIN SELECT*FROM users WHERE status = p_status; END$$ DELIMITER ; CALL get_users_by_status(1);
-- ========== PostgreSQL ========== CREATEOR REPLACE FUNCTION get_users_by_status(p_status INT) RETURNSTABLE(id INT, name VARCHAR, email VARCHAR) AS $$ BEGIN RETURN QUERY SELECT u.id, u.name, u.email FROM users u WHERE u.status = p_status; END; $$ LANGUAGE plpgsql; SELECT*FROM get_users_by_status(1);
-- ========== SQL Server ========== CREATEPROCEDURE get_users_by_status @p_statusINT AS BEGIN SELECT*FROM users WHERE status =@p_status; END; EXEC get_users_by_status 1;
-- ========== Oracle ========== CREATEOR REPLACE PROCEDURE get_users_by_status(p_status IN NUMBER) IS BEGIN FOR rec IN (SELECT*FROM users WHERE status = p_status) LOOP DBMS_OUTPUT.PUT_LINE(rec.name); END LOOP; END; EXEC get_users_by_status(1);
-- ========== MySQL ========== -- 会话级临时表(连接断开自动删除) CREATE TEMPORARY TABLE tmp_users AS SELECT*FROM users WHERE status =1;
-- ========== PostgreSQL ========== -- 会话级临时表 CREATE TEMPORARY TABLE tmp_users AS SELECT*FROM users WHERE status =1; -- 或事务级临时表(事务结束自动删除) CREATE TEMPORARY TABLE tmp_users ONCOMMITDROPAS SELECT*FROM users WHERE status =1;
-- ========== SQL Server ========== -- 本地临时表(# 开头,会话级) SELECT*INTO #tmp_users FROM users WHERE status =1; -- 全局临时表(## 开头,所有会话可见) SELECT*INTO ##tmp_users FROM users WHERE status =1;
-- ========== Oracle ========== -- 全局临时表(结构持久,数据会话/事务级) CREATEGLOBAL TEMPORARY TABLE tmp_users ( id NUMBER, name VARCHAR2(50) ) ONCOMMITDELETEROWS; -- 或 ON COMMIT PRESERVE ROWS INSERT INTO tmp_users SELECT id, name FROM users WHERE status =1;
-- ========== SQLite ========== -- 临时表(连接关闭删除) CREATE TEMPORARY TABLE tmp_users AS SELECT*FROM users WHERE status =1;