2015-04-25 76 views
2

如果我有一個名爲File.txt的文本文件,其中包含一些數據。例如:如何解析Java中的SQL查詢?

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"); 
} 

但我這裏迷路...我不知道如何解析查詢。我的程序設法讀取這兩個文件,但是當處理輸入文件中的查詢時,我似乎無法弄清楚它的邏輯。

+3

所以你基本上必須做一個簡潔的SQL解釋器? Tokenize,定義語法,構建表達式樹,然後評估。基本上是編程語言的所有步驟。祝你好運。 – ryanyuyu

+0

是的,這基本上就是我想要做的。 – TRX

+0

這是一些功課嗎?只是好奇你爲什麼需要這樣的功能。解釋sql查詢的方式與解釋任何語言的方法相同,你必須構建一個sql [解釋器](http://en.wikipedia.org/wiki/Interpreter_%28computing%29)看一看在此鏈接查看口譯員是什麼。我與@ryanyuyu祝你好運,你需要。 –

回答

0

您正在尋找CSV文件的SQL JDBC驅動程序。如果您可以自由地將分隔符從空格改爲逗號,我會爲此使用一個庫。以下代碼將與CsvJdbc一起使用。代碼是開源的,所以你可以看看並實施,如果有什麼不對,但至少你不必從頭開始。我沒有找到一個徹底的方式來改變分隔符,我象下面這樣的文件進行測試:

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

代碼(下載csvjdbc-1.0-23.jar,並把你的classpath):

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 
0

首先,我建議代表您的數據作爲行的集合。這就是數據庫管理系統處理數據的方式,它會使其他邏輯更容易。您可以創建自己的對象類型來存儲c1c2的值。循環訪問數據文件並創建此行集合(可能爲list<row>

現在要「解析」SQL。您需要標記SQL以獲得稍後用於邏輯的實際部分。只需使用內置的Java字符串拆分函數來獲取查詢的實際子句。

我喜歡首先想到獲取特定行(由Where條款決定)。那麼你可以擔心從select返回的每一行的實際數據。

我假設From子句不會改變,因爲你只有一個數據文件。但是如果是這樣的話,你會使用這個子句來做一些事情,比如選擇實際的數據源(文件名可能是?)

對於任何沒有Where子句的SQL,你所有的行都是有效的,你可以返回整個集合的行。否則,您需要弄清楚如何將where子句後的文本轉換爲Java可解釋的謂詞(您可能需要單獨搜索此部分,因爲這是一個完全獨立的問題,並且不在我的答案範圍之內)。然後,您只需遍歷數據行並返回傳遞謂詞的每一行。

Select語句確定要包含哪些列。使用像string.contains這樣的邏輯來檢查包含哪些列名稱。 A *應選擇所有列。由於您已經擁有有效行的集合,只需遍歷它們並從每行獲取實際需要的所有數據即可。例如,您可以將所有有效數據(由string.contains確定)連接成一個由一個新行字符終止的長字符串。

這應該適合你的要求。對不起,不包括任何實際的代碼,但這個大綱應該幫助。

+0

我還不能投票,但我真的謝謝你的提綱。我會盡我所能,看看我能做些什麼。我再一次感謝你的全力幫助。 – TRX

+0

@TRX樂意幫忙。祝你好運。 – ryanyuyu