環境
Windows Server 2003 x64 簡體中文, MySQL 5.5 (UTF8編碼), PostgreSQL 9.1.4-1 (UTF8編碼)
Spring 3.0.7, Struts 2.3.4, Hibernate 3.5.5 java
從MySQL遷移到PostgreSQL sql
-----------------------------分隔線-----------------------------
* 分頁寫法的區別
安全
|
PostgreSQL |
MySQL |
LIMIT 數量 |
支持 |
支持 |
LIMIT 下標, 數量 |
不支持 |
支持 |
LIMIT 數量 OFFSET 下標 |
支持 |
支持 |
SELECT * FROM user LIMIT 10; -- PostgreSQL與MySQL均支持 SELECT * FROM user LIMIT 10, 10; -- PostgreSQL不支持,MySQL支持 SELECT * FROM user LIMIT 10 OFFSET 10; -- PostgreSQL與MySQL均支持-----------------------------分隔線-----------------------------
CREATE TABLE users ( id INT(11) NOT NULL AUTO_INCREMENT, name VARCHAR(50) NOT NULL, PRIMARY KEY (id) );
CREATE TABLE users( id serial NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY (id ) );
-- 更安全有效的解決方案請參考http://stackoverflow.com/questions/244243/how-to-reset-postgres-primary-key-sequence-when-it-falls-out-of-sync/* 假若有表a從MySQL遷移過來,其中有數據100條,若在創建此表時沒有指定序列,PG會默認給此表的主鍵列一個 sequence——它是增加的,幅度爲1。此時若用Hibernate來給表a添加數據會報錯,說主鍵1已經存在! 因此能夠在遷移表以後,將表的sequence做少量修改,讓其從當前表的主鍵的最大值再加1來開始!便可解決 Hibernate添加數據時報錯的問題 ALTER SEQUENCE "public"."表名_主鍵名_seq" RESTART WITH (PK的最大值 + 1); 或 ALTER SEQUENCE 表名_主鍵名_seq RESTART WITH (PK的最大值 + 1); e.g. ALTER SEQUENCE file_types_id_seq" RESTART WITH 10; 從上面stackoverflow.com網站上獲得的更加簡單有效的一句SQL語句以下: SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), (SELECT MAX(id) FROM table_name)+1); */
DROP TABLE IF EXISTS recipient_recipientgroup; CREATE TABLE IF NOT EXISTS recipient_recipientgroup ( id serial NOT NULL, recipient_id INTEGER DEFAULT NULL, recipient_group_id INTEGER DEFAULT NULL, PRIMARY KEY (id), KEY FK_recipient_recipientgroup_recipient (recipient_id), KEY FK_recipient_recipientgroup_recipient_group (recipient_group_id), CONSTRAINT FK_recipient_recipientgroup_recipient FOREIGN KEY (recipient_id) REFERENCES recipient (id), CONSTRAINT FK_recipient_recipientgroup_recipient_group FOREIGN KEY (recipient_group_id) REFERENCES recipient_group (id) );
DROP TABLE IF EXISTS recipient_recipientgroup; CREATE TABLE IF NOT EXISTS recipient_recipientgroup ( id serial NOT NULL, recipient_id INTEGER DEFAULT NULL, recipient_group_id INTEGER DEFAULT NULL, PRIMARY KEY (id), -- KEY FK_recipient_recipientgroup_recipient (recipient_id), -- KEY FK_recipient_recipientgroup_recipient_group (recipient_group_id), CONSTRAINT FK_recipient_recipientgroup_recipient FOREIGN KEY (recipient_id) REFERENCES recipient (id), CONSTRAINT FK_recipient_recipientgroup_recipient_group FOREIGN KEY (recipient_group_id) REFERENCES recipient_group (id) );
/** * 參考SpringSide3,統必定義id的entity基類. * * 基類統必定義id的屬性名稱、數據類型、列名映射及生成策略. * 子類可重載getId()函數重定義id的列名映射和生成策略. */ //JPA 基類的標識 @MappedSuperclass public abstract class IdEntity { protected Long id; @Id // @GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(unique = true, nullable = false) public Long getId() { return this.id; } public void setId(Long id) { this.id = id; } }
* 代碼中的SQL/HQL 更改 app
public List<LeakageDetail> findExceptLeakageDetailList(String ids) { String queryString = "SELECT * FROM leakage_detail " + "WHERE " // -- DATE_FORMAT(find_date, '%Y%m')<(DATE_FORMAT(NOW(), '%Y%m')-1) AND + "CONCAT(find_date, find_process) IN ( " + "SELECT CONCAT(find_date, find_process) AS xx " + "FROM leakage_detail WHERE id IN(" + ids + ")" + "GROUP BY find_date, find_process " // + "HAVING COUNT(xx)>5)"; // 這種寫法MySQL支持,PostgreSQL不支持! + "HAVING COUNT(CONCAT(find_date, find_process))>5) AND id IN(" + ids + ") ORDER BY find_date, find_process"; logger.info("Leakage模塊數據導入時發送漏液異常郵件的查詢sql->"+queryString); Query query = getSession().createSQLQuery(queryString).addEntity(LeakageDetail.class); return query.list(); }
public List<StatisticalAnalysisVo> getStatisticalAnalysisList() { // String hql = "select workshop as name, count(id) as num from DataModel where date_format(create_at, '%Y-%m')=date_format(now(), '%Y-%m') group by workshop"; String sql = "select workshop as name, count(id) as num " + "from data_models " // + "where date_format(create_at, '%Y-%m')=date_format(now(), '%Y-%m') " // date_format函數是MySQL專用的 + "where to_char(create_at, 'yyyy-MM')=to_char(now(), 'yyyy-MM') " // PostgreSQL中的日期格式化函數是to_char + "group by workshop"; // Query query = getSession().createSQLQuery(hql); Query query = getSession().createSQLQuery(sql).addScalar("name", Hibernate.STRING).addScalar("num", Hibernate.LONG); query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP) .setResultTransformer(Transformers.aliasToBean(StatisticalAnalysisVo.class)); return query.list(); }
* 存儲過程更改
MySQL ide
DROP PROCEDURE IF EXISTS `calcUlclp`; DELIMITER // CREATE DEFINER=`root`@`localhost` PROCEDURE `calcUlclp`() COMMENT '計算Hipot不良率的上下限的存儲過程' BEGIN SELECT (@rownum := @rownum + 1) AS `id`, DATE_FORMAT(lot_no_to_date, '%Y%m') AS year_and_month, `model_no`, group_no, SUM(liquid_injected_input_num) AS total_input, SUM(short_circuit_num) AS total_short, COUNT(DISTINCT(lot_no)) AS month_num_of_product_days ,ROUND(SUM(liquid_injected_input_num) / COUNT(DISTINCT(lot_no))) AS sample_size_n ,ROUND(SUM(short_circuit_num) / SUM(liquid_injected_input_num), 4) AS nonconforming_rate_mean_p FROM hipot, (SELECT @rownum := 0) AS r WHERE liquid_injected_input_num!=0 GROUP BY `model_no`, group_no, year_and_month ; END// DELIMITER ;
PostgreSQL 函數
DROP FUNCTION IF EXISTS calcUlclp(); CREATE OR REPLACE FUNCTION calcUlclp() RETURNS SETOF record AS $BODY$ declare -- sql varchar; rownum int; v_rc record; BEGIN for v_rc in SELECT (rownum = rownum + 1) AS id, to_char(lot_no_to_date, 'yyyyMM') AS year_and_month, model_no, group_no, SUM(liquid_injected_input_num) AS total_input, SUM(short_circuit_num) AS total_short, COUNT(DISTINCT(lot_no)) AS month_num_of_product_days ,ROUND(SUM(liquid_injected_input_num) / COUNT(DISTINCT(lot_no))) AS sample_size_n ,ROUND(SUM(short_circuit_num) / SUM(liquid_injected_input_num), 4) AS nonconforming_rate_mean_p FROM hipot, (SELECT rownum = 0) AS r WHERE liquid_injected_input_num!=0 GROUP BY model_no, group_no, year_and_month loop return next v_rc; end loop; END; $BODY$ LANGUAGE 'plpgsql' VOLATILE; -- 調用存儲過程 /* SELECT * from calcUlclp() as t(id_ boolean, year_and_month text, model_no varchar, group_no varchar, total_input bigint, total_short numeric, month_num_of_product_days bigint, sample_size_n double precision, nonconforming_rate_mean_p numeric); */