Как я могу добавить скалярную переменную для команды SQL в функцию, которая не содержит мой запрос напрямую?

Я постараюсь сделать это максимально кратким.

У меня есть функция GetData(ByVal query As String), единственной целью которой является многократное заполнение таблицы данных на основе определенных условий. Как видите, функция принимает строковую переменную, в которой находится оператор SQL. То, что я пытаюсь сделать, это добавить скалярную переменную, «@date» в моем случае, и независимо от того, где я пытаюсь добавить эту переменную, она выдает ошибку «Необходимо объявить скалярную переменную @date.

Обновлено: я должен упомянуть, что он выдает ошибку «должен объявить переменную» в строке sda.Fill(dt).

Функция получения данных


    Private Shared Function GetData(ByVal query As String) As DataTable
        Dim constr As String = ConfigurationManager.ConnectionStrings("WarrantyConnectionString").ConnectionString
        Using con As SqlConnection = New SqlConnection(constr)
            Using cmd As SqlCommand = New SqlCommand(query)
                Dim dt As DataTable = New DataTable()
                cmd.Parameters.Add("@date", SqlDbType.Date).Value = Date.Today
                Using sda As SqlDataAdapter = New SqlDataAdapter(query, con)
                    cmd.Parameters.AddWithValue("@date", Date.Today)
                    sda.Fill(dt)
                End Using

                Return dt
            End Using
        End Using
    End Function

Я вызываю функцию в процедуре, которая имеет запрос и обрабатывает все необходимые мне условия.

Процедура

Dim queryStart As String = "SELECT ( SELECT SUM(DealerNet) FROM Agreement WHERE VoidDate IS NULL "
        Dim queryAlias As String = "AS Actual, "
        Dim queryStart2 As String = "(SELECT SUM(Amount) FROM AccountingUS.dbo.ProjectedSales "
        Dim queryAlias2 As String = "AS Projected "

        If chart = "pmtd" Then
            Dim queryCondition As String = "AND IssueDate BETWEEN (SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, @date)-1, 0)) AND @date) "
            Dim queryCondition2 As String = "WHERE [Month] = MONTH(@date) AND [Year] = YEAR(@date)) "
            Dim query As String = queryStart + queryCondition + queryAlias + queryStart2 + queryCondition2 + queryAlias2
            Dim xMember1 As String = "Actual"
            Dim xMember2 As String = "Projected"

            Dim dt As DataTable = GetData(query)
            pmtdChart.DataSource = dt

Рассматриваемая переменная — это переменная @date в строках оператора «Если», единственное значение, которое она содержит, — это сегодняшняя дата. В настоящее время я пытался использовать «cmd.Parameters.Add("@date", SqlDbType.Date).Value = Date.Today в функции GetData, однако я все еще получаю ту же ошибку «Необходимо объявить скалярную переменную». Я также попытался заменить переменную @date просто "" + Date.Today + "" или переменной, которая содержит сегодняшнюю дату, но при этом я получаю сообщение об ошибке операнда "Конфликт операндов: дата несовместима с Int"

Любая помощь по этому вопросу будет принята с благодарностью, я относительно новичок в программировании и буду признателен за любые советы или критические замечания относительно лучших практик. Если вам нужна дополнительная информация или разъяснения по этому вопросу, я буду рад предоставить все, что могу. Заранее спасибо.

Однако ни один из приведенных выше кодов не добавляет параметр в запрос. ВЫ заявили, что пытались использовать cmd.Parameters.Add; где эта попытка в приведенном выше?

Larnu 30.01.2023 19:23

Извинения @Larnu, я отредактировал вопрос с кодом, показывающим, где я пытался добавить параметр.

Connor C. 30.01.2023 19:26

Каков текст запроса, который терпит неудачу?

Andrew Morton 30.01.2023 19:37

Что означает AND @date) в конце queryCondition?

Andrew Morton 30.01.2023 19:38

@ Эндрю Мортон, запрос не завершается ошибкой, я получаю сообщение об ошибке «Необходимо объявить скалярную переменную @date» в строке «sda.Fill (dt)» выше. 'AND @date)' является частью запроса, обозначающей дату между '(SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, @date)-1, 0))' и 'AND @date)'

Connor C. 30.01.2023 19:43

@КоннорС. Ошибка исходит из базы данных, поэтому что-то не так с SQL-запросом - возможно, если вы закомментировали строку AddWithValue, чтобы она добавляла параметр только один раз, это помогло бы. Вы пробовали запрос в SSMS? (О, теперь я вижу МЕЖДУ, спасибо.)

Andrew Morton 30.01.2023 19:50

Запрос отлично работает в SSMS, потому что я могу объявить переменную там. Мне интересно, где объявить переменную @date в приведенном выше коде, чтобы избежать ошибки «необходимо объявить скалярную переменную @date» в Visual Studio.

Connor C. 30.01.2023 20:01

Итак, поймите, что вы здесь делаете, и оцените, почему, но рассматривали ли вы вместо построения текста команды в вызывающих методах создание фактического объекта SqlCommand, включая параметры, и передачу его вашему методу GetData()?

