Как решить синтаксическую ошибку при использовании этого оператора INSERT INTO и пространства имен .NET OleDb?

Я продолжаю получать сообщение об ошибке, когда пытаюсь вставить значения в базу данных Access.

Ошибка является синтаксической, что приводит к следующему исключению:

OleDbException — необработанная синтаксическая ошибка в операторе INSERT INTO.

private OleDbConnection myCon;

public Form1()
{
    InitializeComponent();
    myCon = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\File.mdb");
}

private void insertuser_Click(object sender, EventArgs e)
{
    OleDbCommand cmd = new OleDbCommand();
    myCon.Open();
    cmd.Connection = myCon;
    cmd.CommandType = CommandType.Text;

    cmd.CommandText = "INSERT INTO User ([UserID], [Forename], [Surname], " +
                                        "[DateOfBirth], [TargetWeight], [TargetCalories], [Height]) " +
                      "VALUES ('" + userid.Text.ToString() + "' , '" +
                                    fname.Text.ToString() + "' , '" +
                                    sname.Text.ToString() + "' , '" +
                                    dob.Text.ToString() + "' , '" +
                                    tarweight.Text.ToString() + "' , '" +
                                    tarcal.Text.ToString() + "' , '" +
                                    height.Text.ToString() + "')";

    cmd.ExecuteNonQuery();
    myCon.Close();
}

person Howard    schedule 07.01.2011    source источник
comment
Можете ли вы опубликовать ошибку, которую вы получаете?   -  person nabrond    schedule 07.01.2011
comment
вы получаете исключение? Приложение вылетает? Поместите операторы в блок try..catch, перехватите исключение и опубликуйте сообщение об исключении.   -  person Devendra D. Chavan    schedule 07.01.2011
comment
Привет, это сообщение об исключении: синтаксическая ошибка в инструкции INSERT INTO OleDbException не была обработана   -  person Howard    schedule 07.01.2011
comment
Я не работаю на C#, поэтому не знаю, как он взаимодействует со слоем интерфейса вашей базы данных, но Jet/ACE использует # в качестве разделителя для строкового представления значений даты, а не '. Изменение этого может помочь. По крайней мере, запишите отправляемую строку SQL и посмотрите, сможете ли вы запустить ее в интерактивном доступе.   -  person David-W-Fenton    schedule 08.01.2011


Ответы (6)


Ну, вы не указали, в чем ошибка, но ваша первая проблема заключается в том, что вы вставляете данные непосредственно в оператор SQL. Не делайте этого. Вы провоцируете атаки путем внедрения кода SQL.

Вместо этого используйте параметризованный оператор SQL. После этого, если у вас все еще есть проблемы, отредактируйте этот вопрос с новым кодом и укажите, в чем ошибка. Новый код, скорее всего, уже будет более понятным, так как не будет задействована огромная конкатенация, легко скрывающая что-то вроде несоответствующей скобки.

РЕДАКТИРОВАТЬ: Как упоминалось в комментариях, Jet/ACE уязвим для меньшего количества типов атак SQL-инъекций, поскольку он не разрешает DML. Для этой инструкции INSERT фактически может быть отсутствие уязвимости, но для SELECT с предложением WHERE, написанным аналогичным образом, пользовательский ввод может обойти некоторые средства защиты предложения WHERE. Я настоятельно рекомендую вам использовать параметризованные запросы как само собой разумеющееся:

  • Они означают, что вам не нужно избегать пользовательских данных
  • Они хранят данные отдельно от кода
  • У вас будет меньше забот, если вы когда-нибудь перейдете с Jet/ACE (независимо от того, переместите ли вы этот конкретный код или просто начнете работать с другими базами данных)
  • Для других типов данных, таких как даты, вам не нужно выполнять никаких действий, чтобы преобразовать данные в форму, подходящую для базы данных.

(Вам также не нужны все вызовы ToString. Мало того, что я ожидаю, что свойство с именем Text является уже строкой, но тот факт, что вы используете конкатенацию строк, означает, что преобразования строк будут в любом случае происходит автоматически.)

