Ошибка необходимо объявить скалярную переменную

@RowFrom int

@RowTo int

are both Global Input Params for the Stored Procedure, and since I am compiling the SQL query inside the Stored Procedure with T-SQL then using Exec(@sqlstatement) at the end of the stored procedure to show the result, it gives me this error when I try to use the @RowFrom or @RowTo inside the @sqlstatement variable that is executed.. it works fine otherwise.. please help.

"Must declare the scalar variable "@RowFrom"."

Also, I tried including the following in the @sqlstatement variable:

'Declare @Rt int'
'SET @Rt = ' + @RowTo

but @RowTo still doesn’t pass its value to @Rt and generates an error.

hofnarwillie's user avatar

hofnarwillie

3,55310 gold badges48 silver badges73 bronze badges

asked Aug 24, 2011 at 20:39

bill's user avatar

1

You can’t concatenate an int to a string. Instead of:

SET @sql = N'DECLARE @Rt int; SET @Rt = ' + @RowTo;

You need:

SET @sql = N'DECLARE @Rt int; SET @Rt = ' + CONVERT(VARCHAR(12), @RowTo);

To help illustrate what’s happening here. Let’s say @RowTo = 5.

DECLARE @RowTo int;
SET @RowTo = 5;

DECLARE @sql nvarchar(max);
SET @sql = N'SELECT ' + CONVERT(varchar(12), @RowTo) + ' * 5';
EXEC sys.sp_executesql @sql;

In order to build that into a string (even if ultimately it will be a number), I need to convert it. But as you can see, the number is still treated as a number when it’s executed. The answer is 25, right?

