本文展示如何在 SQL Server 2008 R2 環境下,純粹使用 T-SQL 的集合運算 (CTE 遞迴產生排列組合) 與字串模式比對,解決經典邏輯謎題:Baker、Cooper、Fletcher、Miller、Smith 住在五層樓的不同樓層,依條件推導各人樓層。
SUBSTRING、LIKE 模式比對過濾符合所有條件的排列。CREATE TABLE #ttb (subname CHAR(1), realname VARCHAR(10));
INSERT INTO #ttb VALUES
('A','Baker'),('B','Cooper'),('C','Fletcher'),('D','Miller'),('E','Smith');
WITH x0 AS (
SELECT CONVERT(VARCHAR(10), 'A') AS hid UNION ALL
SELECT 'B' UNION ALL SELECT 'C' UNION ALL SELECT 'D' UNION ALL SELECT 'E'
),
x1 AS (
SELECT hid FROM x0 WHERE LEN(hid) <= 5
UNION ALL
SELECT CONVERT(VARCHAR(10), a.hid + b.hid)
FROM x0 a INNER JOIN x1 b ON CHARINDEX(a.hid, b.hid, 1) = 0
)
SELECT hid AS name INTO #tt FROM x1 WHERE LEN(hid) = 5 ORDER BY hid;
WITH x2 AS (
SELECT name FROM #tt
WHERE SUBSTRING(name, 5, 1) <> 'A' -- Baker 不住頂樓
AND SUBSTRING(name, 1, 1) <> 'B' -- Cooper 不住底樓
AND SUBSTRING(name, 1, 1) <> 'C' AND SUBSTRING(name, 5, 1) <> 'C' -- Fletcher 不住首尾
AND name LIKE '%B%D%' -- Miller 在 Cooper 之上 (D 在 B 後)
AND name NOT LIKE '%CE%' AND name NOT LIKE '%EC%' -- Smith 與 Fletcher 不相鄰
AND name NOT LIKE '%BC%' AND name NOT LIKE '%CB%' -- Fletcher 與 Cooper 不相鄰
),
x3 AS (
SELECT number AS floor, SUBSTRING(x2.name, number, 1) AS code
FROM master.dbo.spt_values
INNER JOIN x2 ON 1=1
WHERE type = 'P' AND number BETWEEN 1 AND 5
)
SELECT x3.floor AS 樓層, t.realname AS 姓名
FROM x3 INNER JOIN #ttb t ON t.subname = x3.code
ORDER BY x3.floor;
唯一解:
| 樓層 | 姓名 |
|---|---|
| 1 | Cooper |
| 2 | Baker |
| 3 | Fletcher |
| 4 | Miller |
| 5 | Smith |

GENERATE_SERIES 或 PERMUTATION 內建函數的舊版 SQL Server 中,利用 CHARINDEX 排除已用字元,逐層疊加字串產生全排列。SUBSTRING(name, position, 1) 取特定樓層代碼;LIKE '%B%D%' 表示 D 在 B 之後 (不一定相鄰);NOT LIKE '%CE%' 排除相鄰組合。BETWEEN 1 AND 5 產生樓層號 1-5,再將排列字串逐字元拆解對應。此模式可應用於:
對於大規模組合問題,建議改用專屬最佳化演算法 (CP-SAT、遺傳演算法) 或外部程式 (Python OR-Tools) 求解,T-SQL 集合運算較適合中小規模邏輯推理。