Dot-Net

從查詢中獲取表模式

  • October 23, 2013

根據MSDNSqlDataReader.GetSchemaTable返回執行查詢的列元數據。我想知道是否有類似的方法可以為給定查詢提供表元數據?我的意思是涉及哪些表以及它有哪些別名。

在我的應用程序中,我得到了查詢,我需要以where程式方式附加子句。使用GetSchemaTable(),我可以獲得列元數據及其所屬的表。但是即使表有別名,它仍然返回真實的表名。有沒有辦法獲取該表的別名?

以下程式碼顯示了獲取列元數據。

const string connectionString = "your_connection_string";
string sql = "select c.id as s,c.firstname from contact as c";

using(SqlConnection connection = new SqlConnection(connectionString))
using(SqlCommand command = new SqlCommand(sql, connection))
{
   connection.Open();
   SqlDataReader reader = command.ExecuteReader(CommandBehavior.KeyInfo);
   DataTable schema = reader.GetSchemaTable();
   foreach (DataRow row in schema.Rows)
   {
       foreach (DataColumn column in schema.Columns)
       {
           Console.WriteLine(column.ColumnName + " = " + row[column]);
       }
       Console.WriteLine("----------------------------------------");
   }
   Console.Read();
}

這將正確地為我提供列的詳細資訊。但是當我看到BaseTableName列時Id,它給出contact的不是別名c。有沒有辦法從上述查詢中獲取表模式和別名?

任何幫助都會很棒!

編輯

雖然我可以使用 Rob 建議的執行計劃,但我會很感激任何替代的簡單方法。

由tomekszpakowicz回答問題

您(或您的應用程序)是相關查詢的來源嗎?在這種情況下,您應該知道別名。

我不是查詢的作者。我們有一個系統,使用者可以在其中輸入查詢。我們使用我上面解釋的方法從中建構列。這些細節將被持久化,另一個使用者可以使用它,比如添加新的標準等。所以我們需要根據我們擁有的資訊動態地建構 SQL。所以當一個列被別名並且我們沒有得到別名時,那麼構造的 where 子句將是無效的。

謝謝

簡短的回答

這行不通。根據設計,您不能從結果模式中獲取表別名。而且您不能依賴能夠從查詢執行計劃中獲取它們。

長答案

當您獲得 SQL 查詢的結果時,該查詢已經被解析、驗證、優化、編譯成某種內部表示並執行。別名是查詢“原始碼”的一部分,通常在第 1 步和第 2 步左右失去。

執行查詢後,唯一可以視為表的內容是 a) 真實的物理表和 b) 返回的數據,視為單個匿名表。之間的一切都可以轉換或完全優化。

如果要求 DBMS 保留別名,那麼優化複雜查詢實際上是不可能的。

可能的解決方案

我建議重申一個問題:

  1. 您(或您的應用程序)是相關查詢的來源嗎?在這種情況下,您應該知道別名。
  2. 如果您收到其他人提供的查詢…嗯…這取決於您為什麼要添加 where 原因。
  • 在最壞的情況下,您必須自己解析查詢。
  • 在最好的情況下,您可以讓他們訪問視圖而不是真正的表,並將 where 子句放在視圖中。

簡單而醜陋的解決方案

如果我正確理解您的要求:

  • 使用者 A 在您的程序中輸入查詢。
  • 使用者 B 可以執行它(但不能編輯它)並查看返回的數據。此外,她可以使用您提供的某種小元件根據返回的列添加過濾器。
  • 您不想在應用程序內應用過濾器,而是將它們添加到查詢中,以避免從數據庫中獲取不必要的數據。

在這種情況下:

  • 當 A 編輯查詢嘗試執行它並為返回的列收集元數據時。如果ColumnNames 不是唯一的,請向作者投訴。使用查詢儲存元數據。

  • 當 B 添加過濾器(基於查詢元數據)時,儲存列名和條件。

  • 執行時:

    • 檢查過濾器列是否仍然有效(A 可能已更改查詢)。如果不刪除無效過濾器和/或通知 B。
    • 像這樣執行查詢:
     select *
     from ({query entered by A}) x
     where x.Column1 op1 Value1
         and x.Column2 op2 Value2
    

如果您想優雅地處理數據庫架構更改,您需要添加一些額外的檢查以確保元數據與查詢真正返回的內容一致。

安全說明

您的程序會將使用者 A 編寫的查詢直接傳遞給數據庫。使用權限不超過 A 的數據庫權限的數據庫連接來執行此操作至關重要。否則,您要求的是基於 SQL 注入的漏洞利用。

推論

如果使用者 A 出於安全原因沒有直接訪問數據庫的權限,則不能使用上述解決方案。

在這種情況下,使其安全的唯一方法是確保您的應用程序理解 100% 的查詢,這意味著在您的程序中解析它並只允許您認為安全的操作。

引用自:https://stackoverflow.com/questions/3059126