SQL校驗方法


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM