【问题标题】:Splitting a WHERE sql clause into array将 WHERE sql 子句拆分为数组
【发布时间】:2013-07-13 00:21:45
【问题描述】:

我正在尝试将作为 SQL 语句的 WHERE 子句的字符串拆分为具有 5 个输出的数组,其中每个索引下保存以下数据:

0 - The initial clauses (WHERE/AND/OR) plus any open brackets. e.g "AND((("
1 - Either the table the first clause comes from or "VALUE" if its a value. e.g. "transactions". 
2 - The field name or value. e.g. "id"
3 - The joining value. e.g. >
4 - Either the table the second clause comes from or "VALUE" if its a value. e.g. "transactions". 
5 - The field name or value. e.g. "id"
6 - Any closing brackets. e.g. ")))"

例如,通过以下字符串循环将输出以下数组:

WHERE transactions.status_code= 'AFA 2'
AND (transactions.supp_ref = supplier.supp_ref
AND supplier.supp_addr_ref = address.addr_ref)
OR transactions.user_code = user.user_code

output[0] = "WHERE"
output[1] = "transactions"
output[2] = "status_code"
output[3] = "="
output[4] = "VALUE'
output[5] = "AFA 2"
output[6] = ""

output[0] = "AND("
output[1] = "transactions"
output[2] = "supp_ref"
output[3] = "="
output[4] = "supplier"
output[5] = "supp_ref"
output[6] = ""

output[0] = "AND"
output[1] = "supplier"
output[2] = "supp_addr_ref"
output[3] = "="
output[4] = "address"
output[5] = "addr_ref"
output[6] = ")"

output[0] = "OR"
output[1] = "transactions"
output[2] = "user_code"
output[3] = "="
output[4] = "user"
output[5] = "user_code"
output[6] = ""

对于 SQL 语句的其余部分,我已使用 String.Split 方法以类似的方式成功地将其拆分,但是由于 where 子句的差异,我在这部分执行此操作时遇到了困难。从环顾四周,我认为我会更好地使用正则表达式,但无法弄清楚需要什么。任何帮助或指导将不胜感激。

【问题讨论】:

  • 你到底为什么要做这样的事情?
  • 虽然我无法回答您的问题,但为什么您需要解析 SQL?这不是一项微不足道的任务。您要解决什么潜在问题,您将如何处理标记化 SQL?
  • BETWEEN、IN 或一些子查询有什么?
  • 我不需要支持子查询。我同意这似乎是一项疯狂的任务,但是我使用的系统将 SQL 查询存储在数据库中的不同列中 - 这样“新手”用户就可以使用 GUI 前端创建 SQL 查询。不幸的是,我无法更改此系统 - 因此需要拆分查询。
  • 在 SQL 基础知识方面培训你的新手比通过这个游戏要便宜。如果您有前端,那么为什么需要解析 SQL?你在这里是一个失败者。从技术方面实际解决此问题的唯一正确方法是编写或获取 SQL 解析器,但我认为您的前提是有缺陷的。

标签: c# regex arrays split


【解决方案1】:

好的,所以首先我认为正则表达式可能不适合您尝试做的事情。话虽这么说,这是一个正则表达式,它将解析您发布的内容并将其转换为您要查找的内容:

(?<Group>(?<Concat>where|\s*?\)?\s*?and\s*?\(?|\s*?\)?\s*?or\s*?\(?)(?<TableName>[\w\s]+(?=\.))\.?(?<ColName>.+?(?=\=|like|between|\<\>|\>\=|\<\=|in|\>|\<))\s*?(?<Compare>\=|like|between|\<\>|\>\=|\<\=|in|\>|\<)(?<Value>.*?(?=\s*?and\s*?\(*|or\*?\(*)|.*))

我确信这并不能涵盖所有内容,并且根据正则表达式解析器的不同,这可能会有所不同。我将The Regulator 用于我的正则表达式工作。

我建议编写一个解析器来执行此操作。看看我下面的内容,如果你决定走这条路,它可能会有所帮助。我不完全确定您对那里的“VALUE”字符串做了什么,但如果您想确定什么是值以及什么是 table.colName,您可以轻松地将其添加到其中。识别('a','b')之类的东西会更难,但我认为这是可行的。

    //A list of chars that we are going to replace with \s"char"\s this list may not be complete.
    // . is not in here. We will take care of that later.
    static string[] specChars = new string[] { "<", ">", "<=", ">=", "=", "like", "in", "between", "or", "and", "(", ")", "where" };
    static string[] delims = new string[] {"and", "or", "where" };
    static string testData = @"WHERE transactions.status_code= 'AFA 2'
    AND (transactions.supp_ref = supplier.supp_ref
    AND supplier.supp_addr_ref = address.addr_ref)
    OR transactions.user_code = user.user_code";
    static void Main(string[] args)
    {
        Print(Parse(testData));
        Console.ReadKey();
    }

    static List<List<string>> Parse(string input)
    {
        List<List<string>> ret = new List<List<string>>();
        //lets remove all the spaces first becaue we are going to put them back
        //the way we want to see them.
        input = input.Replace(" ", "").Replace("\r", "").Replace("\n", "").ToLower();
        foreach (string item in specChars)
        {
            //this will help clean the string so you can use it
            input = input.Replace(item, string.Format(" {0} ", item));   
        }
        string[] splits = input.Split(' ');

        List<string> currList = null;
        foreach (string item in splits.Where(x => x.Length > 0))
        {
            if (delims.Contains(item))
            {
                if (currList != null)
                {
                    ret.Add(currList);
                    currList = new List<string>();
                    currList.Add(item);
                }
                else
                {
                    currList = new List<string>();
                    currList.Add(item);
                }
            }
            else
            {
                if (item.Contains("."))
                {
                    string[] tmp = item.Split('.');
                    currList.Add(tmp[0]);
                    currList.Add(tmp[1]);
                }
                else
                    currList.Add(item);
            }
        }
        if (currList != null)
            ret.Add(currList);
        return ret;
    }

    static void Print(List<List<String>> input)
    {
        StringBuilder sb = new StringBuilder();
        foreach (List<String> item in input)
        {
            sb.Append("New Chunk:\n");
            foreach (string str in item)
            {
                sb.Append(string.Format("\t{0}\n", str));
            }
            sb.Append("\n");
        }

        Console.WriteLine(sb.ToString());
    }
}

【讨论】:

    【解决方案2】:

    如果您要解析 SQL,您可能需要查看 ScriptDom 命名空间。它可能比您想要做的更多,但它有一些 SQL 解析器,可以为您提供有关给定 SQL 查询的详细信息。

    这里有一些资源。

    MSDN ScriptDOM reference
    An easier introduction

    【讨论】:

      猜你喜欢
      • 2015-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-07
      • 2011-08-07
      • 1970-01-01
      相关资源
      最近更新 更多