#sql #sql-server #count #cursor #procedure
Вопрос:
Проверьте, есть ли какие-либо заказы до указанной даты ( Date
столбец). Процедура имеет передающий параметр «дата» в качестве даты и другой передающий параметр «количество». Этот параметр возвращает количество заказов до этой даты.
Самый простой способ сделать это был бы:
SELECT COUNT([Sales].[dbo].[Order].[Date])
FROM [Sales].[dbo].[Order]
WHERE [Sales].[dbo].[Order].[Date] >= '2019-03-11'
Но, к сожалению, мне приходится использовать процедуру и курсор. Моя попытка заключается в следующем:
CREATE OR ALTER PROCEDURE OrderBeforeDate
(@date date,
@count int OUT)
AS
BEGIN
SET @count = 0;
DECLARE cursor1 SCROLL CURSOR FOR
SELECT [Sales].[dbo].[Order].[Date]
FROM [Sales].[dbo].[Order]
FOR READ ONLY
OPEN cursor1;
FETCH NEXT FROM cursor1 INTO @date
WHILE @@FETCH_STATUS = 0
BEGIN
IF @date <= '2019-03-11'
SET @count = @count 1;
END
CLOSE cursor1;
DEALLOCATE cursor1;
END
DECLARE @count int
EXEC OrderBeforeDate @count OUT
PRINT 'Number of Orders after 2019-03-11'': ' CAST(@count AS VARCHAR(10))
Но я получаю следующее сообщение об ошибке:
Столкновение типов операндов: значение int несовместимо с датой
Я не знаю, что делать. Пожалуйста, протяните мне руку помощи.
Комментарии:
1. Зачем вообще здесь использовать курсор? SQL-это язык, основанный на множествах, и в очень редких случаях вам следует его использовать.
2. Я полностью согласен с вами, но это обязательное значение по умолчанию для этого проекта.
3. Звучит как очень ошибочный проект, требующий курсора для чего-то подобного.
4. Ваша логика хранимых процедур ошибочна. У вас есть параметр даты, но вы используете его неправильно. Вы можете либо включить этот параметр в определение курсора, либо просто посчитать строки, которые он возвращает. Или вы можете оценить дату каждой строки, возвращаемой курсором, по параметру даты и увеличить ее по мере необходимости. Второй подход, который вы реализовали, требует, чтобы другая локальная переменная принимала соответствующий столбец от вашего курсора. Затем вы сравниваете свой параметр с этой локальной переменной.
5. И еще одна плохая привычка — использовать имена из 3 частей. Процедура, как правило, существует в определенной базе данных и будет ссылаться на объекты (таблицы) в той же базе данных. Использование трех имен частей означает, что для изменения имени базы данных потребуются изменения в коде. Изменения имен баз данных являются обычным явлением — не используйте имена из 3 частей без уважительной причины.
Ответ №1:
Вы не передаете ожидаемые параметры. В вашем макете я бы ожидал увидеть
DECLARE @count int=0, @Date date='20190311'
EXEC OrderBeforeDate @Date, @count OUT
PRINT 'Number of Orders after 2019-03-11: ' CAST(@count AS VARCHAR(10))
Я также хотел бы отметить (как вы, вероятно, уже знаете), что этот курсор не служит никакой другой цели, кроме как снизить производительность SQL Server.
Кроме того, ваша процедура подсчитывает строки до значения даты, в вашем print
заявлении говорится обратное.
Ответ №2:
Вероятно, вы не указали значение параметра даты при вызове процедуры OrderBeforeDate. Вы передаете только 1 аргумент, и SQL server может рассматривать значение @count как значение параметра даты.
EXEC OrderBeforeDate @count OUT
Ответ №3:
Ваша хранимая процедура ожидает 2 параметра, в то время как вы используете только один ide. Параметр даты отсутствует. Ваш курсор имеет бесконечный цикл, и процедура yoyr никогда не закончится
Использование курсора для этого-очень плохая идея, поместите свой счетчик в процедуру sored
Комментарии:
1. Пожалуйста, добавьте дополнительные сведения, чтобы расширить свой ответ, например, ссылки на рабочий код или документацию.
Ответ №4:
Спасибо за весь ваш вклад! Я думаю, что теперь это работает с таким кодом:
CREATE OR ALTER PROC OrderBeforeDate(@date date, @count int out)
AS
BEGIN
SET @count = 0;
DECLARE cursor1 scroll cursor for
SELECT [Sales].[dbo].[Order].[Date]
FROM [Sales].[dbo].[Order]
FOR READ ONLY
OPEN cursor1;
FETCH NEXT FROM cursor1 INTO @date
WHILE @@FETCH_STATUS = 0
BEGIN
IF @date < '2019-03-11'
SET @count = @count 1;
FETCH NEXT FROM cursor1 INTO @date
END
CLOSE cursor1;
DEALLOCATE cursor1;
END
DECLARE @count int
DECLARE @date date
EXEC OrderBeforeDate @date, @count OUT
PRINT 'Number of Orders before 2019-03-11: ' CAST(@count AS VARCHAR(10))
Вы правы, что этот метод намного медленнее, чем тот, о котором я упоминал в первую очередь. (1 минута против менее чем секунды)
Спасибо всем за вашу помощь!