Как выбрать с дополнительными столбцами? - PullRequest
2 голосов
/ 08 марта 2012

В настоящее время я работаю над приложением c #, которое извлекает кучу данных из базы данных с указанным пользователем доступом (.mdb) и выполняет кучу вещей с этими данными. Проблема, с которой я недавно столкнулся, заключается в том, что в некоторых базах данных отсутствует столбец, существовавший во всех остальных.

Как мне сделать выборку в базе данных, но изящно потерпеть неудачу (выдать ноль в данных или что-то в этом роде), когда в базе данных нет столбца?

В настоящее время мой код выглядит примерно так:

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 ]

3 голосов
/ 08 марта 2012

Я мог бы что-то упустить, но ...

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

Следует сделать свое дело и позволить клиенту обработать набор результатов с важным предупреждением: исключить столбец из Table1 в приведенном выше примере невозможно.

(Мне не известен ни один метод для «динамического формирования» - с точки зрения вызывающего - SELECT, за исключением * в списке столбцов, как указано выше.)

Удачного кодирования.

2 голосов
/ 08 марта 2012

Нет способа сделать это за один запрос: вы не можете выполнить запрос, который включает столбцы, которых нет в исходных таблицах.Когда сервер пытается скомпилировать запрос, он просто потерпит неудачу.

Если вам абсолютно необходимо поддерживать разные сценарии, вам понадобятся разные запросы для каждого из них.

Чтобы сделать вещи еще болееофигенно, не существует документированного способа проверить, есть ли в таблице 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."
}
2 голосов
/ 08 марта 2012

Способ сделать это состоит не в том, чтобы использовать магические числа, а в том, чтобы извлекать имена полей из считывателя и использовать их - например, GetName и т. Д.

В качестве альтернативы, используйте преобразователь типа «dapper», который будетсделай это для тебя.

1 голос
/ 08 марта 2012

Существует способ извлечь схему таблицы, используя 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 не изменится, пока приложение активно).

В любом случае кажется, что он собирается сделать код для«если еще» просто позаботиться о наличии и отсутствии столбца в таблице.

...