標準 SQL **不支援** 將變數直接用作列別名 (如 `SELECT col AS @var`)。別名必須在查詢編譯時期確定。
在運行時拼接字串構建完整 SQL 陳述式,再透過 `EXEC` / `sp_executesql` 執行。
DECLARE @n1 INT = MONTH(GETDATE());
DECLARE @n2 INT = @n1 + 1;
DECLARE @sql NVARCHAR(MAX);
-- 列名不能以數字開頭,加前綴 'm'
SET @sql = N'SELECT 當前月份發貨數 AS m' + CAST(@n1 AS NVARCHAR(2)) + N'月份發貨數, ' +
N'第二月份發貨數 AS m' + CAST(@n2 AS NVARCHAR(2)) + N'月份發貨數 ' +
N'FROM 發貨表';
EXEC sp_executesql @sql; -- 推薦使用 sp_executesql 參數化,防注入
SET @n1 = MONTH(NOW());
SET @n2 = @n1 + 1;
SET @sql = CONCAT('SELECT `當前月份發貨數` AS `m', @n1, '月份發貨數`, ',
'`第二月份發貨數` AS `m', @n2, '月份發貨數` ',
'FROM `發貨表`');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DECLARE
v_n1 NUMBER := TO_NUMBER(TO_CHAR(SYSDATE, 'MM'));
v_n2 NUMBER := v_n1 + 1;
v_sql VARCHAR2(1000);
BEGIN
v_sql := 'SELECT 當前月份發貨數 AS m' || v_n1 || '月份發貨數, ' ||
'第二月份發貨數 AS m' || v_n2 || '月份發貨數 ' ||
'FROM 發貨表';
EXECUTE IMMEDIATE v_sql; -- 若需返回結果集,需用 REF CURSOR
END;
/
-- 或使用 DBMS_SQL 套件完整動態查詢
| 場景 | 建議做法 |
|---|---|
| 前端報表顯示需動態列標題 | SQL 返回固定列名 (如 `month_1`, `month_2`),前端根據 metadata 動態渲染表頭 |
| 跨資料庫匯出需特定格式 | 應用層 (Java/C#/Python) 查詢固定結構後,組裝 CSV/Excel 時動態寫入標題列 |
| 多租戶自定義欄位名稱 | 元資料表儲存租戶欄位映射,查詢時 JOIN 元資料,應用層重命名 |
原答案提供的 `exec('select ... as m' + @n1 + '...')` 邏輯正確,但**務必注意列名不能以數字開頭** (故加 `m` 前綴),並嚴格防範注入。