如何用Java解析SQL查询?

时间:2015-04-25 02:51:58

标签: java sql string parsing

如果我有一个名为File.txt的文本文件,其中包含一些数据。例如:

55 90 
10 45
33 23
10 500
5  2

第一列称为列C1,第二列称为C2

然后我有另一个名为Input.txt的文件,其中包含两个SQL查询:

SELECT *
FROM File 
WHERE C2 > 60; 

SELECT C1 
FROM File;

解析此文件并生成类似于从真实DBMS获取的输入的一种方法是什么?

到目前为止我已尝试过这个:

// 1. Read the file.  
Main obj = new Main();
URL url = obj.getClass().getResource("File.txt");
File file = new File(url.toURI());
FileReader fileReader = new FileReader(file);
BufferedReader bufferReader = new BufferedReader(fileReader);
StringBuffer stringBuffer = new StringBuffer();
String line;
while ((line = bufferReader.readLine()) != null) {
    stringBuffer.append(line);
    stringBuffer.append("\n");
}
fileReader.close();
String data = stringBuffer.toString(); //this contains the data from File.text
String[] list = data.split(" "); //this stores it into a list

// 2. Read the input file. 
Main input = new Main();
URL urlInput = input.getClass().getResource("Input.txt");
File inputFile = new File(urlInput.toURI());
FileReader fileReaderInput = new FileReader(inputFile);
BufferedReader bufferedReaderInput = new BufferedReader(fileReaderInput);
StringBuffer stringBufferInput = new StringBuffer();
String lineInput;
while ((lineInput = bufferedReaderInput.readLine()) != null) {
    stringBufferInput.append(lineInput);
    stringBufferInput.append("\n");
} 

但我迷失在这里......我不知道如何解析查询。我的程序设法读取这两个文件,但是当在输入文件中处理查询时,我似乎无法弄清楚它的逻辑。

2 个答案:

答案 0 :(得分:0)

您正在寻找CSV文件的SQL JDBC驱动程序。如果您可以自由地将分隔符更改为空格中的逗号,我会使用库来实现此目的。以下代码适用于CsvJdbc。代码是开源的,所以你可以看看并实现一些不对的东西,但至少你不必从头开始。我没有找到更改分隔符的直接方法,我测试了如下文件:

C1,C2
55,90
10,45
33,23
10,500
5,2

代码(下载csvjdbc-1.0-23.jar并放入类路径):

public static void main(String[] args)
{
    try
    {
        // Load the driver.
        Class.forName("org.relique.jdbc.csv.CsvDriver");

        Properties props = new Properties();
        props.put("headerline", "C1,C2");
        props.put("columnTypes", "Int,Int");
        Connection conn = DriverManager.getConnection("jdbc:relique:csv:" + "/home/vinodshukla/tmp", props);

        // Create a Statement object to execute the query with.
        // A Statement is not thread-safe.
        Statement stmt = conn.createStatement();

        // Select the ID and NAME columns from sample.csv
        ResultSet results = stmt.executeQuery("SELECT C1,C2 FROM sample where C2 > 60");
        // Dump out the results to a CSV file with the same format
        // using CsvJdbc helper function
        boolean append = true;
        CsvDriver.writeToCsv(results, System.out, append);

        System.out.println("------------");
        results = stmt.executeQuery("SELECT C1 FROM sample");
        // Dump out the results to a CSV file with the same format
        // using CsvJdbc helper function
        append = true;
        CsvDriver.writeToCsv(results, System.out, append);

        // Clean up
        conn.close();
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}

输出:

C1,C2
10,500
------------
C1
55
10
33
10
5

答案 1 :(得分:0)

首先,我建议将您的数据表示为行集合。这就是DBMS如何处理数据,它将使其他逻辑更容易。您可以创建自己的对象类型来存储c1c2的值。循环遍历数据文件并创建此行集合(可能是list<row>

现在要“解析”SQL。您需要将SQL标记化以获取稍后将用于逻辑的实际部分。只需使用内置的Java字符串拆分函数来获取查询的实际子句。

我想首先考虑获取特定行(由Where子句确定)。然后,您可以担心从select返回的每行的实际数据。

我假设From子句不会改变,因为你只有一个数据文件。但是,如果它确实你使用这个子句来做一些像选择实际数据源(文件名可能?)

对于没有Where子句的任何SQL,所有行都有效,您可以返回整个行集合。否则,您需要弄清楚如何将where子句之后的文本转换为Java可解释谓词(您可能希望单独搜索此部分,因为它是一个完全独立的问题,超出了我的答案范围)。然后,您只需遍历数据行并返回传递谓词的每一行。

Select语句确定要包含哪些列。使用string.contains之类的逻辑来检查包含哪些列名。 *应选择所有列。由于您已经拥有有效行的集合,因此只需遍历它们并从每行获取实际需要的所有数据。例如,您可以将所有有效数据(由string.contains确定)连接成由新行字符终止的长字符串。

这应该适合你的要求。很抱歉不包含任何实际代码,但此大纲应该有所帮助。