在 C# 中,“SELECT TOP 0 * FROM (/* .. */) s”与 ADO.NET 结合使用是确定 S

本文关键字:NET ADO 结合 SELECT TOP FROM | 更新日期: 2023-09-27 18:31:38

我有一个SQL SELECT语句,该语句在运行时之前不会知道,其中可能包含JOIN和内部选择。 我需要从 C# 中确定语句返回结果的每个列的名称和数据类型。 我倾向于做这样的事情:

string orginalSelectStatement = "SELECT * FROM MyTable";
string selectStatement = string.Format("SELECT TOP 0 * FROM ({0}) s", orginalSelectStatement);
SqlConnection connection = new SqlConnection(@"MyConnectionString");
SqlDataAdapter adapter = new SqlDataAdapter(selectStatement, connection);
DataTable table = new DataTable();
adapter.Fill(table);
foreach (DataColumn column in table.Columns)
{
    Console.WriteLine("Name: {0}; Type: {1}", column.ColumnName, column.DataType);
}

有没有更好的方法来做我想做的事情? 通过"更好",我的意思是完成相同任务的资源密集度较低的方式或完成相同任务的更确定的方式(即,据我所知,我刚刚给出的代码片段在某些情况下会失败)。

解决方案:首先,我的TOP 0黑客很糟糕,即像这样的事情:

SELECT TOP 0 * FROM (SELECT 0 AS A, 1 AS A) S

换句话说,在子选择中,如果两个东西被别名为同一名称,则会引发错误。 所以它不在画面中。 但是,为了完整起见,我继续对其进行了测试,以及两个建议的解决方案:SET FMTONLY ONGetSchemaTable

以下是结果(每个查询 1,000 个以毫秒为单位):

架构时间:3130

TOP 0 时间:2808

FMTONLY ON时间:2937

我的建议是GetSchemaTable,因为它更有可能通过将SET FMTONLY ON作为有效的 SQL 删除来证明未来,并且它解决了混叠问题,即使它稍微慢一点。 但是,如果您"知道"重复的列名永远不会成为问题,那么TOP 0GetSchemaTable更快,并且比SET FMTONLY ON更面向未来。

这是我的实验代码:

int schemaTime = 0;
int topTime = 0;
int fmtOnTime = 0;
SqlConnection connection = new SqlConnection(@"MyConnectionString");
connection.Open();
SqlCommand schemaCommand = new SqlCommand("SELECT * FROM MyTable", connection);
SqlCommand topCommand = new SqlCommand("SELECT TOP 0 * FROM (SELECT * FROM MyTable) S", connection);
SqlCommand fmtOnCommand = new SqlCommand("SET FMTONLY ON; SELECT * FROM MyTable", connection);
for (int i = 0; i < 1000; i++)
{
    {
        DateTime start = DateTime.Now;
        using (SqlDataReader reader = schemaCommand.ExecuteReader(CommandBehavior.SchemaOnly))
        {
            DataTable table = reader.GetSchemaTable();
        }
        DateTime stop = DateTime.Now;
        TimeSpan span = stop - start;
        schemaTime += span.Milliseconds;
    }
    {
        DateTime start = DateTime.Now;
        DataTable table = new DataTable();
        SqlDataAdapter adapter = new SqlDataAdapter(topCommand);
        adapter.Fill(table);
        DateTime stop = DateTime.Now;
        TimeSpan span = stop - start;
        topTime += span.Milliseconds;
    }
    {
        DateTime start = DateTime.Now;
        DataTable table = new DataTable();
        SqlDataAdapter adapter = new SqlDataAdapter(fmtOnCommand);
        adapter.Fill(table);
        DateTime stop = DateTime.Now;
        TimeSpan span = stop - start;
        fmtOnTime += span.Milliseconds;
    }
}
Console.WriteLine("Schema Time: " + schemaTime);
Console.WriteLine("TOP 0 Time: " + topTime);
Console.WriteLine("FMTONLY ON Time: " + fmtOnTime);
connection.Close();

在 C# 中,“SELECT TOP 0 * FROM (/* .. */) s”与 ADO.NET 结合使用是确定 S

您可以使用 GetSchemaTable 来执行所需的操作。

这里有一个如何使用它的示例。

如果使用SQL Server,我会尝试使用SET FMTONLY ON

仅将元数据返回给客户端。可用于测试格式 未实际运行查询的响应。

显然在SQL Server 2012上,有一个更好的方法。所有内容在链接的 MSDN 文章中指定。

顺便说一句,这种技术是 LINQ To SQL 在内部用来确定存储过程等返回的结果集的技术。

动态 SQL 总是有点雷区,但你可以在查询上设置 FMTONLY - 这意味着查询将只返回元数据,就像没有返回任何结果一样。 所以:

string selectStatement = string.Format("SET FMTONLY ON; {0}", orginalSelectStatement);

或者,如果您没有绑定到 ADO,您是否不能沿着 Linq-to-SQL 路线并生成一个数据上下文,该上下文将所有数据库架构映射到代码及其相关类型? 您还可以查看一些Micro ORM,例如 Dapper.Net

还有很多

其他的ORM。