将SQL语句从LIMIT转换为TOP C#

时间:2016-04-15 21:59:11

标签: c# sql-server database sqlite sql-server-2012

我正在开发一个使用SQLite数据库实现的应用程序。我目前正在添加使用MSSQL的能力。复杂的部分是它需要能够根据需要使用任何一种引擎。必须考虑少数不同的语法差异。我遇到的最大问题是LIMIT vs TOP。我已经编写了一些逻辑来将SQLite语句转换为适当的MSSQL格式。我将LIMIT转换为TOP的功能似乎正在起作用,但最终变得非常难看。我想在这里发布它,看看是否有人想要一个更简洁的方法来完成这个。我还想看看是否有人注意到我错过了任何明显的问题。我遇到的最大问题是嵌套的select语句也可能带有LIMIT语句。我最后将声明分成了各个部分,将它们从LIMIT更改为TOP,然后重建声明。甚至可能有一种总体上更好的方法来做到这一点,我错过了。如果您花时间看一下,请提前感谢。

private static string ConvertLimitToTop(string commandText)
{
    string processCommand = commandText;
    int start = -1;
    List<string> commandParts = new List<string>();

    //Running through the string looking for nested statemets starting with (
    for (int i = 0; i < processCommand.Length; i++)
    {
        //Any time we find a new open ( we want to start there
        if (processCommand[i] == '(')
            start = i;

        //If we find a close ) we will grab the nested statment and replace it
        if (processCommand[i] == ')')
        {
            //Grab the 3 parts of the string
            string preString = processCommand.Substring(0, start);
            string nestedCommand = processCommand.Substring(start, i - start + 1);
            string postString = processCommand.Substring(i + 1);

            //Add the nested command to the list
            commandParts.Add(nestedCommand);

            //Update the commandText replacing the nested command we removed with its index in the list
            processCommand = preString + "{" + (commandParts.Count - 1) + "}" + postString;

            //Go back the the beginning of the command and look for the next nested command
            i = 0;
            start = -1;
        }
    }
    //If start isnt -1 that means we found an open ( without a closing )
    if (start == -1)
    {
        //We want to add the final command the the list for processing too
        commandParts.Add(processCommand);

        //We're going to go through the command parts and replace the LIMIT
        for (int i = 0; i < commandParts.Count; i++)
        {
            string command = commandParts[i];
            Console.WriteLine(command);
            //We need to find the where the LIMIT is and extact the number
            int limitIndex = command.IndexOf("LIMIT");
            if (limitIndex != -1)
            {
                int startIndex = limitIndex + 6;
                //Assuming after the limit will be ), a space, or the end of the string
                int endIndex = command.IndexOf(')', startIndex);
                if (endIndex == -1)
                    endIndex = command.IndexOf(' ', startIndex);
                if (endIndex == -1)
                    endIndex = command.Length - 1;

                Console.WriteLine(startIndex);
                Console.WriteLine(endIndex);
                //Extract the number
                string limitNumber = command.Substring(startIndex, endIndex - startIndex);
                //Remove the LIMIT command. There should always be a space before so take that out too.
                command = command.Remove(limitIndex - 1, endIndex - limitIndex + 1);
                //Insert the top command with the number
                command = command.Replace("SELECT", "SELECT TOP " + limitNumber);
                //Update the list
                commandParts[i] = command;
            }
        }

        start = -1;
        //We need to go through the commands in reverse order and reassemble the complete command
        for (int i = 0; i < processCommand.Length; i++)
        {
            //If we find a { its a part of the command that needs to be replaced
            if (processCommand[i] == '{')
                start = i;
            if (processCommand[i] == '}')
            {
                string startString = processCommand.Substring(0, start);
                string midString = processCommand.Substring(start, i - start + 1);
                string endString = processCommand.Substring(i + 1);
                //Get the index of the command we need from the list
                int strIndex = Int32.Parse(midString.Substring(1, midString.Length - 2));

                processCommand = processCommand.Replace(midString, commandParts[strIndex]);

                //Go back to the start and look for the next
                i = 0;
                start = -1;
            }
        }

        commandText = processCommand;
    }
    else
    {
        LogManager.Write(LogLevel.Error, "Unmatched parentheses were found while processing a SQL command. Command: " + commandText);
    }

    return commandText;
}

0 个答案:

没有答案