好吧,既然陪我玩,就奖励你一个。
12C写法:
with
move AS (
SELECT p ---- 源水桶编号
,m ---- 目标水桶编号
,'358' c ---- 水桶容量
FROM (SELECT LEVEL p FROM DUAL CONNECT BY LEVEL<=3),(SELECT LEVEL m FROM DUAL CONNECT BY LEVEL<=3)
WHERE p<>m
)
,t(s,path) as (
select '008', CAST('008' AS VARCHAR2(1000)) FROM DUAL
UNION ALL
SELECT new_s
,path||'->'||new_s
FROM t
,move
,LATERAL(SELECT SUBSTR(s,p,1)-LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)) ps
,SUBSTR(s,m,1)+LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)) ms
FROM DUAL
)
,LATERAL(SELECT DECODE(1,p,ps,m,ms,SUBSTR(s,1,1))
||DECODE(2,p,ps,m,ms,SUBSTR(s,2,1))
||DECODE(3,p,ps,m,ms,SUBSTR(s,3,1)) new_s
FROM DUAL
)
WHERE s<>'044'
AND SUBSTR(t.s,p,1)<>0 -----源水桶有水
AND SUBSTR(t.s,m,1)<SUBSTR(c,m,1) -----目标水桶有空
AND INSTR(path,new_s
)=0
)
select path from t where s='044'
;
with
move AS (
SELECT p ---- 源水桶编号
,m ---- 目标水桶编号
,'358' c ---- 水桶容量
FROM (SELECT LEVEL p FROM DUAL CONNECT BY LEVEL<=3),(SELECT LEVEL m FROM DUAL CONNECT BY LEVEL<=3)
WHERE p<>m
)
,t(s,path) as (
select '008', CAST('008' AS VARCHAR2(1000)) FROM DUAL
UNION ALL
SELECT new_s
,path||'->'||new_s
FROM t
JOIN move ON s<>'044'
AND SUBSTR(t.s,p,1)<>0 -----源水桶有水
AND SUBSTR(t.s,m,1)<SUBSTR(c,m,1) -----目标水桶有空
CROSS APPLY (SELECT SUBSTR(s,p,1)-LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)) ps
,SUBSTR(s,m,1)+LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)) ms
FROM DUAL
)
CROSS APPLY (SELECT DECODE(1,p,ps,m,ms,SUBSTR(s,1,1))
||DECODE(2,p,ps,m,ms,SUBSTR(s,2,1))
||DECODE(3,p,ps,m,ms,SUBSTR(s,3,1)) new_s
FROM DUAL
)
WHERE INSTR(path,new_s
)=0
)
select path from t where s='044'
;
11G写法很啰嗦:
with
move AS (
SELECT p ---- 源水桶编号
,m ---- 目标水桶编号
,'358' c ---- 水桶容量
FROM (SELECT LEVEL p FROM DUAL CONNECT BY LEVEL<=3),(SELECT LEVEL m FROM DUAL CONNECT BY LEVEL<=3)
WHERE p<>m
)
,t(s,path) as (
select '008', CAST('008' AS VARCHAR2(1000)) FROM DUAL
UNION ALL
SELECT DECODE(1,p,SUBSTR(s,p,1)-LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),m,SUBSTR(s,m,1)+LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),SUBSTR(s,1,1))
||DECODE(2,p,SUBSTR(s,p,1)-LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),m,SUBSTR(s,m,1)+LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),SUBSTR(s,2,1))
||DECODE(3,p,SUBSTR(s,p,1)-LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),m,SUBSTR(s,m,1)+LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),SUBSTR(s,3,1))
,path||'->'||DECODE(1,p,SUBSTR(s,p,1)-LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),m,SUBSTR(s,m,1)+LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),SUBSTR(s,1,1))
||DECODE(2,p,SUBSTR(s,p,1)-LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),m,SUBSTR(s,m,1)+LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),SUBSTR(s,2,1))
||DECODE(3,p,SUBSTR(s,p,1)-LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),m,SUBSTR(s,m,1)+LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),SUBSTR(s,3,1))
FROM t
,move
WHERE s<>'044'
AND SUBSTR(t.s,p,1)<>0 -----源水桶有水
AND SUBSTR(t.s,m,1)<SUBSTR(c,m,1) -----目标水桶有空
AND INSTR(path,DECODE(1,p,SUBSTR(s,p,1)-LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),m,SUBSTR(s,m,1)+LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),SUBSTR(s,1,1))
||DECODE(2,p,SUBSTR(s,p,1)-LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),m,SUBSTR(s,m,1)+LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),SUBSTR(s,2,1))
||DECODE(3,p,SUBSTR(s,p,1)-LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),m,SUBSTR(s,m,1)+LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)),SUBSTR(s,3,1))
)=0
)
select * from t where s='044'
;
11g 模拟12C LATERAL的写法:
with
move AS (
SELECT p ---- 源水桶编号
,m ---- 目标水桶编号
,'358' c ---- 水桶容量
FROM (SELECT LEVEL p FROM DUAL CONNECT BY LEVEL<=3),(SELECT LEVEL m FROM DUAL CONNECT BY LEVEL<=3)
WHERE p<>m
)
,t(s,path) as (
select '008', CAST('008' AS VARCHAR2(1000)) FROM DUAL
UNION ALL
SELECT new_s.column_value
,path||'->'||new_s.column_value
FROM t
,move
,TABLE(CAST(MULTISET(SELECT SUBSTR(s,p,1)-LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)) FROM DUAL) AS SYS.ODCIVARCHAR2LIST)) ps
,TABLE(CAST(MULTISET(SELECT SUBSTR(s,m,1)+LEAST(SUBSTR(s,p,1),SUBSTR(c,m,1)-SUBSTR(s,m,1)) FROM DUAL) AS SYS.ODCIVARCHAR2LIST)) ms
,TABLE(CAST(MULTISET(SELECT DECODE(1,p,ps.column_value,m,ms.column_value,SUBSTR(s,1,1))
||DECODE(2,p,ps.column_value,m,ms.column_value,SUBSTR(s,2,1))
||DECODE(3,p,ps.column_value,m,ms.column_value,SUBSTR(s,3,1)) FROM DUAL) AS SYS.ODCIVARCHAR2LIST)) new_s
WHERE s<>'044'
AND SUBSTR(t.s,p,1)<>0 -----源水桶有水
AND SUBSTR(t.s,m,1)<SUBSTR(c,m,1) -----目标水桶有空
AND INSTR(path,new_s.column_value
)=0
)
select path from t where s='044'
;
|