Я новичок в SQL Server, что может быть причиной этой синтаксической ошибки.
Мой код:
CREATE PROCEDURE spBaseVoterIndex
@order_col NVARCHAR(100) ,
@order_dir NVARCHAR(20) ,
@offset ITN,
@limit INT
AS
SET NOCOUNT ON;
BEGIN
DECLARE @sql NVARCHAR(MAX)
SET @sql = 'SELECT id, name_voter, home_street_address_1, home_address_city FROM dbo.base_voter'
+' WITH(NOLOCK)'
+' ORDER BY @OC @OD'
+' OFFSET @OF ROWS'
+' FETCH NEXT @LIM ROWS ONLY'
EXECUTE sp_executesql @sql,
N'@OC nvarchar(191),@OD nvarchar(10),@OF int,@LIM int',
@OC @order_col, @OD @order_dir, @OF @offset, @LIM @limit
END
Ошибка:
Msg 102, Level 15, State 1, Procedure spBaseVoterIndex, Line 18 [Batch Start Line 0]
Incorrect syntax near '@order_col'.
Что я здесь делаю не так. Кроме того, это лучший способ выполнить динамический SQL или есть другой способ оптимизации?
Печать @SQL приводит к
SELECT id, name_voter, home_street_address_1, home_address_city
FROM dbo.base_voter WITH(NOLOCK)
ORDER BY @OC @OD
OFFSET @OF ROWS
FETCH NEXT @LIM ROWS ONLY
У меня этот код работает
SELECT id,
name_voter,
home_street_address_1,
home_address_city
FROM dbo.base_voter
WITH(NOLOCK)
WHERE deleted_at IS NULL
order by name_voter asc
OFFSET 0 ROWS
FETCH NEXT 50 ROWS ONLY
Все, что я хочу сделать динамическим, и среди них эти name_voter asc и значение смещения 0 и предельное значение 50, это 4 параметра, которые я хочу сделать динамическими.
Имеется 100 миллионов строк данных, поэтому производительность также важна.
Первое, что вы делаете неправильно, - это не распечатываете и не проверяете @sql. Это ваша первая остановка.
@slon извини, я не понимаю
Посмотрите цвет последних двух строк кода прямо перед концом
@nick Printing @sql показывает SELECT id, name_voter, home_street_address_1, home_address_city FROM dbo.base_voter WITH(NOLOCK) ORDER BY @OC @OD OFFSET @OF ROWS FETCH NEXT @LIM ROWS ONLY
Я отредактирую ваш вопрос и вставлю его - в будущем, пожалуйста, сделайте это так, поскольку тогда в вопросе будет вся информация.
Хорошо, похоже, что в вашем SQL есть некоторые синтаксические ошибки, но есть также ошибки в вашем sp_executesql , как уже указывалось.
@slon Я обновил вторую строку выполнения с помощью N'@OC @order_col,@OD @order_dir,@OF @offset,@LIM @limit'. Хотя он строит хранимую процедуру. Однако, если я попытаюсь выполнить spBaseVoterIndex 'name_voter', 'asc', 0, 50, он покажет ошибку Msg 102, Level 15, State 1, Line 22 Incorrect syntax near '@OD'. Msg 153, Level 15, State 2, Line 22 Invalid usage of the option NEXT in the FETCH statement.
Если вы проверите свой код вокруг идентификатора @order_col, как указано в ошибке, вы увидите, что отсутствует запятая. Но я не думаю, что это все равно сработает - я не думаю, что вы можете параметризовать это так





