【问题标题】:C#: Find tables involved in SQL queryC#:查找 SQL 查询中涉及的表
【发布时间】:2015-03-19 08:30:56
【问题描述】:

给定一个 SQL 查询变量,即

string mySQLQuery = "SELECT TableA.Field1, TableA.Field2,..., TableB.Field1, TableB.Field2,.... FROM TableA LEFT OUTER JOIN TableB ON TableA.Field1 = TableB.Field1"

有没有什么直接的方法可以在两个列表中提取查询中的字段和表名?所以:

列出“字段”:

  • 来自表 A、表 B(以及我可以通过加入添加的其他字段)的所有字段及其表前缀(即使在简单的“SELECT * FROM TableA”中只有一个表,我仍然需要'TableA.' 前缀)。

  • 表 B 中的所有字段及其表前缀,通过循环以通常的 fieldList.Add() 方式将它们添加到列表中。

列出“表格”:

  • 查询中涉及的所有表都以通常的tablesList.Add()方式通过循环。

我的第一种方法是做很多子串和比较,即找到FROM,然后向左修剪,子串直到第一个空格,然后JOIN,然后修剪,然后第一个子串直到空格。 ..,但这似乎不是正确的方法。

重新编辑

我知道我可以从 INFORMATION_SCHEMA.COLUMNS 中获取所有字段以及所有属性(稍后会出现),但问题是对于该查询,我需要知道表。我的步骤应该是:

  1. 查询“SELECT [fields] FROM [tables]”来自多行文本框,因此我可以编写 SQL 查询来获取我想要的字段。我通过 txtMyQuery.Text 属性获取字符串。

  2. 在SELECT查询中查找字段,在FROM子句中查找属于哪个表。

  3. 通过 strFields.Add() 方法将 [Table].[Field] 等字段存储在字符串列表 List strFields = new List() 中;

  4. 然后,以如下方式遍历列表:

    for (int i = 0; i < fieldList.Count; i++)
    {
       string mySqlQuery = "SELECT Table_Name, Column_Name, Data_Type FROM INFORMATION_SCHEMA.COLUMNS 
       WHERE (COLUMN_NAME + "." + TABLE_NAME) ='" + fieldList[i] + "'";
    
      //Commit query, get results in a gridview, etc.
    
    }
    

【问题讨论】:

  • 解析 sql 和解析 HTML 一样复杂。我会看看是否有可用的图书馆。我还没有找到免费的。就是这个:sqlparser.com
  • 如果sql语句是'SELECT * FROM TableA'应该输出什么?您还需要 JOIN 和 WHERE 子句中的字段,还是只需要 SELECT 子句中的字段?如果语句是 'SELECT * FROM TableA INNER JOIN TableB ON(TableA.BId = TableB.Id)' 会发生什么?
  • 我只需要 SELECT 子句中的字段将它们存储在列表中。即使像您建议的那样,在 SELECT 子句中引用了另一个没有字段的表,也不需要 WHERE、HAVING 等。如果是 SELECT * FROM Table A,我需要输出 TableA.Field1、TableA.Field2、TableA.Field3、...
  • 显然,如果不转到数据库中的实际表并从那里获取字段,就无法从诸如“SELECT * FROM Table A”之类的查询中获取字段列表。但是,您说您只需要实际选择的字段,因此您不能简单地向数据库询问查询中涉及的所有表的所有列。抱歉,但我没有看到一个简单的方法来做到这一点......
  • 可以通过使用数据读取器获取给定查询中的选定字段并将其用于模式信息。表可能需要从 SQL 中解析出来

标签: c# sql visual-studio


【解决方案1】:

当然,

表格:

SELECT TABLE_NAME FROM information_schema.TABLES

字段:

SELECT * FROM information_schema.COLUMNS WHERE TABLE_NAME = N'Your Table'

【讨论】:

  • 查看重新编辑...问题是需要提取“您的表”
  • 好的,那么我认为唯一的解决方案是制作自己的解析器或搜索制作的解析器。
【解决方案2】:

好的,过了一会儿,我找到了一些方法来实现这一点......我会在改进解决方案时解决这个问题(即,现在如果我们使用 * 选择,如 'SELECT * FROM TableA ',不支持别名,并且 SELECT 中的所有字段都应该是 [table].[field],但会给出我想要实现的目标):

这样,我在文本框中编写了一条 SQL 语句,我将它传递到一个新表单以检查查询的实际结果(如果需要,通过单击“预览”按钮),然后我填充一个 datagridview使用我想要检索的 SCHEMA 数据。

感谢大家的支持!

 private void btnQuery_Click(object sender, EventArgs e)
    {

        string strSql = this.txtQuery.Text;

        DataTable dt = new DataTable();

        String conStr = "Data Source=(LocalDB)\\v11.0;AttachDbFilename=|DataDirectory|\\TestDB.mdf;Integrated Security=True;Connect Timeout=30";
        using (SqlConnection conn = new SqlConnection(conStr))
        {
            //with the call to strSQLSchema, we get the table involved in the query, to retrieve the fields and properties
            SqlCommand cmd = new SqlCommand(strSQLSchema(strSql), conn);
            SqlDataAdapter adapter = new SqlDataAdapter(cmd);
            try
            {
                adapter.Fill(dt);
            }

            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        this.dgvColumns.DataSource = dt;

    }

    private void btnPreview_Click(object sender, EventArgs e)
    {
        //We must pass the sql query to preview
        string strSql = this.txtQuery.Text;
        SQLQueryDataPreview qp = new SQLQueryDataPreview(strSql);
        qp.Show();
    }

    private string strSQLSchema(string sqlQuery)
    {
        //we cut the "SELECT " start
        sqlQuery = sqlQuery.ToUpper();
        sqlQuery = sqlQuery.Substring(7);
        //we take all the fields until the FROM
        int myIndex = sqlQuery.IndexOf("FROM");

        sqlQuery = sqlQuery.Substring(0, myIndex);
        sqlQuery = sqlQuery.Trim();
        sqlQuery = sqlQuery.Replace(" ", string.Empty);
        sqlQuery = sqlQuery.Replace("\r\n", string.Empty);

        //Here we add all fields to a list... so far, "*" is not allowed, and all fields should be written [Table].[Name]
        string[] myFields = sqlQuery.Split(new char[] {' ', ','});

        List <string> myTables = new List<string>();

        //We will use this WHERE to find the fields in the SCHEMA. This WHERE first sentence helps to construct a valid where
        //and avoid problems with the 'OR' clause in each loop.

        string myWhere = "TABLE_NAME + '.' + COLUMN_NAME = ''";

        for (int i = 0; i < myFields.Count(); i++)
        {
            //here we take the table prefix and add it to an array
            int tableIndex = myFields[i].IndexOf(".");
            if (tableIndex != -1)
            {
                myTables.Add(myFields[i].Substring(0, tableIndex));
                myWhere += "OR (TABLE_NAME + '.' + COLUMN_NAME = '" + myFields[i] + "')";
            }               
        }

        //this is a List where we keep the tables derivated from names. We just copy the list generated before with a DISTINCT to eliminate duplicates.
        myTables = myTables.Distinct().ToList();

        string schema = "SELECT Table_Name, Column_Name, Data_Type FROM INFORMATION_SCHEMA.COLUMNS WHERE " + myWhere;
        return schema;
    }

}

【讨论】:

    猜你喜欢
    • 2016-07-26
    • 1970-01-01
    • 2015-05-12
    • 1970-01-01
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多