Проблемы со вставкой значений в таблицу SQL, значения ошибочно принимаются за столбцы

Я продолжаю получать исключение, которое гласит:

"Invalid Column Name, 'IBM'."

Ошибка возникает по адресу: "' + @ticker + '", хотя @ticker объявлено в VALUES. Я подозреваю, что ошибка может происходить в какой-то другой точке запроса, но я новичок в SQL/T-SQL, поэтому не знаю, как выяснить, где именно.

private string InsertRecord(Indicator indicator)
{
    try
    {
        if (!CheckIfColumnExists(indicator.GetType().Name))
        {
            AddColumn(indicator.GetType().Name, SqlDbType.Real);
        }

        const string query = @"
        DECLARE @sql nvarchar(max) = '
        INSERT INTO ' + QUOTENAME(@tableName) + '(
        ' + QUOTENAME(@indicator) + ', date, ticker)  
        VALUES(' + @indicatorValue + ', ' + @date + ', ' + @ticker + ') 
        ';

        EXEC sp_executesql @sql;
        ";

        //checking if the record is already there
        if (!CheckIfRecordExists(indicator))
        {
            using (SqlConnection conn = new SqlConnection(this.connectionstring))
            {



                conn.Open();


                SqlCommand cmd = new SqlCommand(query , conn);
                cmd.Parameters.AddWithValue("@tableName", tableName);
                cmd.Parameters.AddWithValue("@indicator", indicator.GetType().Name);
                cmd.Parameters.AddWithValue("@indicatorValue", indicator.Value.ToString());
                cmd.Parameters.AddWithValue("@date", indicator.Date.ToString("yyyy-MM-dd"));
                cmd.Parameters.AddWithValue("@ticker", indicator.Ticker);
                var result = cmd.ExecuteNonQuery();




                return "New Record Inserted";


            }
        }
        else
        {
            return "Record Already Exists";
        }
    }
    catch
    {
        return "Failure Inserting New Record";
    }
}

Обновлено: я принимаю ответ CharlieFace, потому что он позволяет избежать нарушений через SQL Injection и объясняет необходимость sp_executesql.

Кроме того, вы не добавляете галочки в заполнители параметров ('@placeholder'). В общем, вместо того, чтобы создавать сложные машины, такие как код для вставки в любую таблицу, начните с простого, прямого кода, пока у вас не будет нескольких лет опыта.

Ňɏssa Pøngjǣrdenlarp 06.05.2022 06:18

@YongShun Indicator — это класс, который расширяет несколько подклассов, поэтому indicator.GetType().Name будет меняться в зависимости от того, как объявлен индикатор, в данном случае строка читается как «SMA». Кроме того, спасибо за советы, я думаю, я просто использую конкатенацию.

oglilprettythug 06.05.2022 06:30

@ŇɏssaPøngjǣrdenlarp Хорошо, спасибо, я их уберу. Спасибо и за совет.

oglilprettythug 06.05.2022 06:32
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
61
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Обеспокоенность

  1. Вы не можете использовать параметры для добавления значений для имени таблицы и имени столбца. Вместо этого требуется конкатенация строк, хотя это будет привести к открытой атаке SQL Injection (пример: Бобби Столы). Следовательно, убедитесь, что у вас есть сделано достаточно проверки для tableName или части конкатенации строк.

  2. Вам не нужно добавлять одинарные кавычки ' для параметров в запросе. Это будет сделано автоматически, когда SQLCommand добавит значение SQLParameter к запросу в соответствии с типом параметра.

  3. Не вижу необходимости использовать EXEC sp_executesql. Хотя вы можете просто сразу выполнить запрос INSERT.

  4. В сообществе StackOverflow обычно предлагается использовать SqlCommand.Add("@Name", SqlDbType).Value и указывать тип параметра вместо SqlCommand.AddWithValue(). См. Можем ли мы уже отказаться от использования AddWithValue()?.

В заключение, ваш SqlCommand должен быть таким:

string query = @"
    INSERT INTO " + tableName + 
    "(" + indicator.GetType().Name + ", date, ticker)" +
    " VALUES (@indicatorValue, @date, @ticker)"; 

SqlCommand cmd = new SqlCommand(query , conn);
cmd.Parameters.Add("@indicatorValue", SqlDbType.NVarchar).Value = indicator.Value.ToString();
cmd.Parameters.Add("@date", SqlDbType.NVarchar).Value = indicator.Date.ToString("yyyy-MM-dd");
cmd.Parameters.Add("@ticker", SqlDbType.NVarchar).Value = indicator.Ticker;

Есть является причина использовать sp_executesql: чтобы использовать QUOTENAME. Вы не используете его, и поэтому могут возникнуть проблемы с инъекцией. Также вы должны передавать длины параметров, а не только типы. А у значений параметров еще есть ToString() чего не должно быть

Charlieface 06.05.2022 10:39
Ответ принят как подходящий

Вы должны передать параметры, которые содержат данные (в отличие от имен столбцов и таблиц), вплоть до sp_executesql

        const string query = @"
DECLARE @sql nvarchar(max) = '
INSERT INTO ' + QUOTENAME(@tableName) + '(
  ' + QUOTENAME(@indicator) + ', date, ticker)  
VALUES(@indicatorValue, @date, @ticker) 
';

EXEC sp_executesql @sql,
  N'@indicatorValue nvarchar(100), @date date, @ticker nvarchar(100)',
  @indicatorValue,
  @date,
  @ticker;
";

Вы также должны передавать параметры как их реальные значения (дата, целое число), а не ToString. Также явно объявляйте типы и длины параметров.

// table and column name should be NVARCHAR(128)
cmd.Parameters.Add("@tableName", SqlDbType.NVarchar, 128).Value = tableName;
cmd.Parameters.Add("@indicator", SqlDbType.NVarchar, 128).Value = indicator.GetType().Name;
cmd.Parameters.Add("@indicatorValue", SqlDbType.NVarchar, 100).Value = indicator.Value;
cmd.Parameters.Add("@date", SqlDbType.Date).Value = indicator.Date;
cmd.Parameters.Add("@ticker", SqlDbType.NVarchar, 100).Value = indicator.Ticker;

была небольшая синтаксическая ошибка в : N'@indicatorValue nvarchar(100), @date date, @ticker nvarchar(100);,, должно быть: N'@indicatorValue nvarchar(100), @date date, @ticker nvarchar(100)',

oglilprettythug 06.05.2022 18:32

Другие вопросы по теме