【问题标题】:How to parse an SQL query in Java?如何在 Java 中解析 SQL 查询?
【发布时间】:2015-07-03 19:45:03
【问题描述】:

如果我有一个名为 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");
} 

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

【问题讨论】:

  • 所以你基本上必须制作一个精简的sql解释器?标记,定义语法,构建表达式树,然后评估。基本上是制作编程语言的所有步骤。祝你好运。
  • 是的,这基本上就是我想要做的。
  • 这是作业吗?只是好奇你为什么需要这样的功能。解释 sql 查询的方式与解释任何语言的方式相同,您必须构建一个 sql interpreter 看看这个链接以了解解释器是什么。我和@ryanyuyu 一起祝你好运,你需要。
  • 您只需要处理 Select、From、Where 关键字吗?如果是这样,那就简化了很多。
  • 是的,只有 Select、From 和 Where。但我不知道该怎么做。我只需要查看它的工作示例代码,我相信我可以自己解决剩下的问题。这只是更大计划的一部分。

标签: java sql string parsing


【解决方案1】:

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

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

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

我假设From 子句不会更改,因为您只有一个数据文件。但如果是这样,你会使用这个子句来做一些事情,比如选择实际的数据源(可能是文件名?)

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

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

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

【讨论】:

  • 我还不能投票,但我真的很感谢你的这个大纲。我会尽我所能,看看我能做些什么。再次衷心感谢您的帮助。
  • @TRX 很乐意为您提供帮助。祝你好运。
【解决方案2】:

您正在寻找适用于 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2013-03-26
    • 2012-06-14
    • 2010-09-06
    • 1970-01-01
    • 1970-01-01
    • 2016-04-09
    相关资源
    最近更新 更多