問題簡介:在工作中,表字段多到一定程度,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中的值數量