In your case you can use proper parameterization rather than use concatenation which, if you get into that habit, you will expose yourself to SQL injection at some point (see this and this:

SET @sql = @sql + ' WHERE RowNum BETWEEN @RowFrom AND @RowTo;';

EXEC sys.sp_executesql @sql,
  N'@RowFrom int, @RowTo int',
  @RowFrom, @RowTo;

answered Aug 24, 2011 at 21:01

Aaron Bertrand's user avatar

Aaron BertrandAaron Bertrand

272k36 gold badges465 silver badges487 bronze badges

4

You can also get this error message if a variable is declared before a GOand referenced after it.

See this question and this workaround.

answered Mar 25, 2019 at 22:11

Pierre C's user avatar

Pierre CPierre C

2,76035 silver badges32 bronze badges

Just FYI, I know this is an old post, but depending on the database COLLATION settings you can get this error on a statement like this,

SET @sql = @Sql + ' WHERE RowNum BETWEEN @RowFrom AND @RowTo;';

if for example you typo the S in the

SET @sql = @***S***ql 

sorry to spin off the answers already posted here, but this is an actual instance of the error reported.

Note also that the error will not display the capital S in the message, I am not sure why, but I think it is because the

Set @sql =

is on the left of the equal sign.

answered Apr 1, 2015 at 19:13

htm11h's user avatar

htm11hhtm11h

1,7298 gold badges46 silver badges103 bronze badges

0

This is most likely not an answer to the issue itself, but this question pops up as first result when searching for Sql declare scalar variable hence I want to share a possible solution to this error.

In my case this error was caused by the use of ; after a SQL statement. Just remove it and the error will be gone.

I guess the cause is the same as @IronSean already posted in a comment above:

it’s worth noting that using GO (or in this case ;) causes a new branch where declared variables aren’t visible past the statement.

For example:

DECLARE @id int
SET @id = 78

SELECT * FROM MyTable WHERE Id = @var; <-- remove this character to avoid the error message
SELECT * FROM AnotherTable WHERE MyTableId = @var

answered Nov 5, 2020 at 16:25

ViRuSTriNiTy's user avatar

ViRuSTriNiTyViRuSTriNiTy

5,0072 gold badges31 silver badges56 bronze badges

5

Sometimes, if you have a ‘GO’ statement written after the usage of the variable, and if you try to use it after that, it throws such error. Try removing ‘GO’ statement if you have any.

answered May 24, 2021 at 6:12

Sunita Rani Nayak's user avatar

Just adding what fixed it for me, where misspelling is the suspect as per this MSDN blog…

When splitting SQL strings over multiple lines, check that that you are comma separating your SQL string from your parameters (and not trying to concatenate them!) and not missing any spaces at the end of each split line. Not rocket science but hope I save someone a headache.

For example:

db.TableName.SqlQuery(
    "SELECT Id, Timestamp, User " +
    "FROM dbo.TableName " +
    "WHERE Timestamp >= @from " +
    "AND Timestamp <= @till;" + [USE COMMA NOT CONCATENATE!]
    new SqlParameter("from", from),
    new SqlParameter("till", till)),
    .ToListAsync()
    .Result;

EBH's user avatar

EBH

10.3k3 gold badges32 silver badges59 bronze badges

answered Jun 21, 2017 at 15:46

Tim Tyler's user avatar

Tim TylerTim Tyler

2,3112 gold badges15 silver badges13 bronze badges

1

Case Sensitivity will cause this problem, too.

@MyVariable and @myvariable are the same variables in SQL Server Man. Studio and will work. However, these variables will result in a «Must declare the scalar variable «@MyVariable» in Visual Studio (C#) due to case-sensitivity differences.

answered Jun 9, 2016 at 11:20

Hans M Ohio's user avatar

Just an answer for future me (maybe it helps someone else too!). If you try to run something like this in the query editor:

USE [Dbo]
GO

DECLARE @RC int

EXECUTE @RC = [dbo].[SomeStoredProcedure] 
   2018
  ,0
  ,'arg3'
GO

SELECT month, SUM(weight) AS weight, SUM(amount) AS amount 
FROM SomeTable AS e 
WHERE year = @year AND type = 'M'

And you get the error:

Must declare the scalar variable «@year»

That’s because you are trying to run a bunch of code that includes BOTH the stored procedure execution AND the query below it (!). Just highlight the one you want to run or delete/comment out the one you are not interested in.

marc_s's user avatar

marc_s

729k175 gold badges1327 silver badges1455 bronze badges

answered Jul 21, 2019 at 18:05

saiyancoder's user avatar

saiyancodersaiyancoder

1,2752 gold badges13 silver badges20 bronze badges

If someone else comes across this question while no solution here made my sql file working, here’s what my mistake was:

I have been exporting the contents of my database via the ‘Generate Script’ command of Microsofts’ Server Management Studio and then doing some operations afterwards while inserting the generated data in another instance.

Due to the generated export, there have been a bunch of «GO» statements in the sql file.

What I didn’t know was that variables declared at the top of a file aren’t accessible as far as a GO statement is executed. Therefore I had to remove the GO statements in my sql file and the error «Must declare the scalar variable xy» was gone!

answered Oct 19, 2020 at 10:33

pbur's user avatar

pburpbur

757 bronze badges

As stated in https://learn.microsoft.com/en-us/sql/t-sql/language-elements/sql-server-utilities-statements-go?view=sql-server-ver16 , the scope of a user-defined variable is batch dependent .

—This will produce the error

 GO   
    DECLARE @MyVariable int;
    SET @MyVariable = 1;
    GO --new batch of code
    SELECT @MyVariable--CAST(@MyVariable AS 
    int);
 GO

—This will not produce the error

 GO   
   DECLARE @MyVariable int;
   SET @MyVariable = 1;
   SELECT @MyVariable--CAST(@MyVariable AS int);
 GO

We get the same error when we try to pass a variable inside a dynamic SQL:

GO
DECLARE @ColumnName VARCHAR(100),
        @SQL NVARCHAR(MAX);
SET @ColumnName = 'FirstName';
EXECUTE ('SELECT [Title],@ColumnName FROM Person.Person');  
GO

—In the case above @ColumnName is nowhere to be found, therefore we can either do:

EXECUTE ('SELECT [Title],' +@ColumnName+ ' FROM Person.Person');

or

GO
DECLARE @ColumnName VARCHAR(100),
        @SQL NVARCHAR(MAX);
SET @ColumnName = 'FirstName';
SET @SQL = 'SELECT ' + @ColumnName + ' FROM Person.Person';
EXEC sys.sp_executesql @SQL  
GO

answered Sep 15, 2022 at 10:39

Mihnea Andrei Ciorica's user avatar

Give a ‘GO’ after the end statement and select all the statements then execute

answered Dec 29, 2021 at 15:23

Srestha Chakraborty's user avatar

1

Цитата из документации Database Identifiers:

Rules for Regular Identifiers

  1. Embedded spaces or special characters are not allowed.

В именах параметров не разрешены пробелы.
Уберём из них пробелы и квадратные скобки.

Попутно исправим другие ошибки и недочёты: имя соединения (у вас оно почему-то названо connectionString), опасность потери ресурсов (используем using для устранения этого), использование устаревшего и опасного метода AddWithValue (заменим его на Add с указанием точного типа).

Кроме того, время_входаTextBox используется дважды. Будьте внимательны!

string sql = @"UPDATE Табель SET Статус = @Статус, [Код смены] = @КодСмены, [Время входа] = @ВремяВхода, [Время выхода] = @ВремяВыхода WHERE [Код сотрудника] = @КодСотрудника AND Дата = @Дата AND [Код табеля] = @КодТабеля";

using var connection = new SqlConnection(_connectionString);
connection.Open();

using var command = new SqlCommand(sql, connection);

command.Parameters.Add("КодТабеля", SqlDbType.Int).Value = textBox5.Text; // int.Parse(textBox5.Text)
command.Parameters.Add("КодСотрудника", SqlDbType.Int).Value = код_сотрудникаTextBox.Text;
command.Parameters.Add("Дата", SqlDbType.DateTime2).Value = датаDateTimePicker.Value;
command.Parameters.Add("Статус", SqlDbType.NVarChar).Value = comboBox1.Text;
command.Parameters.Add("КодСмены", SqlDbType.Int).Value = comboBox2.Text;
command.Parameters.Add("ВремяВхода", SqlDbType.DateTime2).Value = время_входаTextBox.Text;
command.Parameters.Add("ВремяВыхода", SqlDbType.DateTime2).Value = время_выходаTextBox.Text;

command.ExecuteNonQuery();

Благодаря использованию using соединение будет гарантировано закрыто, даже в случае возникновения исключения. Вызывать метод Close() не нужно.

Я не знаю, какие именно типы используются у вас в таблице, поэтому сами укажите правильные типы SqlDbType. При необходимости примените int.Parse и тому подобные методы. А лучше используйте NumericUpDown для ввода чисел вместо TextBox.

Почему не стоит использовать метод AddWithValue:
Can we stop using AddWithValue() already?
AddWithValue is evil!
AddWithValue is Evil
Достаточно прочитать любую из этих статей.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
 
--МАССОВАЯ ВСТАВКА НЕСКОЛЬКИХ ФАЙЛОВ_CSV ИЗ ПАПКИ 
--Пока что ругается на курсор
 
  
    IF (OBJECT_ID('tempdb..#csv_temp') IS NOT NULL) DROP TABLE #csv_temp;
    
    CREATE TABLE #csv_temp(
            [Times] VARCHAR (100),
            [Caller_Name] INT,
            [Caller_Number] INT,
            [Callee_Name] INT,
            [Callee_Numbers] VARCHAR(100),
            [DOD] VARCHAR(100),
            [DID] VARCHAR(100),
            [Call_Duration_(s)] INT,
            [Talk_Duration_(s)] INT,
            [STATUS] VARCHAR(100),
            [Source_Trunk] VARCHAR(50),
            [Destination_Trunk] VARCHAR(100),
            [Communication_Type] VARCHAR(100),
            [PIN_Code] VARCHAR(10),
            [Caller_IP_Address] VARCHAR(200),
            [Cost] VARCHAR(100),
            [Billing_Account] VARCHAR(100)
            ) 
 
    -- Переменые 
    DECLARE @filename VARCHAR(255),
            @path     VARCHAR(255),
            @SQL      VARCHAR(8000),
            @cmd      VARCHAR(1000),
            @Times   VARCHAR(1000), 
            @Caller_Name  INT,
            @Caller_Number INT,
            @Callee_Name INT,
            @Callee_Numbers VARCHAR(100),
            @DOD VARCHAR(100),
            @DID VARCHAR(100),
            @Call_Duration_(s)INT,
            @Talk_Duration_(s) INT,
            @STATUS VARCHAR(100),
            @Source_Trunk VARCHAR(50),
            @Destination_Trunk VARCHAR(100),
            @Communication_Type VARCHAR(100),
            @PIN_Code VARCHAR(10),
            @Caller_IP_Address VARCHAR(200),
            @Cost VARCHAR(100),
            @Billing_Account VARCHAR(100)
    --получить список файлов для обработки:
    SET @path = 'C:serg'
    SET @cmd = 'dir ' + @path + '*.csv /b'
    
    INSERT INTO #csv_temp
    (       [Times] ,
            [Caller_Name],
            [Caller_Number],
            [Callee_Name],
            [Callee_Numbers] ,
            [DOD],
            [DID],
            [Call_Duration_(s)],
            [Talk_Duration_(s)],
            [Status],
            [Source_Trunk],
            [Destination_Trunk],
            [Communication_Type],
            [PIN_Code],
            [Caller_IP_Address],
            [Cost],
            [Billing_Account]
        )
    --SELECT '17'
    VALUES (
    (SELECT [Times] FROM #csv_temp ),
    (SELECT [Caller_Name] FROM #csv_temp ),
    (SELECT [Caller_Number] FROM #csv_temp ),
    (SELECT [Callee_Name] FROM #csv_temp ),
    (SELECT [Callee_Numbers] FROM #csv_temp ),
    (SELECT [DOD] FROM #csv_temp ),
    (SELECT [DID] FROM #csv_temp ),
    (SELECT [Call_Duration_(s)] FROM #csv_temp ),
    (SELECT [Talk_Duration_(s)] FROM #csv_temp ),
    (SELECT [Status] FROM #csv_temp ),
    (SELECT [Source_Trunk] FROM #csv_temp ),
    (SELECT [Destination_Trunk] FROM #csv_temp ),
    (SELECT [Communication_Type] FROM #csv_temp ),
    (SELECT [PIN_Code] FROM #csv_temp ),
    (SELECT [Caller_IP_Address] FROM #csv_temp ),
    (SELECT [Cost] FROM #csv_temp ),
    (SELECT [Billing_Account] FROM #csv_temp )
     )
    
    EXEC Master..xp_cmdShell @cmd
    UPDATE #csv_temp SET [Times] = @path where [Times] is null
 
 
    -- Курсор
    declare c1 cursor for SELECT 
            [Times],
            [Caller_Name],
            [Caller_Number],
            [Callee_Name],
            [Callee_Numbers] ,
            [DOD],
            [DID],
            [Call_Duration_(s)],
            [Talk_Duration_(s)],
            [Status],
            [Source_Trunk],
            [Destination_Trunk],
            [Communication_Type],
            [PIN_Code],
            [Caller_IP_Address],
            [Cost],
            [Billing_Account]
 
 FROM #csv_temp where Times like '%.csv%'
 
--Открываем Курсор
    open c1
--- выборка данных
    ---fetch next from c1 into @path,@filename
 fetch next from c1 into @Times,@Caller_Name,@Caller_Number,
@Callee_Name,@Callee_Numbers,@DOD,@DID,@Call_Duration_(s),
@Talk_Duration_(s),@Status,@Source_Trunk,@Destination_Trunk,
@Communication_Type,@PIN_Code,@Caller_IP_Address,@Cost,@Billing_Account
 
 
    While @@fetch_status <> -1
      begin
      --bulk insert won't take a variable name, so make a SQL AND EXECUTE it instead:
       SET @SQL = 'BULK INSERT #csv_temp FROM ''' + @path + @filename + ''' '
           + '     WITH ( 
                   FIELDTERMINATOR = '';'', 
                   ROWTERMINATOR = ''0x0a'', 
                   FIRSTROW = 2 
                ) '
   -- Вывод результата
   print @SQL
    EXEC (@SQL)
 
   --   fetch NEXT FROM c1 INTO @path,@filename
      END
    close c1
    deallocate c1
--------------------------------------------------------------------------------------

Задача: разделить данные за сегодня и вчера по столбцам. Если использовать этот запрос без переменных то все работает. Анализ синтаксиса в excel пишет «необходимо объявить скалярную переменную @today» хотя я вроде его объявил в начале Используется MSSQL 2016

DECLARE @today as Date, @yesterday as Date;
Set @today = convert(date, getdate());
Set @yesterday = convert(date, dateadd(day, -1, getdate()));
SELECT n.Name, o.Created,
Count(DISTINCT(CASE WHEN Status =  'N' And  o.Date = @today Then ID END))  as NewQ,
Count(DISTINCT(CASE WHEN Status =  'N' And  o.Date = @yesterday Then ID END))  as YdNewQ,
Count(DISTINCT(CASE WHEN Status =  'W' And  o.Date = @today Then ID END)) as WaitingQ,
Count(DISTINCT(CASE WHEN Status =  'W' And  o.Date = @yesterday Then ID END)) as YDWaitingQ,
Count(DISTINCT(CASE WHEN Status =  'U' And  o.Date = @today Then ID END))  as ProblemQ,
Count(DISTINCT(CASE WHEN Status =  'U' And  o.Date = @yesterday Then ID END))  as YdProblemQ,
Count(DISTINCT(CASE WHEN Status =  'Z' And  o.Date = @today Then ID END))  as CancelledQ,
Count(DISTINCT(CASE WHEN Status =  'Z' And  o.Date = @yesterday Then ID END))  as YdCancelledQ

FROM Orders i 
LEFT JOIN OrderItems o ON o.OrderID = i.ID
LEFT JOIN NomenclUS m ON m.ID = o.ProductID

WHERE i.Status <> 'Z' AND o.Created >= dateadd(day, -2, getdate())

GROUP BY o.Created, n.CatID, n.CatName
ORDER BY o.Created, n.CatID

Причина, по которой вы получаете DECLARE Ошибка в вашем динамическом операторе заключается в том, что динамические операторы обрабатываются отдельными пакетами, что сводится к области видимости. Хотя может быть более формальное определение областей, доступных в SQL Server, я считаю, что достаточно иметь в виду следующие три, упорядоченные от самой высокой доступности до самой низкой доступности:

Глобальный:

Объекты, доступные для всего сервера, такие как временные таблицы, созданные с двойным знаком хеш / фунт (##GLOBALTABLE Однако вы хотели бы позвонить #). Будьте очень осторожны с глобальными объектами, так же, как с любым приложением, SQL Server или другим способом; Эти типы вещей, как правило, лучше всего избегать вообще. По сути, я говорю о том, чтобы помнить об этом как об отдельном напоминании, чтобы не вмешиваться.

IF ( OBJECT_ID( 'tempdb.dbo.##GlobalTable' ) IS NULL )
BEGIN
    CREATE TABLE ##GlobalTable
    (
        Val             BIT
    );

    INSERT INTO ##GlobalTable ( Val )
    VALUES ( 1 );
END;
GO

-- This table may now be accessed by any connection in any database,
-- assuming the caller has sufficient privileges to do so, of course.

Сессия:

Объекты, ссылки на которые привязаны к определенному спиду. На мой взгляд, единственный тип объекта сеанса, о котором я могу думать, это обычная временная таблица, определенная как #Table. Нахождение в области действия сеанса по сути означает, что после пакета (завершается GO), ссылки на этот объект будут продолжать разрешаться успешно. Они технически доступны для других сессий, но это было бы неким подвигом сделать так программно, так как они получают своего рода рандомизированные имена в базе данных tempdb, и доступ к ним в любом случае является проблемой в заднице.

-- Start of session;
-- Start of batch;
IF ( OBJECT_ID( 'tempdb.dbo.#t_Test' ) IS NULL )
BEGIN
    CREATE TABLE #t_Test
    (
        Val     BIT
    );

    INSERT INTO #t_Test ( Val )
    VALUES ( 1 );
END;
GO 
-- End of batch;

-- Start of batch;
SELECT  *
FROM    #t_Test;
GO
-- End of batch;

При открытии нового сеанса (соединение с отдельным spid) второй пакет выше не будет выполнен, так как этот сеанс не сможет решить #t_Test имя объекта

Пакет:

Нормальные переменные, такие как ваш @value1 а также @value2, предназначены только для партии, в которой они заявлены. В отличие от #Temp таблицы, как только ваш блок запроса достигает GO эти переменные перестают быть доступными для сеанса. Это уровень области, который генерирует вашу ошибку.

-- Start of session;
-- Start of batch;
DECLARE @test   BIT = 1;

PRINT @test;
GO
-- End of batch;

-- Start of batch;
PRINT @Test;  -- Msg 137, Level 15, State 2, Line 2
              -- Must declare the scalar variable "@Test".
GO
-- End of batch;

Хорошо, и что?

Что происходит здесь с вашим динамическим утверждением, что EXECUTE() Команда эффективно оценивает как отдельный пакет, не прерывая пакет, из которого вы его выполнили. EXECUTE() это хорошо и все, но с момента введения sp_executesql() Я использую первое только в самых простых случаях (явно, когда в моих высказываниях совсем мало «динамических» элементов, в первую очередь, чтобы «обмануть» иным образом неаккомодирующий DDL CREATE заявления, чтобы бежать в середине других партий). Aaron Bertrand, приведенный выше, аналогичен и по производительности будет аналогичен приведенному ниже, используя функцию оптимизатора при оценке динамических операторов, но я подумал, что стоит остановиться на @param Ну, параметр.

IF NOT EXISTS ( SELECT  1
                FROM    sys.objects
                WHERE   name = 'TblTest'
                    AND type = 'U' )
BEGIN
    --DROP TABLE dbo.TblTest;
    CREATE TABLE dbo.TblTest
    (
        ID      INTEGER,
        VALUE1  VARCHAR( 1 ),
        VALUE2  VARCHAR( 1 )
    );

    INSERT INTO dbo.TblTest ( ID, VALUE1, VALUE2 )
    VALUES ( 61, 'A', 'B' );
END;

SET NOCOUNT ON;

DECLARE @SQL    NVARCHAR( MAX ),
        @PRM    NVARCHAR( MAX ),
        @value1 VARCHAR( MAX ),
        @value2 VARCHAR( 200 ),
        @Table  VARCHAR( 32 ),
        @ID     INTEGER;

    SET @Table = 'TblTest';
    SET @ID = 61;

    SET @PRM = '
        @_ID        INTEGER,
        @_value1    VARCHAR( MAX ) OUT,
        @_value2    VARCHAR( 200 ) OUT';
    SET @SQL = '
        SELECT  @_value1 = VALUE1,
                @_value2 = VALUE2
        FROM    dbo.[' + REPLACE( @Table, '''', '' ) + ']
        WHERE   ID = @_ID;';

EXECUTE dbo.sp_executesql @statement = @SQL, @param = @PRM,
            @_ID = @ID, @_value1 = @value1 OUT, @_value2 = @value2 OUT;

PRINT @value1 + ' ' + @value2;

SET NOCOUNT OFF;

  • Ошибка необходимо наполнить аппарат krups
  • Ошибка необходимо заполнить настройки системы налогообложения
  • Ошибка необходимо заполнить password дом ру
  • Ошибка необходим файл asms
  • Ошибка необрабатываемое исключение autocad