SqlStrHelper.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. using LJLib.Method;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Text.RegularExpressions;
  8. namespace LJLib.DAL.SQL
  9. {
  10. internal static class SqlStrHelper
  11. {
  12. /// <summary>
  13. /// 从查询语句中分离出字段部分与表部分
  14. /// </summary>
  15. /// <param name="selectstr">查询语句ie:select...from...</param>
  16. /// <returns>两项分别是字段部分、表部分</returns>
  17. private static string[] SpliteSelectStr(string selectstr)
  18. {
  19. Regex regex = new Regex(@"\bselect\s+(distinct\s+)?(.+?)\s+from\s+(.*)", RegexOptions.IgnoreCase | RegexOptions.Singleline);
  20. Match match = regex.Match(selectstr);
  21. string outCmdStr = string.Empty;
  22. if (match.Success)
  23. {
  24. return new[] {match.Groups[2].Value.Trim(), match.Groups[3].Value.Trim(), match.Groups[1].Value.Trim()};
  25. }
  26. else
  27. {
  28. throw new Exception("selectstr分析失败,ie:select...from...");
  29. }
  30. }
  31. /// <summary>
  32. /// 分析字段部分
  33. /// </summary>
  34. /// <param name="orgFieldStr">字段部分</param>
  35. /// <param name="orgFields">字段名对字段表达式</param>
  36. /// <param name="orgOrderFields">字段名对排序表达式</param>
  37. private static void AnalyseFields(string orgFieldStr, Dictionary<string, string> orgFields, Dictionary<string, string> orgOrderFields)
  38. {
  39. string[] selectFieldArr = SplitFields(orgFieldStr);
  40. string[] pattens = new string[] { @"^\s*(?<sort>(?<key>\w+))\s*=.+$", @"^.+\s+as\s+(?<sort>(?<key>\w+))\s*$", @"^.+\s+(?<sort>(?<key>\w+))\s*$", @"^(?<sort>.*\.\s*(?<key>\w+)\s*)$", @"^\s*(?<sort>(?<key>\w+))\s*$" };
  41. foreach (string orgField in selectFieldArr)
  42. {
  43. var find = false;
  44. foreach (string patten in pattens)
  45. {
  46. Match fiMatch = Regex.Match(orgField, patten, RegexOptions.IgnoreCase | RegexOptions.Singleline);
  47. if (fiMatch.Success)
  48. {
  49. find = true;
  50. string key = fiMatch.Groups["key"].Value.Trim().ToLower();
  51. if (orgFields.ContainsKey(key))
  52. {
  53. throw new Exception(string.Format("查询字段名重复:[{0}] = [{1}]", orgFields[key], orgField));
  54. }
  55. orgFields[key] = fiMatch.Value.Trim();
  56. orgOrderFields[key] = fiMatch.Groups["sort"].Value.Trim();
  57. break;
  58. }
  59. }
  60. if (!find)
  61. {
  62. throw new Exception(string.Format("字段表达式分析失败:{0}", orgField));
  63. }
  64. }
  65. }
  66. /// <summary>
  67. /// 将字段部分拆分
  68. /// </summary>
  69. /// <param name="orgFieldStr">字段部分</param>
  70. /// <returns>各字段</returns>
  71. private static string[] SplitFields(string orgFieldStr)
  72. {
  73. List<string> rslt = new List<string>();
  74. string builder = string.Empty;
  75. Stack<char> states = new Stack<char>();
  76. for (int i = 0; i < orgFieldStr.Length; i++)
  77. {
  78. char cur = orgFieldStr[i];
  79. if (states.Count == 0)
  80. {
  81. if (cur == ',')
  82. {
  83. rslt.Add(builder);
  84. builder = string.Empty;
  85. }
  86. else
  87. {
  88. builder += cur;
  89. if (cur == '(' || cur == '\'')
  90. {
  91. states.Push(cur);
  92. }
  93. }
  94. }
  95. else
  96. {
  97. builder += cur;
  98. char curstate = states.Peek();
  99. if (curstate == '\'')
  100. {
  101. if (cur == '\'')
  102. {
  103. states.Pop();
  104. }
  105. }
  106. else
  107. {
  108. if (cur == '(' || cur == '\'')
  109. {
  110. states.Push(cur);
  111. }
  112. else if (cur == ')')
  113. {
  114. states.Pop();
  115. }
  116. }
  117. }
  118. }
  119. rslt.Add(builder.Trim());
  120. return rslt.ToArray();
  121. }
  122. /// <summary>
  123. /// 生成新的字段语句
  124. /// </summary>
  125. /// <param name="orgFields">字段名-字段表达式</param>
  126. /// <param name="preOutFieldStr">输出字段名ie:mtrlid,mtrlname,如果与原始字段完全不匹配就输出全部字段,最终会变成与输出字段一至</param>
  127. /// <returns>新的字段语句</returns>
  128. private static string BuildSelectFields(Dictionary<string, string> orgFields, ref string preOutFieldStr, string orderFieldStr = null)
  129. {
  130. string outFieldStr = string.Empty;
  131. Dictionary<string, string> outFields = new Dictionary<string, string>();
  132. if (!string.IsNullOrEmpty(preOutFieldStr))
  133. {
  134. string[] fields = preOutFieldStr.Split(',');
  135. foreach (string field in fields)
  136. {
  137. string key = field.Trim().ToLower();
  138. if (orgFields.ContainsKey(key) && !outFields.ContainsKey(key))
  139. {
  140. outFields[key] = orgFields[key];
  141. }
  142. }
  143. }
  144. if (!string.IsNullOrEmpty(orderFieldStr))
  145. {
  146. string[] fields = orderFieldStr.Split(',');
  147. foreach (string field in fields)
  148. {
  149. string key = field.Trim().ToLower();
  150. if (orgFields.ContainsKey(key) && !outFields.ContainsKey(key))
  151. {
  152. outFields[key] = orgFields[key];
  153. }
  154. }
  155. }
  156. preOutFieldStr = string.Empty;
  157. if (outFields.Count == 0)
  158. {
  159. outFields = orgFields;
  160. }
  161. foreach (KeyValuePair<string, string> kvp in outFields)
  162. {
  163. if (string.IsNullOrEmpty(outFieldStr))
  164. {
  165. outFieldStr = kvp.Value;
  166. }
  167. else
  168. {
  169. outFieldStr += "," + kvp.Value;
  170. }
  171. if (string.IsNullOrEmpty(preOutFieldStr))
  172. {
  173. preOutFieldStr = kvp.Key;
  174. }
  175. else
  176. {
  177. preOutFieldStr += "," + kvp.Key;
  178. }
  179. }
  180. return outFieldStr;
  181. }
  182. /// <summary>
  183. /// 生成新的排序语名
  184. /// </summary>
  185. /// <param name="orgOrderFields">字段名-字段表达式</param>
  186. /// <param name="preOrderStr">输出字段名ie:mtrlid asc,mtrlname desc</param>
  187. /// <returns>可为空</returns>
  188. private static string BuildOrderFields(Dictionary<string, string> orgOrderFields, string preOrderStr)
  189. {
  190. string outOrderStr = string.Empty;
  191. Dictionary<string, string> outOrderFields = new Dictionary<string, string>();
  192. if (!string.IsNullOrEmpty(preOrderStr))
  193. {
  194. string[] fields = preOrderStr.Split(',');
  195. foreach (string field in fields)
  196. {
  197. string key = field.Trim().ToLower();
  198. string[] arr = key.Split(' ');
  199. if (arr.Length > 1)
  200. {
  201. key = arr[0];
  202. string sort = arr[arr.Length - 1];
  203. if (orgOrderFields.ContainsKey(key) && !outOrderFields.ContainsKey(key) && (sort == "asc" || sort == "desc"))
  204. {
  205. outOrderFields[key] = orgOrderFields[key] + " " + sort;
  206. }
  207. }
  208. else
  209. {
  210. if (orgOrderFields.ContainsKey(key) && !outOrderFields.ContainsKey(key))
  211. {
  212. outOrderFields[key] = orgOrderFields[key];
  213. }
  214. }
  215. }
  216. }
  217. foreach (KeyValuePair<string, string> kvp in outOrderFields)
  218. {
  219. if (string.IsNullOrEmpty(outOrderStr))
  220. {
  221. outOrderStr = kvp.Value;
  222. }
  223. else
  224. {
  225. outOrderStr += "," + kvp.Value;
  226. }
  227. }
  228. return outOrderStr;
  229. }
  230. /// <summary>
  231. /// 生成新的查询语句
  232. /// </summary>
  233. /// <param name="orgSelectStr">原始查询语名,select...from...</param>
  234. /// <param name="preOutFieldStr">输出字段</param>
  235. /// <param name="orgWhereStr">条件语句</param>
  236. /// <param name="preOrderStr">排序语句</param>
  237. /// <param name="pageindex">页数</param>
  238. /// <param name="pagesize">每页项数</param>
  239. /// <returns>新的查询语句</returns>
  240. public static string BuildSelectStr(string orgSelectStr, ref string preOutFieldStr, string orgWhereStr,
  241. string preOrderStr, int pageindex, int pagesize)
  242. {
  243. var parts = SpliteSelectStr(orgSelectStr);
  244. var orgFieldStr = parts[0];
  245. var orgFromStr = parts[1];
  246. var distinctStr = parts[2];
  247. Dictionary<string, string> orgFields = new Dictionary<string, string>();
  248. Dictionary<string, string> orgOrderFields = new Dictionary<string, string>();
  249. AnalyseFields(orgFieldStr, orgFields, orgOrderFields);
  250. string outFieldStr = BuildSelectFields(orgFields, ref preOutFieldStr, preOrderStr);
  251. string outOrderStr = BuildOrderFields(orgOrderFields, preOrderStr);
  252. var outCmdStr = outFieldStr + " FROM " + orgFromStr;
  253. if (!string.IsNullOrEmpty(orgWhereStr))
  254. {
  255. outCmdStr += " WHERE " + orgWhereStr;
  256. }
  257. if (!string.IsNullOrEmpty(outOrderStr))
  258. {
  259. outCmdStr += " ORDER BY " + outOrderStr;
  260. }
  261. if (pageindex > 0 && pagesize > 0)
  262. {
  263. outCmdStr = "SELECT " + distinctStr + " TOP " + (pageindex * pagesize).ToString() + " " + outCmdStr;
  264. outCmdStr = "SELECT RowNumber = IDENTITY(INT,1, 1)," + preOutFieldStr + " INTO #tmp_sorttable FROM (" +
  265. outCmdStr + @") a
  266. SELECT TOP " + pagesize.ToString() + " " + preOutFieldStr + @" FROM #tmp_sorttable WHERE RowNumber > " +
  267. (pagesize * (pageindex - 1)).ToString() + @" ORDER BY RowNumber
  268. DROP TABLE #tmp_sorttable";
  269. }
  270. else if (pageindex <= 0 && pagesize > 0)
  271. {
  272. outCmdStr = "SELECT " + distinctStr + " TOP " + pagesize + " " + outCmdStr;
  273. }
  274. else
  275. {
  276. outCmdStr = "SELECT " + distinctStr + " " + outCmdStr;
  277. }
  278. return outCmdStr;
  279. }
  280. public static string RemoveComment(string source)
  281. {
  282. var sb = new StringBuilder();
  283. using (StringReader reader = new StringReader(source))
  284. {
  285. string line;
  286. while ((line = reader.ReadLine()) != null)
  287. {
  288. if (line.Contains("--"))
  289. {
  290. int commentstart = -1;
  291. var instr = false;
  292. for (var i = 0; i < line.Length; i++)
  293. {
  294. var curchar = line[i];
  295. if (curchar == '\'')
  296. {
  297. instr = !instr;
  298. }
  299. else if (!instr)
  300. {
  301. if (curchar == '-')
  302. {
  303. if (i + 1 < line.Length)
  304. {
  305. if (line[i + 1] == '-')
  306. {
  307. commentstart = i;
  308. break;
  309. }
  310. }
  311. }
  312. }
  313. }
  314. if (commentstart >= 0)
  315. {
  316. line = line.Substring(0, commentstart);
  317. }
  318. }
  319. sb.AppendLine(line);
  320. }
  321. }
  322. return sb.ToString().TrimEnd('\n').TrimEnd('\r');
  323. }
  324. public static ParseResult ParseSelectStr(string orgSelectStr)
  325. {
  326. var rslt = new ParseResult();
  327. orgSelectStr = RemoveComment(orgSelectStr);
  328. var indexchars = GetIndexChar(orgSelectStr);
  329. var regex = new Regex(@"\bselect\s+(distinct\s+)?(top\b)?", RegexOptions.IgnoreCase | RegexOptions.Singleline);
  330. #region 查找select关键字
  331. var selectMatch = regex.Match(orgSelectStr);
  332. if (!selectMatch.Success)
  333. {
  334. throw new Exception(string.Format("查找select关键字失败,表达式[{0}],请检查:{1}", regex, orgSelectStr));
  335. }
  336. var stateIndex = indexchars.Keys.GetFirstIndexBefore(selectMatch.Index);
  337. if (stateIndex >= 0)
  338. {
  339. throw new Exception(string.Format("第{0}个字符的select关键字前面不允许存在括号或字符串,表达式[{1}],请检查:{2}", selectMatch.Index, regex,
  340. orgSelectStr));
  341. }
  342. if (!string.IsNullOrEmpty(selectMatch.Groups[2].Value))
  343. {
  344. throw new Exception(string.Format("第{0}位,不应该包含TOP关键字,请使用分页参数,请检查:{1}", selectMatch.Groups[2].Index,
  345. orgSelectStr));
  346. }
  347. rslt.selectStr = orgSelectStr.Substring(0, selectMatch.Index + selectMatch.Length);
  348. #endregion
  349. regex = new Regex(@"\bfrom\b", RegexOptions.IgnoreCase | RegexOptions.Singleline);
  350. #region 查找from关键字
  351. var match = regex.Match(orgSelectStr);
  352. int fromIndex = -1;
  353. while (match.Success)
  354. {
  355. stateIndex = indexchars.Keys.GetFirstIndexBefore(match.Index);
  356. if (stateIndex < 0 || indexchars.Values[stateIndex] == ' ')
  357. {
  358. fromIndex = match.Index;
  359. break;
  360. }
  361. match = match.NextMatch();
  362. }
  363. if (fromIndex < 0)
  364. {
  365. throw new Exception(string.Format("最外层查找from字句失败,请检查:{0}", orgSelectStr));
  366. }
  367. #endregion
  368. #region 分析返回字段
  369. Dictionary<string, string> orgFields = new Dictionary<string, string>();
  370. Dictionary<string, string> orgOrderFields = new Dictionary<string, string>();
  371. var parts = SpliteSelectStr(orgSelectStr);
  372. var orgFieldStr = parts[0];
  373. AnalyseFields(orgFieldStr, orgFields, orgOrderFields);
  374. rslt.selectFieldsDic = orgFields;
  375. #endregion
  376. regex = new Regex(@"\where\b", RegexOptions.IgnoreCase | RegexOptions.Singleline);
  377. #region 查找where关键字
  378. int whereIndex = -1;
  379. match = regex.Match(orgSelectStr, fromIndex);
  380. while (match.Success)
  381. {
  382. stateIndex = indexchars.Keys.GetFirstIndexBefore(match.Index);
  383. if (stateIndex < 0 || indexchars.Values[stateIndex] == ' ')
  384. {
  385. whereIndex = match.Index;
  386. break;
  387. }
  388. match = match.NextMatch();
  389. }
  390. #endregion
  391. regex = new Regex(@"\bgroup\b", RegexOptions.IgnoreCase | RegexOptions.Singleline);
  392. #region 查找group关键字
  393. int groupIndex = -1;
  394. match = regex.Match(orgSelectStr, fromIndex);
  395. while (match.Success)
  396. {
  397. stateIndex = indexchars.Keys.GetFirstIndexBefore(match.Index);
  398. if (stateIndex < 0 || indexchars.Values[stateIndex] == ' ')
  399. {
  400. groupIndex = match.Index;
  401. break;
  402. }
  403. match = match.NextMatch();
  404. }
  405. #endregion
  406. regex = new Regex(@"\border\b", RegexOptions.IgnoreCase | RegexOptions.Singleline);
  407. #region 查找order关键字
  408. int orderindex = -1;
  409. match = regex.Match(orgSelectStr, fromIndex);
  410. while (match.Success)
  411. {
  412. stateIndex = indexchars.Keys.GetFirstIndexBefore(match.Index);
  413. if (stateIndex < 0 || indexchars.Values[stateIndex] == ' ')
  414. {
  415. orderindex = match.Index;
  416. break;
  417. }
  418. match = match.NextMatch();
  419. }
  420. #endregion
  421. rslt.fromStr = string.Empty;
  422. var fromStopIndexs = new List<int> { whereIndex, groupIndex, orderindex }.Where(x => x > 0);
  423. if (fromStopIndexs.Any())
  424. {
  425. rslt.fromStr = orgSelectStr.Substring(fromIndex, fromStopIndexs.Min() - fromIndex);
  426. }
  427. else
  428. {
  429. rslt.fromStr = orgSelectStr.Substring(fromIndex);
  430. }
  431. rslt.whereStr = string.Empty;
  432. if (whereIndex > 0)
  433. {
  434. var whereStopIndexs = new List<int> { groupIndex, orderindex }.Where(x => x > 0);
  435. if (whereStopIndexs.Any())
  436. {
  437. rslt.whereStr = orgSelectStr.Substring(whereIndex, whereStopIndexs.Min() - whereIndex);
  438. }
  439. else
  440. {
  441. rslt.whereStr = orgSelectStr.Substring(whereIndex);
  442. }
  443. }
  444. rslt.orderStr = string.Empty;
  445. if (orderindex > 0)
  446. {
  447. rslt.orderStr = orgSelectStr.Substring(orderindex);
  448. }
  449. rslt.groupStr = string.Empty;
  450. if (groupIndex > 0)
  451. {
  452. if (orderindex > 0)
  453. {
  454. rslt.groupStr = orgSelectStr.Substring(groupIndex, orderindex - groupIndex);
  455. }
  456. else
  457. {
  458. rslt.groupStr = orgSelectStr.Substring(groupIndex);
  459. }
  460. }
  461. return rslt;
  462. }
  463. /// <summary>
  464. /// 获取SQL中括号与字符串的转换位置
  465. /// </summary>
  466. /// <param name="sqlStr"></param>
  467. /// <returns></returns>
  468. public static SortedList<int, char> GetIndexChar(string sqlStr)
  469. {
  470. var rslt = new SortedList<int, char>();
  471. Stack<char> states = new Stack<char>();
  472. char curstate = ' ';
  473. for (int i = 0; i < sqlStr.Length; i++)
  474. {
  475. char cur = sqlStr[i];
  476. if (curstate == '\'')
  477. {
  478. if (cur == '\'')
  479. {
  480. states.Pop();
  481. curstate = states.Count > 0 ? states.Peek() : ' ';
  482. rslt[i] = curstate;
  483. }
  484. continue;
  485. }
  486. if (curstate == '(')
  487. {
  488. if (cur == ')')
  489. {
  490. states.Pop();
  491. curstate = states.Count > 0 ? states.Peek() : ' ';
  492. rslt[i] = curstate;
  493. continue;
  494. }
  495. }
  496. if (curstate == '[')
  497. {
  498. if (cur == ']')
  499. {
  500. states.Pop();
  501. curstate = states.Count > 0 ? states.Peek() : ' ';
  502. rslt[i] = curstate;
  503. continue;
  504. }
  505. }
  506. if (cur == '(' || cur == '\'' || cur == '[')
  507. {
  508. states.Push(cur);
  509. curstate = cur;
  510. rslt[i] = curstate;
  511. continue;
  512. }
  513. if (cur == ')')
  514. {
  515. throw new Exception(string.Format("第{0}位\")\"没有找到对应的\"(\",请检查:{1}", i, sqlStr));
  516. }
  517. if (cur == ']')
  518. {
  519. throw new Exception(string.Format("第{0}位\"]\"没有找到对应的\"[\",请检查:{1}", i, sqlStr));
  520. }
  521. }
  522. if (states.Count > 0)
  523. {
  524. throw new Exception(string.Format("第{0}位\"{1}\"没有找到对应的结束符,请检查:{2}", rslt.Keys[rslt.Count - 1], rslt.Values[rslt.Count - 1], sqlStr));
  525. }
  526. return rslt;
  527. }
  528. public class ParseResult
  529. {
  530. public string selectStr { get; set; }
  531. //public List<string> selectFields { get; set; }
  532. //public List<string> selectTitles { get; set; }
  533. public Dictionary<string, string> selectFieldsDic { get; set; }
  534. public string fromStr { get; set; }
  535. public string whereStr { get; set; }
  536. public string groupStr { get; set; }
  537. public string orderStr { get; set; }
  538. }
  539. }
  540. }