問題簡介:在工作中,表字段多到一定程度,Select 中的字段和結果集中的字段對比很麻煩,還容易出錯。於是寫了一個檢查Select和Insert的方法。(使用的是Scala語言)
1. 代碼如下
import scala.annotation.tailrec /** * 校驗SQL,現支持三種校驗 * select 查詢校驗:select語句與結果集比對 * insert into select 查詢插入校驗:查詢語句與插入語句 * insert into 插入校驗:insert字段與values中的值數量 * */ object TestSQL extends App { //select語句測試sql val selectStr = """ |select |name, |password, |hello2, |hello2, |hello2 | from | testTables | |rs.getString("name") |rs.getString("password") |rs.getString("hello") |rs.getString("hello") """.stripMargin //insert測試語句 val insertStr = """ |Insert |into |testTable |(name, |password, |hello2,,,) | values |(,,,,,) """.stripMargin //insert into select測試語句 val insertAndSelectSql = s""" |insert |into |testTable |(name, |password, |password, |hello) | values |select |name, |password, |hello2, |hello2, |hello3 | from | testTable2 """.stripMargin //測試方法 sqlTest(insertAndSelectSql) /** * 判斷字符串中關鍵字,匹配校驗語句 * * @param str 待判斷的字符串 */ def sqlTest(str: String): Unit = { //將字符串轉換成小寫 val strLower = str.toLowerCase judgeSQL(strLower) match { case (true, false) => selectTest(strLower) case (false, true) => insertTest(strLower) case (true, true) => insertAndSelectTest(strLower) case (_, _) => println("暫不支持該SQL") } } /** * 查詢語句和結果集字段校驗 * * @param selectStr 包含select語句和結果集的字符串 */ private def selectTest(selectStr: String): Unit = { //1.將select與from中的字段,放入鏈表中 val selectLists: List[String] = strToList(getSubString(selectStr, "select", "from", 6)) //2.獲取rs.get中所有的值 var rsLists: List[String] = List() rsLists = nextElement(selectStr, rsLists) //3.判斷select語句和結果集獲取的值中的參數是否重復 judgeIsEquals(selectLists, "select") judgeIsEquals(rsLists, "result") //4.判斷select中列的數量和結果集是否相等 judgeFieldsNums(selectLists.size, rsLists.size, "select") //5.比較select語句和結果集獲取的值中的參數是否相等 judgeFields(selectLists, rsLists, "select") } /** * insert into select 語句校驗 * * @param insertAndSelectStr 查詢插入語句字符串 */ private def insertAndSelectTest(insertAndSelectStr: String): Unit = { //1.將select與from中的字段,並計算數量 //1.1截取select和from中的子字符串 val selectSubFront = getSubString(insertAndSelectStr, "select", "from", 6) //1.2將select和from中的列放入鏈表集合中 val selectLists: List[String] = strToList(selectSubFront) //1.3.判斷select語句中的參數是否重復 judgeIsEquals(selectLists, "select") //2.截取insert和select中間的字符串,計算字段數量 //2.1截取insert和values中的子字符串 val insertSubFront = getSubString(insertAndSelectStr, "insert", "values", 0) //2.2再截取“()”內列的集合 val insertSubFrontList = strToList(getSubString(insertSubFront, "(", ")", 1)) //2.3判斷insert語句中字段是否有重復 judgeIsEquals(insertSubFrontList, "insert") //3.判斷insert和select中列的數量是否相等 judgeFieldsNums(selectLists.size, insertSubFrontList.size, "insertAndSelect") //4.判斷insert語句中的字段與select中是否相等 judgeFields(selectLists, insertSubFrontList, "insertAndSelect") } /** * 插入SQL校驗 * * @param insertStr 插入語句sql */ private def insertTest(insertStr: String): Unit = { //1.獲取insert和values之間的字符串 val insertSubFront = getSubString(insertStr, "insert", "values", 0) val insertSubFrontNums = countNumbers(insertSubFront) //2.獲取values之后的字符串 val insertSubBack = insertStr.substring(insertStr.indexOf("values")) val insertSubBackNums = countNumbers(insertSubBack) //3.判斷兩個字符串中的','數量差值 judgeFieldsNums(insertSubFrontNums, insertSubBackNums, "insert") } /** * 獲取結果集中字段組成的鏈表集合 * * @param string 包含select和結果集的字符串 * @param list 空list集合 * @return 返回結果集中字段組成的鏈表集合 */ @tailrec private def nextElement(string: String, list: List[String]): List[String] = { val rightIndex = string.indexOf("\")") val leftIndex = string.indexOf("(\"") + 2 val lists = list.::(string.substring(leftIndex, rightIndex)) val subString = string.substring(rightIndex + 2) if ( string.lastIndexOf("\")").hashCode() == rightIndex.hashCode() ) { lists } else { nextElement(subString, lists) } } /** * 計算“,”的數量 * * @param strs 待計算的字符串 * @return “,”的數量 */ private def countNumbers(strs: String): Integer = { //計算包含','字符的數量 var count: Integer = 0 strs.foreach { str => if ( str == ',' ) { count = count + 1 } } count } /** * 判斷是否是包含SQL關鍵字 * * @param str 待校驗的字符串 * @return */ private def judgeSQL(str: String): (Boolean, Boolean) = { //是否有insert關鍵字 val isHasInsert = str.contains("insert") //是否有select關鍵字 val isHasSelect = str.contains("select") (isHasSelect, isHasInsert) } /** * 獲取子字符串 * * @param parString 父字符串 * @param firstString sql語句第一個關鍵字 * @param secoundString sql語句第二個關鍵字 * @param shift 下標位移距離 * @return 字符串 */ private def getSubString(parString: String, firstString: String, secoundString: String, shift: Integer): String = { parString.substring(parString.indexOf(firstString) + shift, parString.indexOf(secoundString)) } /** * 將字符串轉換為List集合 * * @param strToListString 將被轉換為集合的字符串 * @return String類型的集合 */ private def strToList(strToListString: String): List[String] = { strToListString.replace("\r\n", "").trim.split(",").toList } /** * List集合驗重 * * @param list 將被校驗的list * @param typeString 涉及SQL語句類型 */ private def judgeIsEquals(list: List[String], typeString: String): Unit = { val tmpListResult: Boolean = list.distinct.size != list.size typeString.toUpperCase() match { case "SELECT" => if ( tmpListResult ) println("查詢語句有重復值") case "INSERT" => if ( tmpListResult ) println("插入語句有重復值") case "RESULT" => if ( tmpListResult ) println("結果集有重復值") case _ => println("暫不支持該SQL語句驗重") } } /** * 比較SQL中字段數量 * * @param firstNum 第一個需要比較字段的數量 * @param secoundNum 第二個需要比較字段的數量 * @param typeString SQL類型 */ private def judgeFieldsNums(firstNum: Integer, secoundNum: Integer, typeString: String): Unit = { var delNums = firstNum - secoundNum val delNumsCompare = firstNum.compareTo(secoundNum) (typeString.toUpperCase(), delNumsCompare) match { case ("SELECT", -1) => delNums = -delNums println(s"結果集 多了[$delNums]個數據") case ("SELECT", 1) => println(s"SELECT 多了[$delNums]個數據") case ("SELECT", 0) => println(s"SELECT語句與結果集中字段數量相等") case ("INSERT", -1) => delNums = -delNums println(s"VALUES 多了[$delNums]個數據") case ("INSERT", 1) => println(s"INSERT 多了[$delNums]個數據") case ("INSERT", 0) => println(s"INSERT語句中字段字段數量相等") case ("INSERTANDSELECT", -1) => delNums = -delNums println(s"INSERT 多了[$delNums]個數據") case ("INSERTANDSELECT", 1) => println(s"SELECT 多了[$delNums]個數據") case ("INSERTANDSELECT", 0) => println(s"INSERT語句和SELCECT語句中字段數量相等") case _ => println("暫不支持該SQL語句比較字段數量") } } /** * 判斷字段是否相等 * * @param firstList 第一個待比較集合 * @param secoundList 第二個待比較集合 * @param typeString SQL類型 */ private def judgeFields(firstList: List[String], secoundList: List[String], typeString: String): Unit = { val selectSurplus = firstList.toSet -- secoundList.toSet val insertSubFrontSurplus = secoundList.toSet -- firstList.toSet typeString.toUpperCase() match { case "SELECT" => if ( selectSurplus.nonEmpty ) { println("select語句中比結果集多的字段有" + selectSurplus) } if ( insertSubFrontSurplus.nonEmpty ) { println("結果集中比select語句多的字段有" + insertSubFrontSurplus) } if ( selectSurplus.isEmpty && insertSubFrontSurplus.isEmpty ) { println("select語句中與結果集字段相同") } case "INSERTANDSELECT" => if ( selectSurplus.nonEmpty ) { println("select語句中比insert多的字段有" + selectSurplus) } if ( insertSubFrontSurplus.nonEmpty ) { println("insert語句中比select多的字段有" + insertSubFrontSurplus) } if ( selectSurplus.isEmpty && insertSubFrontSurplus.isEmpty ) { println("insert語句中與select語句中的字段相同") } } } }
2. 支持的校驗類型:現支持三種校驗
(1).select 查詢校驗:select語句與結果集比對
(2).insert into select 查詢插入校驗:查詢語句與插入語句
(3).insert into 插入校驗:insert字段與values中的值數量