Hursey 30.01.2023 20:46

Вы, кажется, правильно объявили это здесь. Тем не менее, будет ли @date всегда сегодняшней датой? Возможно, вместо этого просто используйте CURRENT_DATE() в своем запросе? Вы объединяете SQL-запрос, который редко рекомендуется.

ClearlyClueless 30.01.2023 20:46

@Hursey, в идеале я бы сделал что-то подобное, однако мне нужно, чтобы общий текст команды менялся в зависимости от выполнения определенных условий. Я не верю, что могу «предварительно построить» команду, если условия еще не выполнены. Я поэкспериментирую с этой идеей, и, если возможно, это может решить проблемы, которые у меня есть. Спасибо за ответ.

Connor C. 30.01.2023 21:00
dbdelta.com/addwithvalue-is-evil
Sean Lange 30.01.2023 23: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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
11
66
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Если вы посмотрите внимательно, вы настраиваете команду cmd, но фактически никогда не передаете ее в DataTable. Так что он ничего не знает о ваших параметрах. Как насчет этого (скопировано непроверенным из Попытка передать SqlCommand в SqlDataAdapter в качестве параметров):


DataTable dt = new DataTable();
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings("WarrantyConnectionString").ConnectionString))
            {
                con.Open();
                using (SqlCommand cmd = con.CreateCommand())
                {
                    cmd.CommandText = query;
                    cmd.CommandType = CommandType.Text;
                    cmd.Parameters.Add("@date", SqlDbType.Date)
                    cmd.Parameters.AddWithValue("@date", Date.Today)
                    using (SqlDataAdapter adp = new SqlDataAdapter(cmd))
                    {
                        adp.Fill(dt);
                        return dt;
                    }
                }
            }

Спасибо за ответ, к сожалению, с этим решением я все еще получаю сообщение «Необходимо объявить скалярную переменную @date».

Connor C. 30.01.2023 22:14

Работает ли он только с cmd.Parameters.Add("@date", SqlDbType.Date).Value = Date.Today вместо строк с двумя параметрами. Кроме того, какая строка на самом деле генерирует ошибку?

siggemannen 30.01.2023 22:17

Хорошо подмечено! @КоннорС. В коде вопроса должны быть Using cmd As SqlCommand = New SqlCommand(query, con) и Using sda As SqlDataAdapter = New SqlDataAdapter(cmd).

Andrew Morton 31.01.2023 19:45
    Dim dt as new DataTable()
    using db as new SqlConnection(ConfigurationManager.ConnectionStrings("WarrantyConnectionString").ConnectionString)
        db.Open();
        using cmd as New SqlCommand(query, con)
            cmd.Parameters.Add("@date", SqlDbType.Date).value = Date.Today
            //cmd.Parameters.AddWithValue("@date", Date.Today)
            using adp as new SqlDataAdapter(cmd)
                adp.Fill(dt)
                return dt
            End using
        End using
    End using
Ответ принят как подходящий

Хорошо, несколько вещей:

Я бы фактически передал объект команды этой процедуре получения данных.

И ваша проблема заключается в том, что вы передаете запрос «адаптеру», но НЕ предоставляете параметр @date этому «sda».

этот:

   Using sda As SqlDataAdapter = New SqlDataAdapter(query, con)
      cmd.Parameters.AddWithValue("@date", Date.Today)
      sda.Fill(dt)
   End Using

Другими словами, вы ДАЖЕ НЕ используете объект cmd!!!

Итак, вам нужно будет добавить параметр к объекту sda!!

например это:

Public Function GetData(ByVal query As String) As DataTable

    Dim dt As DataTable = New DataTable()

    Dim constr As String =
        ConfigurationManager.ConnectionStrings("WarrantyConnectionString").ConnectionString

    Using con As SqlConnection = New SqlConnection(constr)
        Using sda As SqlDataAdapter = New SqlDataAdapter(query, con)
            sda.SelectCommand.Parameters.Add("@date", SqlDbType.Date).Value = Date.Today()
            sda.Fill(dt)
        End Using
    End Using

    Return dt

End Function

Итак, да, вы ПОЛУЧИТЕ эту ошибку о том, что «@date» не объявлено, поскольку вы НЕ используете объект cmd для заполнения таблицы, а используете адаптер данных.

Итак, как на будущее?

Выберите тот или иной путь.

Я НАМНОГО за эти годы решил, что я буду использовать/принимать/принимать файлы cookie снова и снова над объектом SqlCommand.

Я нахожу объект Sql cmd лучше, так как:

it has the parameters.
it has a connection object (if you want to use)
it has a data reader built in

Итак, что это значит?

Я предлагаю этот код для получения данных:

Private Shared Function GetData(ByVal query As String) As DataTable
    Dim constr As String =
        ConfigurationManager.ConnectionStrings("WarrantyConnectionString").ConnectionString
    Dim dt As DataTable = New DataTable()

    Using con As SqlConnection = New SqlConnection(constr)
        Using cmd As SqlCommand = New SqlCommand(query, con))
            con.Open()
            cmd.Parameters.Add("@date", SqlDbType.Date).Value = Date.Today
            dt.Load(cmd.ExecuteReader)
        End Using
    End Using

    Return dt

