#c# #sql-server #stored-procedures
#c# #sql-server #хранимые процедуры
Вопрос:
Я пытаюсь передать имя таблицы хранимой процедуре в SQL Server.
Я понял, что по умолчанию это невозможно сделать из-за рисков для injection malicious attacks
.
Когда я поискал в Google, я понял, что это в любом случае возможно сделать.
Я все равно попытаюсь создать это, поскольку я понял, что это возможно каким-то образом, объявив string query
, как я пытаюсь сделать ниже. Зная о рисках, я все равно попытаюсь это сделать, поскольку мне действительно нравится создавать весь код в процедурах, чтобы сделать его более чистым. Код также будет использоваться только на моем собственном компьютере.
Исходный код, который у меня есть для хранимой процедуры, выглядит следующим образом. Я поместил @tableName
здесь в качестве параметра, который затем не работает, поскольку по умолчанию невозможно передать здесь имя таблицы.
CREATE PROCEDURE getLastFeatureUpdate
@maxDateTime BIGINT = 0,
@tableName nvarchar
AS
SELECT
test.FeatureNbr,
test.DayTime,
test.Val
FROM
@tableName test
WHERE
DayTime = (SELECT MAX(DayTime)
FROM @tableName
WHERE FeatureNbr = test.FeatureNbr
AND DayTime <= @maxDateTime)
Теперь появляется версия, которую я пытаюсь сделать, чтобы переписать приведенный выше код, чтобы он работал, передавая @tableName
параметр — я получаю 2 ошибки для этого кода:
System.Data.SqlClient.SQLException: ‘Необходимо объявить скалярную переменную «@maxDateTime»
EXEC sp_executesql @FullQuery
показывает ошибку:
Ошибка: процедура: [dbo].[getLastFeatureUpdate] имеет неразрешенную ссылку на объект [dbo].[sp_executesql]
Затем я задаюсь вопросом, что я могу делать неправильно в своем коде?
Переписанная хранимая процедура:
CREATE PROCEDURE getLastFeatureUpdate
@maxDateTime BIGINT = 0,
@tableName nvarchar
AS
BEGIN
DECLARE @FullQuery nvarchar(1000)
SET @FullQuery = N'SELECT test.FeatureNbr, test.DayTime, test.Val FROM ' QUOTENAME(@tableName) ' test
WHERE DayTime = ( SELECT MAX(DayTime) FROM ' QUOTENAME(@tableName) ' WHERE FeatureNbr = test.FeatureNbr AND DayTime <= @maxDateTime )'
EXEC sp_executesql @FullQuery
END
Редактировать:
C # код для выполнения хранимой процедуры:
void getLastFeatureUpdate()
{
using (SqlConnection conn = new SqlConnection(GetConnectionString()))
{
conn.Open();
// 1. create a command object identifying the stored procedure
SqlCommand cmd = new SqlCommand("getLastFeatureUpdate", conn);
// 2. set the command object so it knows to execute a stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// 3. add parameter to command, which will be passed to the stored procedure
cmd.Parameters.Add(new SqlParameter("@maxDateTime", 201010222045));
cmd.Parameters.Add(new SqlParameter("@tableName", "testTable"));
// execute the command
using (SqlDataReader rdr = cmd.ExecuteReader())
{
// iterate through results, printing each to console
while (rdr.Read())
{
Int64 v1 = (Int64)rdr["DayTime"];
int v2 = (Int16)rdr["FeatureNbr"];
double v3 = (double)rdr["Val"];
MessageBox.Show(v1 "," v2 "," v3);
}
}
}
}
Комментарии:
1. Вы должны объявить имя вашей таблицы как тип «sysname», просто к вашему сведению. «sysname» — это тип всех объектов схемы … имена таблиц, имена столбцов, имена ограничений по умолчанию, имена внешних ключей, имена индексов и т.д.
Ответ №1:
Вы должны определить и передать параметры при использовании sp_executesql
для запроса, который принимает параметры:
EXECUTE sp_executesql
@FullQuery,
N'@maxDateTime float(53)',
@maxDateTime ;
Я скажу, что использование динамического имени таблицы является признаком того, что у вас плохой дизайн таблицы, особенно когда у вас похожие данные, разделенные на несколько таблиц, а не на одну таблицу со столбцами для категоризации данных.
Комментарии:
1. Я буду жестко кодировать все, чтобы иметь уникальные имена. Это не может быть ошибкой, если я делаю это правильно. В программном обеспечении не будет никакого пользовательского ввода.
2.
AddWithValue
удобно, но, по крайней мере, с SQL Server, это плохой вариант. У этого есть нюансы, и вы находитесь в центре их влияния. Читайте: можем ли мы уже прекратить использовать AddWithValue() ? Вам нужно прочитать документацию поAdd
методам. Не просто догадывайтесь. Что касается исключения, вы внесли изменения, не поделившись ими, поэтому нет никакого способа помочь вам с этим.3. Как вам было сказано в последнем вопросе,
text
иntext
они устарели.varchar(max)
nvarchar(max)
Вместо этого используйте и . Кроме того, изменение наBIGINT
не является правильной реакцией. Измените его наDATETIME
и передайтеDateTime
значение.4. Мне сказали:
varchar or nvarchar
нетnvarchar(max)
, ноnvarchar(max)
сработало. Тогда я должен использовать это, поэтому я не используюtext
, чтобы оно было совместимо с более новыми версиями. Как я уже упоминал. Я изменил на BIGINT, чтобы найти другую актуальную проблему. Я разберусь, для чего предназначен форматDateTime
.5. Обратите внимание, что у
DateTime
типа нет формата. Строковые представления имеют формат, и вы анализируете этот форматDateTime
.