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

时间:2012-03-08 18:35:15

标签: c# sql oledb

我目前正在开发一个c#应用程序,该应用程序从用户指定的访问(.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]列的数据库,它已经停止工作了。它正在抛出OleDbException: "No value given for one or more required parameters."

任何帮助都将不胜感激。

4 个答案:

答案 0 :(得分:3)

我可能会遗漏一些东西,但是......

SELECT Table1.*, Table2.otherInfo
FROM ...

应该做的伎俩,并让客户端处理结果集,但有一个重要的警告:上面的Table1中无法排除列。

(我不知道任何“动态塑造”的方法 - 使用调用者的观点 - 除了上面列列表中的*之外的SELECT。)

快乐的编码。

答案 1 :(得分:2)

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

或者,使用像“dapper”这样的映射器来完成此操作。

答案 2 :(得分:2)

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

如果您绝对需要支持不同的场景,则每个场景都需要不同的查询。

为了使事情变得更加精彩,没有记录的方法来检查Access表是否通过SQL在其上具有特定列。在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."
}

答案 3 :(得分:1)

有一种方法可以使用OleDbDataReader.GetSchemaTable提取表模式,并且可以使用

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”只是为了处理表格中的列的存在和缺失。