我正在创建需要检索 SQL 语句的架构(实际上是返回的表的架构)的应用程序:列名和相应的 SQL 类型的集合。基本实现如下:
DataTable table = new DataTable();
SqlDataAdapter sda = new SqlDataAdapter(sqlCommand);
sda.FillSchema(table, SchemaType.Source);
之后,我解析 DataTable 的列信息。一切正常,直到我尝试在 SQL 中使用条件语句并根据该条件返回具有不同模式的数据。例如:
CREATE TABLE TestDataTable(Column1 int, Column2 nvarchar(100))
IF EXISTS(SELECT * FROM TestDataTable)
BEGIN
SELECT Column1 FROM TestDataTable WHERE Column1>2
END
ELSE
BEGIN
SELECT Column2 FROM TestDataTable WHERE Column1>2
END
结果始终是检索模式中的 Column1,而不取决于 IF 语句中的条件(当我反转它时,结果仍然相同)。再一次 SQL 指标是 SELECT 子句中的 CASE 语句——如果它们根据某些条件返回不同的列,我们会得到更令人惊讶的结果。
我尝试了不同的变体和选项,但它们都有自己的局限性:
- SqlDataAdapter.Fill(); - IF statemt 评估正确,但无法获取字符串类型长度
- sqlCommand.ExecuteReader(CommandBehavior.SequentialAccess); SqlDataReader.GetSchemaTable(); - IF statemt 评估正确,但无法获取字符串类型长度
- sqlCommand.ExecuteReader(CommandBehavior.SchemaOnly); SqlDataReader.GetSchemaTable(); - 无法获得字符串类型的长度。此外,它还返回模式,假设每个条件都评估为 True。
我发现了有关 SqlDataAdapter.FillSchema() 方法如何工作的讨论,看起来它真的很复杂,并且会生成一些元数据请求 SQL。所以我真的很惊讶它即使使用动态生成的 SQL 也能正常工作,比如
DECLARE @selectPart1 nvarchar(100)
SET @selectPart1=N'SELECT Column1'
DECLARE @selectPart2 nvarchar(100)
SET @selectPart2=N'FROM TestDataTable'
DECLARE @selectQuery nvarchar(200)
SET @selectQuery = @selectPart1 + ' ' + @selectPart2
EXECUTE sp_executesql @selectQuery"
但是,如果它成功地评估了 SET 语句,为什么它不能评估 IF 条件呢?
PS:我知道根据某些条件返回不同数据模式的语句是不寻常且难以处理的,这绝对是一种不好的做法,但是我们将获得的 SQL 是用户提供的,我们至少应该检测到这种不一致案例。
作为一种解决方法,一种检测此类情况的方法(向用户显示适当的消息)也是可以接受的。