数据库编程大赛:一条SQL计算扑克牌24点

参赛选手:傅昌林
个人简介:HBI Solutions, Inc, VP Engineering
参赛数据库:SQL Server
性能评测:百万级数据代码性能评测 11.45秒
综合得分:78.8
以下是傅昌林选手的代码说明思路简介:
1. 数据范围估计
2. 由于只有715种数字组合且每种组合至多需要一种解答, 算法的主要思想是构建出这个结果集, 对于每条查询数据在这个结果集里寻找匹配
3. 随后按照具体的12条步骤生成最终结果。
以下是傅昌林选手的算法说明,结尾附完整SQL:
算法说明:


















参赛完整SQL:
;WITH Nums AS (SELECT CAST(value as INT) as val, value as strFROM STRING_SPLIT('1,2,3,4,5,6,7,8,9,10', ',')), Ops AS (SELECT value as strFROM STRING_SPLIT('+,-,*,/', ',')), ExprN2 AS (SELECTu.str + op.str + v.str AS str,CASEWHEN op.str = '+' THEN u.val + v.valWHEN op.str = '-' THEN u.val - v.valWHEN op.str = '*' THEN u.val * v.valWHEN op.str = '/' THEN u.val / v.valEND AS val,u.val AS n1,v.val AS n2,op.str AS op1FROM Nums uLEFT JOIN Nums v ON 1 = 1LEFT JOIN Ops op ON 1 = 1WHERE (op.str = '/' AND v.val <> 0 AND u.val % v.val = 0) OR (op.str != '/')), ExprN3 AS (SELECTIIF(op.str IN ('*', '/') AND u.op1 IN ('+', '-'), '(' + u.str + ')' + op.str + v.str, u.str + op.str + v.str) AS str,CASEWHEN op.str = '+' THEN u.val + v.valWHEN op.str = '-' THEN u.val - v.valWHEN op.str = '*' THEN u.val * v.valWHEN op.str = '/' THEN u.val / v.valEND AS val,u.n1,u.n2,v.val AS n3,u.op1,op.str AS op2FROM ExprN2 uLEFT JOIN Nums v ON 1 = 1LEFT JOIN Ops op ON 1 = 1WHERE (op.str = '/' AND v.val <> 0 AND u.val % v.val = 0) OR (op.str != '/')), ExprN4 AS (SELECTIIF(op.str IN ('*', '/') AND u.op2 IN ('+', '-'), '(' + u.str + ')' + op.str + v.str, u.str + op.str + v.str) AS str,CASEWHEN op.str = '+' THEN u.val + v.valWHEN op.str = '-' THEN u.val - v.valWHEN op.str = '*' THEN u.val * v.valWHEN op.str = '/' THEN u.val / v.valEND AS val,u.n1,u.n2,u.n3,v.val AS n4FROM ExprN3 uLEFT JOIN Nums v ON 1 = 1LEFT JOIN Ops op ON 1 = 1WHERE (op.str = '/' AND v.val <> 0 AND u.val % v.val = 0) OR (op.str != '/')), ExprN2N2 AS (SELECT'(' + u.str + ')' + op.str + '(' + v.str + ')' AS str,CASEWHEN op.str = '+' THEN u.val + v.valWHEN op.str = '-' THEN u.val - v.valWHEN op.str = '*' THEN u.val * v.valWHEN op.str = '/' THEN IIF(v.val = 0, 0, u.val / v.val)END AS val,u.n1,u.n2,v.n1 AS n3,v.n2 AS n4FROM ExprN2 uLEFT JOIN ExprN2 v ON 1 = 1LEFT JOIN Ops op ON 1 = 1WHERE (op.str = '/' AND IIF(v.val = 0, -1, u.val % v.val) = 0) OR (op.str != '/')), ExprSpecial AS (-- Case 1: a * (b/c + d) = ab/c + adSELECTa.str + '*(' + b.str + '/' + c.str + '+' + d.str + ')' AS str,24 AS val,a.val AS n1,b.val AS n2,c.val AS n3,d.val AS n4FROM Nums aLEFT JOIN Nums b ON 1 = 1LEFT JOIN Nums c ON 1 = 1LEFT JOIN Nums d ON 1 = 1WHERE a.val * b.val % c.val = 0 AND a.val * b.val / c.val + a.val * d.val = 24-- Case 2: a * (b/c - d) = ab/c - adUNIONSELECTa.str + '*(' + b.str + '/' + c.str + '+' + d.str + ')' AS str,24 AS val,a.val AS n1,b.val AS n2,c.val AS n3,d.val AS n4FROM Nums aLEFT JOIN Nums b ON 1 = 1LEFT JOIN Nums c ON 1 = 1LEFT JOIN Nums d ON 1 = 1WHERE a.val * b.val % c.val = 0 AND a.val * b.val / c.val - a.val * d.val = 24-- Case 3: a * (b - c/d) = ab - ac/dUNIONSELECTa.str + '*(' + b.str + '-' + c.str + '/' + d.str + ')' AS str,24 AS val,a.val AS n1,b.val AS n2,c.val AS n3,d.val AS n4FROM Nums aLEFT JOIN Nums b ON 1 = 1LEFT JOIN Nums c ON 1 = 1LEFT JOIN Nums d ON 1 = 1WHERE a.val * c.val % d.val = 0 AND a.val * b.val - a.val * c.val / d.val = 24-- Case 4: a / (b/c + d) = ac / (b + cd)UNIONSELECTa.str + '/(' + b.str + '/' + c.str + '+' + d.str + ')' AS str,24 AS val,a.val AS n1,b.val AS n2,c.val AS n3,d.val AS n4FROM Nums aLEFT JOIN Nums b ON 1 = 1LEFT JOIN Nums c ON 1 = 1LEFT JOIN Nums d ON 1 = 1WHERE (b.val + c.val * d.val) <> 0 AND a.val * c.val % (b.val + c.val * d.val) = 0 AND a.val * c.val / (b.val + c.val * d.val) = 24-- Case 5: a / (b/c - d) = ac / (b - cd)UNIONSELECTa.str + '/(' + b.str + '/' + c.str + '-' + d.str + ')' AS str,24 AS val,a.val AS n1,b.val AS n2,c.val AS n3,d.val AS n4FROM Nums aLEFT JOIN Nums b ON 1 = 1LEFT JOIN Nums c ON 1 = 1LEFT JOIN Nums d ON 1 = 1WHERE (b.val - c.val * d.val) <> 0 AND a.val * c.val % (b.val - c.val * d.val) = 0 AND a.val * c.val / (b.val - c.val * d.val) = 24-- Case 6: a / (b - c/d) = ad / (bd - c)UNIONSELECTa.str + '/(' + b.str + '-' + c.str + '/' + d.str + ')' AS str,24 AS val,a.val AS n1,b.val AS n2,c.val AS n3,d.val AS n4FROM Nums aLEFT JOIN Nums b ON 1 = 1LEFT JOIN Nums c ON 1 = 1LEFT JOIN Nums d ON 1 = 1WHERE (b.val * d.val - c.val) <> 0 AND a.val * d.val % (b.val * d.val - c.val) = 0 AND a.val * d.val / (b.val * d.val - c.val) = 24), ExprMerged AS (SELECT *FROM ExprN4WHERE val = 24UNIONSELECT *FROM ExprN2N2WHERE val = 24UNIONSELECT *FROM ExprSpecial), ExprWithTag AS (SELECT S.str AS result, STRING_AGG(num, ',') WITHIN GROUP (ORDER BY num) as tagFROM (SELECT str, col, num FROM ExprMerged UNPIVOT (num for col IN (n1, n2, n3, n4)) unpvt) SGROUP BY S.str), ResultWithRk AS (SELECT tag, result, ROW_NUMBER() OVER(PARTITION BY tag ORDER BY result) as rkFROM ExprWithTag), ResultLookup AS (SELECT tag, resultFROM ResultWithRkWHERE Rk = 1)SELECT Src.id, Src.c1, Src.c2, Src.c3, Src.c4, Ans.resultFROM poker24.cards SrcJOIN (SELECT S.id, STRING_AGG(num, ',') WITHIN GROUP (ORDER BY num) as tagFROM (SELECT id, col, num FROM poker24.cards UNPIVOT (num for col IN (c1, c2, c3, c4)) unpvt) SGROUP BY S.id) IdTagON Src.id = IdTag.idLEFT JOIN ResultLookup AnsON IdTag.tag = Ans.tagORDER BY Src.id
数据库编程大赛,下一次再聚!
感谢大家对本次《数据库编程大赛》的关注和支持,欢迎加入技术交流群,更多精彩活动不断,我们下次再相聚!


















