2008-11-11 34 views
6

Tôi không nóng ở những biểu thức thông thường và nó khiến tâm trí của tôi làm tan chảy một số thứ.Cụm từ thông dụng để tìm tất cả các tên bảng trong một truy vấn

Tôi đang cố gắng tìm tất cả các tên bảng trong truy vấn. Vì vậy, nói tôi có truy vấn:

SELECT one, two, three FROM table1, table2 WHERE X=Y 

Tôi muốn rút khỏi "table1, table2" hoặc "table1" và "table2"

Nhưng nếu không có là nơi tuyên bố. Nó có thể là kết thúc của tập tin, hoặc có thể là một nhóm bằng hoặc một đơn đặt hàng của vv Tôi biết "nhất" của thời gian này sẽ không phải là một vấn đề nhưng tôi không thích ý tưởng mã hóa cho "nhất" tình huống và biết rằng tôi đã để lại một lỗ hổng có thể khiến mọi thứ trở nên sai sau đó.

Đây có phải là biểu thức Regex có thể thực hiện được không? Tôi có phải là một pleb Regex không?

(P.S. điều này sẽ được thực hiện trong C# nhưng cho rằng điều đó không quan trọng nhiều).

+0

Regular expressions là thứ ít nhất các vấn đề của bạn.Chỉ cần liệt kê tất cả các cách mà một bảng có thể xuất hiện trong một câu lệnh SQL là một vấn đề phức tạp. BTW. Bạn không bao giờ đề cập đến hương vị của SQL bạn đang cố gắng phân tích cú pháp. – JohnFx

+0

Và vấn đề cơ bản mà anh ta đang cố gắng giải quyết là gì. –

+0

Tôi không nghĩ rằng cụm từ thông dụng là giải pháp đúng, bạn cần có trình phân tích cú pháp SQL thay vào đó, hãy xem bài viết này: http://www.dpriver.com/blog/list-of-demos-illustrate-how-to-use- chung-sql-parser/get-cột-và-bảng-in-sql-script-net-phiên bản/ –

Trả lời

13

RegEx không phải là rất tốt lúc này, vì nó là rất nhiều phức tạp hơn nó xuất hiện:

  • gì nếu họ sử dụng LEFT/RIGHT INNER/OUTER/CHÉO/MERGE/TỰ NHIÊN tham gia thay vì một , b cú pháp? Tuy nhiên, cú pháp a, b nên tránh.
  • Còn các truy vấn lồng nhau thì sao?
  • Điều gì sẽ xảy ra nếu không có bảng (chọn một hằng số)
  • Điều gì về ngắt dòng và định dạng khoảng trắng khác?
  • Tên bí danh?

Tôi có thể tiếp tục.

Những gì bạn có thể làm là tìm trình phân tích cú pháp sql và chạy truy vấn của bạn thông qua đó.

+0

Tôi nghĩ rằng kẻ giết người thỏa thuận thực sự sẽ là quan điểm. Sẽ không có cách nào thực tế để phân tích các tên bảng cơ bản của bất kỳ khung nhìn nào được bao gồm trong truy vấn. – JohnFx

1

Chắc chắn là không dễ dàng.

Xem xét truy vấn phụ.

select 
    * 
from 
    A 
    join (
    select 
     top 5 * 
    from 
     B) 
    on B.ID = A.ID 
where 
    A.ID in (
    select 
     ID 
    from 
     C 
    where C.DOB = A.DOB) 

Có ba bảng được sử dụng trong truy vấn này.

1

Tôi nghĩ rằng sẽ dễ dàng hơn để mã hóa chuỗi và tìm kiếm các từ khóa SQL có thể gắn các tên bảng. Bạn biết tên sẽ theo sau FROM, nhưng chúng có thể được theo sau bởi WHERE, GROUP BY, HAVING hoặc không có từ khóa nào nếu chúng ở cuối truy vấn.

4

Mọi thứ đều nói về tính hữu ích của một regex như vậy trong ngữ cảnh SQL. Nếu bạn nhấn mạnh vào một regex và câu lệnh SQL của bạn luôn trông giống như một bạn thấy (có nghĩa là không có truy vấn con, tham gia, và vân vân), bạn có thể sử dụng

FROM\s+([^ ,]+)(?:\s*,\s*([^ ,]+))*\s+ 
2

tôi tìm thấy trang web này mà có một phân tích cú pháp GREAT!

http://www.sqlparser.com/

cũng đáng giá. Làm việc một điều trị.

3

Tôi khá muộn với bữa tiệc tuy nhiên tôi nghĩ rằng tôi sẽ chia sẻ một regex tôi hiện đang sử dụng để phân tích tất cả các đối tượng cơ sở dữ liệu của chúng tôi và tôi không đồng ý với tình cảm rằng nó không thể làm điều này bằng cách sử dụng một.

Các regex có một vài giả định

1) Bạn không sử dụng A, B tham gia cú pháp phong cách

2) Dù phân tích cú pháp regex bạn đang sử dụng hỗ trợ bỏ qua trường hợp.