End Function

Итак, нам не нужен адаптер данных. На самом деле адаптер нужен только в том случае, если вы собираетесь обновлять результирующую таблицу (подумайте об «адаптивной» таблице, чтобы запомнить это). Вы не собираетесь обновлять данные, так что здесь вообще не нужно использовать «адаптер». (и, к сожалению, в слишком многих примерах все равно используется «адаптер». Они предназначены для РАЗРЕШЕНИЯ обновления таблицы данных, а вы этого не делаете!

Итак, используйте командный объект. Обратите внимание, что вы ВСЕГДА должны открыть кондитерское изделие, но, поскольку у нас есть блоки «использования», оно ВСЕГДА будет закрыто для вас.

И обратите внимание, как тогда мы не создаем «использовать» «читатель» из адаптера или команду заполнения. (итак, мы устранили один сбивающий с толку объект!!).

Итак, в вашем примере вы создали объект команды SQL, правильно добавили параметр в объект команды, но ПОТОМ НЕ использовали его, а затем решили создать адаптер данных и использовать его!!!

Таким образом, вы можете/можете оставить свой код таким же, как и с исправлением sda "prameter", которое я опубликовал выше.

Однако, но я думаю, что вам лучше использовать объект команды sql.

Обратите внимание еще лучше?

Передайте объект команды процедуре GetData.

У меня есть глобальная подпрограмма общего назначения, называемая MyRstP(), и я передаю ей командный объект даже для простого jane sql.

но, если вы решите добавить параметры, вы можете!

Обратите внимание, что параметры могут быть добавлены на 100% независимо от строки SQL, и они могут быть добавлены до или после установки строки SQL.

И вы можете добавить параметры БЕЗ действительного рабочего соединения (или уже создали его). Таким образом, "параметры" - это просто коллекция - она ​​не заботится о SQL (ну, по крайней мере, пока!!).

Итак, вот мой RstP, и я выгрузил его в простой jane «module1», который есть в VB (это означает, что вам не нужно создавать статический класс, и тогда это работает так же, как VB6 или VBA.

Итак, это:

Public Function MyRstP(cmdSQL As SqlCommand, ByVal Optional strCon As String = "") As DataTable

    If strCon = "" Then
        strCon = My.Settings.TEST4
    End If

    Dim rstData As New DataTable
    Using conn As New SqlConnection(strCon)
        Using (cmdSQL)
            cmdSQL.Connection = conn
            conn.Open()
            rstData.Load(cmdSQL.ExecuteReader)
        End Using
    End Using

    Return rstData

End Function

Итак, теперь, чтобы заполнить представление сетки, я использую это:

    Dim strSQL As String =
        "SELECT id, HotelName, City FROM tblHotelsA"

    Dim cmdSQL As New SqlCommand(strSQL)

    GridView1.DataSource = MyRstP(cmdSQL)
    GridView1.DataBind()

или сказать определенную дату некоторых таких: Как насчет всех дат посещения отеля с начала года?

Итак, это:

    Dim strSQL As String =
        "SELECT id, HotelName, City FROM tblHotelsA
        WHERE VisitDate >= @dtStart"

    Dim dtStart As DateTime
    dtStart = DateSerial(DateTime.Today.Year, 1, 1)

    Dim cmdSQL As New SqlCommand(strSQL)
    cmdSQL.Parameters.Add("@dtStart", SqlDbType.DateTime).Value = dtStart

    GridView1.DataSource = MyRstP(cmdSQL)
    GridView1.DataBind()

обратите внимание, что у меня есть этот MyRstP (например, ваши данные для получения), но я могу передать ему все, что захочу, включая параметры из «вызывающего» кода, а НЕ в этой общей процедуре.

В любом случае, описанное выше использование и добавление параметра к «адаптеру» исправит это, но я бы перешел на использование только командного объекта и соединения — адаптер действительно не требуется, и, как уже отмечалось, они действительно должны использоваться, КОГДА вы на самом деле хотите обновить таблицу данных, а затем отправить ее обратно в базу данных одним выстрелом.

Привет, Альберт, ты снова мне очень помог, я очень ценю время, которое ты потратил на свои ответы. Добавление параметров к адаптеру решило мою проблему, однако, прочитав ваше решение, я вижу значение только в использовании объекта команды и установке параметров в вызывающем коде. Я думаю, что буду использовать это в будущем.

Connor C. 01.02.2023 15:42

Либо дорога/выбор (адаптер sql или объект cmd). Я думаю, что делать это одним способом, а затем нарезать печенье и делать это снова и снова одним и тем же способом — это урок (поэтому, какой бы способ вы ни выбрали, это нормально). Тем не менее, я лично предпочитаю объект команды sql, и причина в том, что тогда я могу «передать» этот объект cmd в «общую» процедуру, которая принимает объект cmd. Я рекомендую подпрограмму, которая принимает объект sql cmd, и на самом деле у меня есть две подпрограммы.

Albert D. Kallal 01.02.2023 21:08

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