person Jon Skeet    schedule 07.01.2011
comment
@Howard: Без каких-либо подробностей? Ну что ж, это все же лучше, чем даже не знать так много. Когда ваш SQL параметризован, может быть легче увидеть проблему - или она может просто исчезнуть, если ошибка была вызвана вашими данными, содержащими кавычки. - person Jon Skeet; 07.01.2011
comment
О, великий эксперт SO, пожалуйста, дайте нам краткое изложение степени опасностей SQL Injection с хранилищем данных Jet/ACE. Возможно, вы захотите выполнить поиск SO, прежде чем отвечать на это... - person David-W-Fenton; 08.01.2011
comment
@David-W-Fenton: Мне кажется, что некоторые классы атак с внедрением SQL здесь неприменимы (те, которые включают DML), но могут быть другие классы (те, которые имеют прямой "WHERE X='"+input+'" код. (I прочитал ваше сообщение на pcreview.co.uk/forums/thread-4021211. php, в котором упоминалось об этом, и связанных сообщениях SO). Кроме того, параметризованный SQL хранит данные отдельно от кода, который я считаю более чистым. Наконец, я легко вижу, как кто-то портирует этот код с Jet/ACE на другую платформу баз данных, не задумываясь о всех возможных опасностях. - person Jon Skeet; 08.01.2011
comment
Также забыл упомянуть, что это означает, что вам не нужно беспокоиться об очистке или выходе из ввода. Я рассматриваю параметризованные запросы как лучший способ справиться, скажем, с фамилией О'Рейли. Я осмелюсь сказать, что существуют специфичные для Jet/ACE подпрограммы для выполнения экранирования, но каковы преимущества тех, которые используют технику, которая будет широко переносима между базами данных? (Возможно, вам придется переключаться между именованными и дополнительными параметрами, но основной подход будет таким же.) - person Jon Skeet; 08.01.2011
comment
Я думаю, что ваша точка зрения неверна. Вы, кажется, подходите к этому с точки зрения Интернета, и я не считаю Jet/ACE подходящей базой данных для любого веб-приложения. Конечно, вы можете использовать Jet/ACE из языков .NET, Delphi или любой другой среды разработки. В этом случае использование уровня абстракции базы данных, вероятно, является хорошей идеей, и это сделает параметризацию почти единственным способом сделать что-то. В среде Access все эти вещи не так важны (и именно в этом контексте я написал свой длинный пост о SQL-инъекциях в Access). - person David-W-Fenton; 10.01.2011
comment
@David-W-Fenton: я не понимаю, какое это имеет отношение к тому, чтобы быть в Интернете или нет. Будут ли пользовательские данные содержать такое имя, как О'Рейли, только в Интернете? Почему уровень абстракции не может быть хорошей практикой разработки программного обеспечения в среде, использующей Jet/ACE? Почему использование стандартной передовой практики, которая впоследствии сразу же переносится в другую базу данных (как с точки зрения навыков разработчика, так и с точки зрения фактического кода), не является хорошей идеей при использовании Jet/ACE? В чем заключается недостаток использования стандартных рекомендаций? Я подозреваю, что нам, возможно, придется согласиться, чтобы не согласиться... - person Jon Skeet; 10.01.2011
comment
@David-W-Fenton: Имейте в виду, что мы уже можем сказать, что OP использует использование Jet/ACE из языка .NET (C#). Обратите внимание, что ваш комментарий к самому вопросу (о разделителе даты для Access) является примером того, о чем не следует беспокоиться, и какие параметризованные запросы могут изолировать от вас. Почему меня должен волновать текстовый формат дат? Мне просто нужны данные! - person Jon Skeet; 10.01.2011
comment
Опять же, я думаю, что вы упускаете мою мысль. Я имею в виду объяснение SO проблем с SQL-инъекциями в приложениях Access, и в этом отношении все ваши точки зрения не соответствуют действительности. Скорее всего, вы не стали бы создавать интерфейс Access QBF, который просто позволял бы пользователю вводить произвольный текст (если бы вы это сделали, в большинстве случаев вы усложнили бы задачу своим пользователям). Что касается других сред, я полностью за уровень абстракции. В самом Access не рекомендуется использовать что-либо, кроме Jet/ACE, в качестве посредника для других источников данных, поэтому по большей части ваш код изначально будет независимым от движка db. - person David-W-Fenton; 12.01.2011
comment
Я ожидаю, что надлежащий обобщенный интерфейс базы данных любого рода позаботится о таких проблемах, как разделители и подстановочные знаки, и когда я использую SQL Server из Access с использованием ODBC, мне не нужно беспокоиться о специфике целевой БД в этом отношении. Я не знаю, обрабатывает ли это для него интерфейс, который использовал оригинальный постер, или нет. Если это не так, на мой взгляд, это не очень полезный интерфейс. Я предложил это предложение только как способ обойти недостатки этого интерфейса (при условии, что это причина, по которой он не работает). - person David-W-Fenton; 12.01.2011
comment
@JonSkeet Я задаю связанный вопрос здесь: stackoverflow .com/questions/14475968/, не могли бы вы проверить это - person Saeid; 23.01.2013
comment
@Saeid: На самом деле это вообще не похоже. - person Jon Skeet; 23.01.2013
comment
@JonSkeet Вы правы, но на самом деле я ищу любое решение, а затем нахожу вас здесь, спасибо за внимание. - person Saeid; 23.01.2013
comment
@Saeid: Итак, вы считаете уместным просто добавить комментарий к ответу на несвязанный вопрос? Извините, но это не так. - person Jon Skeet; 23.01.2013

Я разместил это как комментарий к повторяющемуся вопросу по адресу: Синтаксическая ошибка в операторе INSERT INTO в c# OleDb Exception не может обнаружить ошибку

Поместите скобки [] вокруг имени таблицы «Пользователь». Это зарезервированное слово в SQL Server.

«Пользователь» также является зарезервированным словом в Access (судя по провайдеру в вашей строке подключения).

Но я полностью согласен с Джоном — если вы исправите свою текущую реализацию, вы просто откроете большую дыру в безопасности (не меньше вашей таблицы User!)

person Tim Medora    schedule 07.01.2011

Эта проблема может возникнуть, если таблица базы данных содержит имена столбцов, в которых используются зарезервированные слова Microsoft Jet 4.0.

Измените имена столбцов в таблице базы данных, чтобы не использовать зарезервированные слова Jet 4.0.

person user3183270    schedule 23.04.2014
comment
Мне пришлось поставить [] вокруг имен таблиц и столбцов в запросе, чтобы разрешить принятие зарезервированного слова. - person Kevin S. Miller; 07.06.2017

Если TargetWeight, Height и TargetCalories являются значениями с плавающей запятой или целыми числами, их не нужно заключать в кавычки в операторе SQL.

Кроме того, это не имеет прямого отношения к вашему вопросу, но вам действительно следует подумать об использовании параметризованного запроса. Ваш код очень уязвим для SQL-инъекций.

person Brennan Vincent    schedule 07.01.2011

public decimal codes(string subs)
    {
        decimal a = 0;


        con_4code();
            query = "select SUBJINTN.[SCODE] from SUBJINTN where SUBJINTN.[ABBR] = '" +                         subs.ToString() + "'";
            cmd1 = new OleDbCommand(query, concode);
            OleDbDataReader dr = cmd1.ExecuteReader();

вот ошибка в dr он говорит синтаксическая ошибка ehile в СУБД работает хорошо

            if (dr.Read())
            {
                a = dr.GetDecimal(0);
                MessageBox.Show(a.ToString());
            }
            return a;



    }
person user1289578    schedule 26.03.2012
comment
OleDbDataReader dr = cmd1.ExecuteReader(); в этот момент он показывает синтаксическую ошибку, в то время как простой карьер работает хорошо........ - person user1289578; 26.03.2012

После этого

cmd.CommandText="INSERT INTO User ([UserID], [Forename], [Surname], [DateOfBirth], [TargetWeight], [TargetCalories], [Height]) Values ('" + userid.Text.ToString() + "' , '" + fname.Text.ToString() + "' , '" + sname.Text.ToString() + "' , '" + dob.Text.ToString() + "' , '" + tarweight.Text.ToString() + "' , '" + tarcal.Text.ToString() + "' , '" + height.Text.ToString() + "')";

проверьте, что это содержит, возможно, [DateOfBirth] имеет недопустимый формат

person CLARK    schedule 12.05.2013