Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用可选列进行选择?_C#_Sql_Oledb - Fatal编程技术网

C# 如何使用可选列进行选择?

C# 如何使用可选列进行选择?,c#,sql,oledb,C#,Sql,Oledb,我目前正在开发一个c应用程序,它从用户指定的access.mdb数据库中获取一组数据,并用这些数据做一些工作。我最近遇到的一个问题是,一个数据库的某些部分缺少一个在所有其他数据库中都存在的列 当数据库中不存在列时,如何在数据库上执行select,但在数据中正常地抛出null或其他内容 目前,我的代码如下所示: OleDbConnection aConnection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data

我目前正在开发一个c应用程序,它从用户指定的access.mdb数据库中获取一组数据,并用这些数据做一些工作。我最近遇到的一个问题是,一个数据库的某些部分缺少一个在所有其他数据库中都存在的列

当数据库中不存在列时,如何在数据库上执行select,但在数据中正常地抛出null或其他内容

目前,我的代码如下所示:

OleDbConnection aConnection = new 
    OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + FileName);

string sqlQuery = "SELECT [Table1].[Index], [Table1].[Optional Info], 
    [Table2].[Other Info], .... 
    FROM [Table1] INNER JOIN [Table2] ON [Table1].[Index]=[Table2].[Index] 
    ORDER BY [Table1].[Index]";

OleDbCommand aCommand = new OleDbCommand(sqlQuery, aConnection);
OleDbDataReader aReader = aCommand.ExecuteReader();

(proceed to read data in line by line, using fabulous magic numbers)
很明显,这是我第一次使用数据库。只要它能正常工作,我就不会过分担心,但是对于一个不包含[Table1].[Optional Info]列的数据库,它已经停止工作了。它抛出了一个OLEDBEException:没有为一个或多个必需参数提供值


任何帮助都将不胜感激。

这样做的方法是不使用幻数,而是从读取器中获取字段名并使用它们-例如GetName等


或者,可以使用dapper之类的映射器来完成此操作。

在单个查询中无法完成此操作:无法运行包含源表中不存在的列的查询。当服务器试图编译查询时,它将失败

如果您确实需要支持不同的SCEMA,那么您将需要对每个SCEMA进行不同的查询

为了让事情变得更可怕,没有文档化的方法通过SQL检查Access表上是否有特定的列。在SQL Server中,您可以查询系统架构,如sys.objects或sys.columns。在Access中,MsysObjects表包含您需要的信息,但其模式可能会在不通知您的情况下更改

可能最安全的方法是在执行命令时进行一次预先检查,例如

SELECT * FROM Table1
然后扫描生成的列名,查看可选列是否存在;您的C代码将变成:

string sqlQuery = string.Empty;
if (optionalColumnExists)
{
  sqlQuery = "SELECT [Table1].[Index], [Table1].[Optional Info], -- etc."
}
else
{
  sqlQuery = "SELECT [Table1].[Index], '' AS [Optional Info], -- etc."
}

我可能错过了什么,但是

SELECT Table1.*, Table2.otherInfo
FROM ...
应该做到这一点,让客户机处理结果集,但有一个重要的警告:在上面的表1中无法排除列

我不知道有什么方法可以用调用者的视角动态地塑造一个SELECT,除了上面列列表中的*之外


愉快的编码。

有一种方法可以使用和提取表架构

OleDbConnection aConnection = new 
    OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + FileName);

OleDbCommand aCommand = new OleDbCommand("Table1", aConnection);
aCommand.CommandType = CommandType.TableDirect;
aConnection.Open();
OleDbDataReader aReader = cmd.ExecuteReader(CommandBehavior.SchemaOnly);
DataTable schemaTable = aReader.GetSchemaTable();
aReader.Close();
aConnection.Close();

bool optionalInfoColumnExists = schemaTable.Columns.Contains("Optional Info");  
现在在代码的后面

string sqlQuery = @"SELECT [Table1].[Index], {0} 
    [Table2].[Other Info], .... 
    FROM [Table1] INNER JOIN [Table2] ON [Table1].[Index]=[Table2].[Index] 
    ORDER BY [Table1].[Index]";

if (optionalInfoColumnExists)
{
    sqlQuery = string.Format(sqlQuery, "[Table1].[Optional Info],");
}
else
{
    sqlQuery = string.Format(sqlQuery, "");
}
在阅读时使用类似的逻辑

我不知道这是什么类型的应用程序,但optionalInfoColumnExists应该在应用程序或会话启动时填充,并在应用程序的整个生命周期内重复使用,即不要每次在此表上运行查询时都执行GetSchemaTable,假设应用程序处于活动状态时mdb不会更改


无论哪种方式,它似乎都会使代码具有if-else,以处理表中是否存在列。

如果SELECT子句中的一列丢失,他甚至不会返回查询的结果集……是的,不会编译。我并不认为一直以来都是这样。@MichaelEdenfield我在做一个隐含的假设,这里某处涉及到一个。*……即使有,包括一个不存在的列,后跟一个*也会导致查询失败;使用SELECT*当然可以避免整个问题:@Michael不需要只是*,因此我特意提到了。*,即SELECT x.a、x.b、y.*、z.c、z.d、z.eI最初发布了一个带有查询的答案,以检查该列是否存在,但您提出了一个很好的观点。。。查询将不会运行,因为服务器不会编译查询。接得好。值得注意的一点是,SQL中只有一部分更改为[col],将值更改为[col]。也就是说,可以进一步组合SQL语句。但是,这确实需要初始列检查/检测:请注意关于幻数的OP备注,大概是列索引-在这种情况下,在使用时需要进行一些调整。*是的,停止使用幻数的建议显然是很好的建议,无论其他问题如何。我很清楚地理解,我的印象是,在SQL中使用*,通常是一种不好的做法。有点像我在代码中烘焙列索引。。。我很高兴,如果唯一的效果是由于读取的数据比需要的多而导致效率降低,但是这里还有其他陷阱吗?@tugs我同意,这通常是一种不理想的做法,因为它隐藏了结果集的形状。但是,关于规则的第一条规则是,规则被破坏,在这种特殊情况下,获取动态形状,然后在客户机上进行适当的处理可能是有益的;-当然,另一种选择是如其他答案中所讨论的那样,对原始查询进行强烈的塑造。我不知道还有其他问题;使用t1.*、t2.*等语法时,使用完全限定名和DataTable inspe时,不会出现意外的名称碰撞 Action IIRC。@使用*拖拽对查询计划器没有什么影响,只是如果省略了任何列,它可能会比手动键入的列拾取更多的列。查询在执行之前解析为固定形状,就像它们都是显式指定的一样。调用者直到得到结果集才知道形状。打电话的人不知道电话的形状——可能是电话打得太多或太少了——这就导致了这样的争议-