-- 正確
SELECT a.appname FROM appinfo a;
-- 錯誤
SELECT a.appname FROM appinfo AS a;
原因:Oracle 不支援 AS 關鍵字用於表別名,僅用於欄位別名。避免與 PL/SQL 宣告區 AS/IS 混淆。
-- 正確
SELECT af.keynode INTO kn FROM appfoundation af WHERE af.appid = aid;
-- 錯誤
SELECT af.keynode FROM appfoundation af WHERE af.appid = aid;
-- PLS-00428: an INTO clause is expected in this SELECT statement
規則:PL/SQL 中單行查詢強制要求 INTO 接收結果;多行查詢需用游標或 BULK COLLECT。
-- 風險:無資料拋 NO_DATA_FOUND,多行拋 TOO_MANY_ROWS
SELECT SUM(vcount) INTO fcount FROM a WHERE bid = 'xxxxxx';
-- 安全模式
DECLARE
v_cnt NUMBER;
BEGIN
SELECT COUNT(*) INTO v_cnt FROM a WHERE bid = 'xxxxxx';
IF v_cnt > 0 THEN
SELECT SUM(vcount) INTO fcount FROM a WHERE bid = 'xxxxxx';
ELSE
fcount := 0;
END IF;
END;
-- 正確:表別名區分欄位
SELECT af.keynode INTO kn FROM appfoundation af
WHERE af.appid = aid AND af.foundationid = fid;
-- 錯誤:別名與欄位同名導致歧義
SELECT af.keynode INTO kn FROM appfoundation af
WHERE af.appid = appid AND af.foundationid = foundationid;
-- ORA-01422: exact fetch returns more than requested number of rows
原因:appid = appid 永真,等同無 WHERE 條件,返回多行。
-- 問題:無匹配行時 SUM 返回 NULL,非 0
SELECT SUM(vcount) INTO fcount FROM a WHERE bid = 'xxxxxx';
-- 即使 fcount NUMBER := 0 預設,仍被覆蓋為 NULL
-- 修正
IF fcount IS NULL THEN fcount := 0; END IF;
this.pnumberManager.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
CallableStatement cs = session.connection()
.prepareCall("{call modify_appnumber_remain(?)}");
cs.setString(1, foundationid);
cs.execute();
return null;
}
});
關鍵點:使用 CallableStatement、{call proc_name(?)} 語法、正確綁定參數。
| 類別 | 規範 |
|---|---|
| 命名 | 表別名簡短有意義(t, a, b);避免與欄位同名 |
| 查詢 | 單行必用 INTO;多行用游標/BULK COLLECT |
| 異常 | 捕獲 NO_DATA_FOUND、TOO_MANY_ROWS;記錄 SQLERRM |
| 空值 | 聚合函數結果必做 NULL 判斷;NVL/COALESCE 預設值 |
| 參數 | IN/OUT/IN OUT 明確標註;避免過度使用 OUT |
| 除錯 | DBMS_OUTPUT + SET SERVEROUTPUT ON;正式環境移除 |
| 編譯 | SHOW ERRORS 即時檢查;單元測試覆蓋邊界條件 |
CREATE OR REPLACE FUNCTION get_sum_vcount(p_bid VARCHAR2) RETURN NUMBER AS
v_result NUMBER;
BEGIN
SELECT NVL(SUM(vcount), 0) INTO v_result -- NVL 直接處理 NULL
FROM a WHERE bid = p_bid;
RETURN v_result;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
RETURN 0; -- 或 RAISE 視業務而定
END;
/