Похоже, вам не хватает запятой между @OC и @OD в строке + 'ЗАКАЗАТЬ @OC @OD'
Вы также заметили, что размер ваших параметров меняется между определением процедуры и определением динамического SQL?
Вы можете протестировать, заменив динамические параметры SQL фактическими и просто распечатав последнюю строку, а затем запустив ее.
Помимо того, что вы знаете о возможных проблемах с использованием NOLOCK (грязное чтение, фантомное чтение, дублированные данные), ваше использование выглядит допустимым.
Это необработанный запрос, который работает, SELECT id, name_voter, home_street_address_1, home_address_city FROM dbo.base_voter WITH(NOLOCK) ORDER BY name_voter asc OFFSET 0 ROWS FETCH NEXT 50 ONLY. И вы говорите, что я должен поставить запятую между name_voter и asc. Я не думаю, что это имеет смысл.
Хорошо, это не сработает. Вам нужно использовать динамический SQL, что означает, что вы объединяете переменные в строку. Вы не передаете их в sp_executesql как параметры.
Попробуй это.
CREATE PROCEDURE spBaseVoterIndex
@order_col NVARCHAR(100) ,
@order_dir NVARCHAR(20) ,
@offset INT,
@limit INT
AS
SET NOCOUNT ON;
BEGIN
DECLARE @sql NVARCHAR(MAX)
SET @sql = 'SELECT id, name_voter, home_street_address_1, home_address_city FROM dbo.base_voter'
+' WITH(NOLOCK)'
+' ORDER BY @OC @OD'
+' OFFSET @OF ROWS'
+' FETCH NEXT @LIM ROWS ONLY'
EXECUTE sp_executesql @sql,
N'@OC nvarchar(100),@OD nvarchar(20),@OF int,@LIM int',
@OC=@order_col, @OD=@order_dir, @OF=@offset, @LIM=@limit
END
Что ж, это выполняется без ошибок. Но когда я пытаюсь выполнить spBaseVoterIndex 'name_voter','asc',0,50, выдает ошибку Msg 102, Level 15, State 1, Line 21 Incorrect syntax near '@OD'. Msg 153, Level 15, State 2, Line 21 Invalid usage of the option NEXT in the FETCH statement.
Попробуйте добавить запятую между @OD и @OD в предложении ORDER BY.
Это необработанный запрос, который работает, SELECT id, name_voter, home_street_address_1, home_address_city FROM dbo.base_voter WITH(NOLOCK) ORDER BY name_voter asc OFFSET 0 ROWS FETCH NEXT 50 ONLY. И вы говорите, что я должен поставить запятую между name_voter и asc. Я не думаю, что это имеет смысл.
Я думал, что переменная @OD обозначает другой столбец. Запрос кажется нормальным и должен работать.
Вам необходимо присвоить параметры переменным для sp_executesql. (Вы уже объявили его, но не присвоили (забыли использовать знак равенства).
CREATE PROCEDURE spBaseVoterIndex
@order_col NVARCHAR(191) ,
@order_dir NVARCHAR(10) ,
@offset INT,
@limit INT
AS
SET NOCOUNT ON;
BEGIN
DECLARE @sql NVARCHAR(MAX)
SET @sql = 'SELECT id, name_voter, home_street_address_1, home_address_city FROM dbo.base_voter'
+' WITH(NOLOCK)'
+' ORDER BY @order_col @order_dir'
+' OFFSET @offset ROWS'
+' FETCH NEXT @limit ROWS ONLY'
SET @sql = REPLACE(@sql,'@order_col',@order_col)
SET @sql = REPLACE(@sql,'@order_dir',@order_dir)
SET @sql = REPLACE(@sql,'@offset',@offset)
SET @sql = REPLACE(@sql,'@limit',@limit)
EXECUTE sp_executesql @sql
END
Кстати, в нединамическом SQL OFFSET и FETCH NEXT принимают переменные INT. Итак, вы можете, например, использовать его (напрямую) следующим образом:
SELECT
id
, name_voter
, home_street_address_1
, home_address_city
FROM
dbo.base_voter
ORDER BY id
OFFSET @offset ROWS
FETCH NEXT @limit ROWS ONLY
Но это заставит вас использовать фиксированный порядок (что, кстати, не является реальной проблемой). Если вам нужно использовать порядок по, вы можете использовать метод ROW_NUMBER, примерно так:
SELECT * FROM (
SELECT
id
, name_voter
, home_street_address_1
, home_address_city
, ROW_NUMBER() OVER(ORDER BY @order_col + @order_dir) RN
FROM
base_voter
) D
WHERE
RN > @Offset
AND RN <= @Limit + @Offset
это даст вам те же результаты, что и OFFSET и FETCH NEXT
Надеюсь, когда-нибудь это будет полезно.
Это возвращает ошибку Msg 102, Level 15, State 1, Line 31 Incorrect syntax near '@OD'. Msg 153, Level 15, State 2, Line 31 Invalid usage of the option NEXT in the FETCH statement., когда я выполняю spBaseVoterIndex 'name_voter','asc',0,50
Это не работает - вы не можете параметризовать ASC таким образом. Вам нужно буквально соединить строки.
Хорошая идея - добавить санацию строк, чтобы остановить SQL-инъекцию.
CREATE PROCEDURE spBaseVoterIndex
@order_col NVARCHAR(100) ,
@descending INT,
@offset INT,
@limit INT
AS
SET NOCOUNT ON;
BEGIN
DECLARE @sql NVARCHAR(MAX)
DECLARE @OD varchar(4) = 'ASC'
-- Default is ascending. Pass in 1 to order descending
IF @descending = 1 THEN SET @OD='DESC'
-- If the order column is not valid, exit
-- You need to put a list of valid columns in here
IF @order_col NOT IN ('column1','column2','column3') RETURN
-- Finally build and run the SQL
SET @sql = 'SELECT id, name_voter, home_street_address_1, home_address_city'
+' FROM dbo.base_voter'
+' WITH(NOLOCK)'
+' ORDER BY ' + @order_col + ' ' + @OD + ' '
+' OFFSET ' + CAST(@offset AS VARCHAR(20)) + ' ROWS'
+' FETCH NEXT ' + CAST(@limit AS VARCHAR(20)) + ' ROWS ONLY'
EXEC(@sql)
END
Что касается производительности, здесь есть две части:
Разве это не будет подвержено SQL-инъекции?
Определенно
не могли бы вы подсказать, как мне поступить с описанием дела
Я только что обновил вопрос, пожалуйста, посмотрите.
Ваша одинарная кавычка находится в первой строке только в части "Выполнить"