3) Bạn đang phân tích, chọn, tham gia, cập nhật, xóa và cắt bớt. Nó không hỗ trợ MERGE/NATURAL nói trên vì chúng tôi không sử dụng chúng, tuy nhiên tôi chắc chắn hỗ trợ thêm sẽ không khó thêm vào.

Tôi rất muốn biết loại giao dịch mà bảng là một phần của vì vậy tôi đã bao gồm các nhóm Capture có tên để cho tôi biết.

Bây giờ tôi đã không sử dụng regex trong một thời gian dài vì vậy có thể có những cải tiến có thể được thực hiện tuy nhiên cho đến nay trong tất cả các thử nghiệm của tôi điều này là chính xác.

\bjoin\s+(?<Retrieve>[a-zA-Z\._\d]+)\b|\bfrom\s+(?<Retrieve>[a-zA-Z\._\d]+)\b|\bupdate\s+(?<Update>[a-zA-Z\._\d]+)\b|\binsert\s+(?:\binto\b)?\s+(?<Insert>[a-zA-Z\._\d]+)\b|\btruncate\s+table\s+(?<Delete>[a-zA-Z\._\d]+)\b|\bdelete\s+(?:\bfrom\b)?\s+(?<Delete>[a-zA-Z\._\d]+)\b 
0

Xây dựng cụm từ thông dụng sẽ ít nhất là vấn đề của bạn. Tùy thuộc vào hương vị của SQL bạn mong muốn hỗ trợ với mã này, số lượng các cách bạn có thể tham chiếu một bảng trong một câu lệnh SQL là đáng kinh ngạc.

PLUS, nếu truy vấn bao gồm tham chiếu đến chế độ xem hoặc UDF, thông tin về những bảng cơ bản sẽ không nằm trong chuỗi làm cho việc nhận thông tin đó hoàn toàn không thực tế. Ngoài ra, bạn cần phải thông minh về việc phát hiện các bảng tạm thời và loại trừ chúng khỏi kết quả của bạn.

Nếu bạn phải làm điều này, cách tiếp cận tốt hơn sẽ là sử dụng các API cho công cụ cơ sở dữ liệu cụ thể mà SQL được dự định. Ví dụ: bạn có thể tạo chế độ xem dựa trên truy vấn và sau đó sử dụng api Máy chủ DB để phát hiện các phụ thuộc cho chế độ xem đó. Công cụ DB sẽ có khả năng phân tích cú pháp của nó đáng tin cậy hơn bao giờ hết nếu bạn không có nỗ lực lớn để đảo ngược kỹ sư truy vấn.

Nếu, một cách tình cờ, bạn đang làm việc với SQL Server, đây là một bài viết về việc phát hiện phụ thuộc vào nền tảng đó: Finding Dependencies in SQL Server 2005

0

này sẽ rút khỏi một tên bảng trên chèn vào truy vấn:

(?<=(INTO)\s)[^\s]*(?=\(()) 

sau đây sẽ làm như vậy nhưng với một lựa chọn bao gồm tham gia

(?<=(from|join)\s)[^\s]*(?=\s(on|join|where)) 

Cuối cùng sẽ trở lại một chèn nếu bạn muốn quay trở lại chỉ các giá trị được tổ chức tại một truy vấn chèn sử dụng Regex sau

(?i)(?<=VALUES[ ]*\().*(?=\)) 

Tôi biết đây là một chủ đề cũ nhưng nó có thể giúp người khác nhìn xung quanh

Thưởng thức

0

Tôi đã thử tất cả các bên trên nhưng không ai làm việc kể từ khi tôi sử dụng nhiều truy vấn. Tôi đang làm việc với PHP mặc dù và sử dụng một thư viện PEAR gọi là SQL_Parser, nhưng hy vọng giải pháp của tôi sẽ giúp.Ngoài ra, tôi đã gặp rắc rối với dấu nháy đơn và sencences dành riêng cho MySQL vì vậy tôi quyết định loại bỏ tất cả các lĩnh vực từ truy vấn trước khi phân tích nó.

function getQueryTable ($query) { 
    require_once "SQL/Parser.php"; 
    $parser = new SQL_Parser(); 
    $parser->setDialect('MySQL'); 

    // Stripping fields section 
    $queryType = substr(strtoupper($query),0,6);    
    if($queryType == 'SELECT') { $query = "SELECT * ".stristr($query, "FROM"); } 
    if ($havingPos = stripos($query, 'HAVING')) { $query = substr($query, 0, $havingPos); } 


    $struct = $parser->parse($query); 

    $tableReferences = $struct[0]['from']['table_references']['table_factors']; 

    foreach ((Array) $tableReferences as $ref) { 
     $tables[] = ($ref['database'] ? $ref['database'].'.' : $ref['database']).$ref['table']; 
    } 

    return $tables; 

} 
0

Trong PHP, tôi sử dụng chức năng này, nó sẽ trả về một mảng với tên bảng được sử dụng trong một tuyên bố sql:

function sql_query_get_tables($statement){ 
    preg_match_all("/(from|into|update|join) [\\'\\´]?([a-zA-Z0-9_-]+)[\\'\\´]?/i", 
      $statement, $matches); 
    if(!empty($matches)){ 
     return array_unique($matches[2]); 
    }else return array(); 
} 

Chú ý rằng nó không làm việc với a, b tham gia hoặc giản đồ. tablename đặt tên

tôi hy vọng nó làm việc cho bạn

1

một workaround là để thực hiện một quy ước đặt tên trên bảng và quan điểm. Sau đó, câu lệnh SQL có thể được phân tích cú pháp trên tiền tố đặt tên.

Ví dụ:

SELECT tbltable1.one, tbltable1.two, tbltable2.three FROM tbltable1 INNER JOIN tbltable2 ON tbltable1.one = tbltable2.three

Chia khoảng trắng để mảng:

("SELECT","tbltable1.one,","tbltable1.two,","tbltable2.three","FROM","tbltable1","INNER","JOIN","tbltable2","ON","tbltable1.one","=","tbltable2.three")

Get trái của các yếu tố đến giai đoạn:

("SELECT","tbltable1","tbltable1","tbltable2","FROM","tbltable1","INNER","JOIN","tbltable2","ON","tbltable1","=","tbltable2")

yếu tố Remove với biểu tượng:

("SELECT","tbltable1","tbltable1","tbltable2","FROM","tbltable1","INNER","JOIN","tbltable2","ON","tbltable1","tbltable2")

Giảm đến giá trị duy nhất:

("SELECT","tbltable1","tbltable2","FROM","INNER","JOIN","ON")

Lọc trên Left 3 ký tự = "tbl"

("tbltable1","tbltable2")

0

Tôi sử dụng này mã dưới dạng macro Excel để phân tích cú pháp tab chọn và trích xuất tên điện tử.

phân tích của tôi giả định rằng các sintax “chọn từ a, b, c" không được sử dụng.

Chỉ cần chạy nó chống lại truy vấn sql của bạn và nếu bạn không sadisfied với kết quả bạn sẽ có chỉ một vài dòng mã xa kết quả bạn mong đợi. Chỉ cần gỡ lỗi và sửa đổi mã cho phù hợp.

get_tables Sub()

sql_query = Cells(5, 1).Value 

tables = "" 

'get all tables after from 

sql_from = sql_query 

While InStr(1, UCase(sql_from), UCase("from")) > 0 

    i = InStr(1, UCase(sql_from), UCase("from")) 

    sql_from = Mid(sql_from, i + 5, Len(sql_from) - i - 5) 

    i = InStr(1, UCase(sql_from), UCase(" ")) 

    While i = 1 

     sql_from = Mid(sql_from, 2, Len(sql_from) - 1) 

     i = InStr(1, UCase(sql_from), UCase(" ")) 

    Wend 

    i = InStr(1, sql_join, Chr(9)) 

    While i = 1 

     sql_join = Mid(sql_join, 2, Len(sql_join) - 1) 

     i = InStr(1, sql_join, Chr(9)) 

    Wend 

    a = InStr(1, UCase(sql_from), UCase(" ")) 

    b = InStr(1, sql_from, Chr(10)) 

    c = InStr(1, sql_from, Chr(13)) 

    d = InStr(1, sql_from, Chr(9)) 

    MinC = a 

    If MinC > b And b > 0 Then MinC = b 

    If MinC > c And c > 0 Then MinC = c 

    If MinC > d And d > 0 Then MinC = d 

    tables = tables + "[" + Mid(sql_from, 1, MinC - 1) + "]" 

Wend 

'get all tables after join 

sql_join = sql_query 

While InStr(1, UCase(sql_join), UCase("join")) > 0 

    i = InStr(1, UCase(sql_join), UCase("join")) 

    sql_join = Mid(sql_join, i + 5, Len(sql_join) - i - 5) 

    i = InStr(1, UCase(sql_join), UCase(" ")) 

    While i = 1 

     sql_join = Mid(sql_join, 2, Len(sql_join) - 1) 

     i = InStr(1, UCase(sql_join), UCase(" ")) 

    Wend 

    i = InStr(1, sql_join, Chr(9)) 

    While i = 1 

     sql_join = Mid(sql_join, 2, Len(sql_join) - 1) 

     i = InStr(1, sql_join, Chr(9)) 

    Wend 

    a = InStr(1, UCase(sql_join), UCase(" ")) 

    b = InStr(1, sql_join, Chr(10)) 

    c = InStr(1, sql_join, Chr(13)) 

    d = InStr(1, sql_join, Chr(9)) 

    MinC = a 

    If MinC > b And b > 0 Then MinC = b 

    If MinC > c And c > 0 Then MinC = c 

    If MinC > d And d > 0 Then MinC = d 

    tables = tables + "[" + Mid(sql_join, 1, MinC - 1) + "]" 

Wend 

tables = Replace(tables, ")", "") 

tables = Replace(tables, "(", "") 

tables = Replace(tables, " ", "") 

tables = Replace(tables, Chr(10), "") 

tables = Replace(tables, Chr(13), "") 

tables = Replace(tables, Chr(9), "") 

tables = Replace(tables, "[]", "") 

End Sub

Các vấn đề liên quan