Я постараюсь сделать это максимально кратким.
У меня есть функция 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"
Любая помощь по этому вопросу будет принята с благодарностью, я относительно новичок в программировании и буду признателен за любые советы или критические замечания относительно лучших практик. Если вам нужна дополнительная информация или разъяснения по этому вопросу, я буду рад предоставить все, что могу. Заранее спасибо.
Извинения @Larnu, я отредактировал вопрос с кодом, показывающим, где я пытался добавить параметр.
Каков текст запроса, который терпит неудачу?
Что означает AND @date)
в конце queryCondition
?
@ Эндрю Мортон, запрос не завершается ошибкой, я получаю сообщение об ошибке «Необходимо объявить скалярную переменную @date» в строке «sda.Fill (dt)» выше. 'AND @date)' является частью запроса, обозначающей дату между '(SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, @date)-1, 0))' и 'AND @date)'
@КоннорС. Ошибка исходит из базы данных, поэтому что-то не так с SQL-запросом - возможно, если вы закомментировали строку AddWithValue, чтобы она добавляла параметр только один раз, это помогло бы. Вы пробовали запрос в SSMS? (О, теперь я вижу МЕЖДУ, спасибо.)
Запрос отлично работает в SSMS, потому что я могу объявить переменную там. Мне интересно, где объявить переменную @date в приведенном выше коде, чтобы избежать ошибки «необходимо объявить скалярную переменную @date» в Visual Studio.
Итак, поймите, что вы здесь делаете, и оцените, почему, но рассматривали ли вы вместо построения текста команды в вызывающих методах создание фактического объекта SqlCommand, включая параметры, и передачу его вашему методу GetData()?
Вы, кажется, правильно объявили это здесь. Тем не менее, будет ли @date всегда сегодняшней датой? Возможно, вместо этого просто используйте CURRENT_DATE() в своем запросе? Вы объединяете SQL-запрос, который редко рекомендуется.
@Hursey, в идеале я бы сделал что-то подобное, однако мне нужно, чтобы общий текст команды менялся в зависимости от выполнения определенных условий. Я не верю, что могу «предварительно построить» команду, если условия еще не выполнены. Я поэкспериментирую с этой идеей, и, если возможно, это может решить проблемы, которые у меня есть. Спасибо за ответ.
Если вы посмотрите внимательно, вы настраиваете команду 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».
Работает ли он только с cmd.Parameters.Add("@date", SqlDbType.Date).Value = Date.Today вместо строк с двумя параметрами. Кроме того, какая строка на самом деле генерирует ошибку?
Хорошо подмечено! @КоннорС. В коде вопроса должны быть Using cmd As SqlCommand = New SqlCommand(query, con)
и Using sda As SqlDataAdapter = New SqlDataAdapter(cmd)
.
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 (например, ваши данные для получения), но я могу передать ему все, что захочу, включая параметры из «вызывающего» кода, а НЕ в этой общей процедуре.
В любом случае, описанное выше использование и добавление параметра к «адаптеру» исправит это, но я бы перешел на использование только командного объекта и соединения — адаптер действительно не требуется, и, как уже отмечалось, они действительно должны использоваться, КОГДА вы на самом деле хотите обновить таблицу данных, а затем отправить ее обратно в базу данных одним выстрелом.
Привет, Альберт, ты снова мне очень помог, я очень ценю время, которое ты потратил на свои ответы. Добавление параметров к адаптеру решило мою проблему, однако, прочитав ваше решение, я вижу значение только в использовании объекта команды и установке параметров в вызывающем коде. Я думаю, что буду использовать это в будущем.
Либо дорога/выбор (адаптер sql или объект cmd). Я думаю, что делать это одним способом, а затем нарезать печенье и делать это снова и снова одним и тем же способом — это урок (поэтому, какой бы способ вы ни выбрали, это нормально). Тем не менее, я лично предпочитаю объект команды sql, и причина в том, что тогда я могу «передать» этот объект cmd в «общую» процедуру, которая принимает объект cmd. Я рекомендую подпрограмму, которая принимает объект sql cmd, и на самом деле у меня есть две подпрограммы.
Однако ни один из приведенных выше кодов не добавляет параметр в запрос. ВЫ заявили, что пытались использовать
cmd.Parameters.Add
; где эта попытка в приведенном выше?