Скрипт T-SQL отказывается продолжать после завершения цикла построения запроса

#sql #sql-server #tsql #variables #loops

#sql #sql-server #tsql #переменные #циклы

Вопрос:

В моей базе данных есть таблица, которая автоматически записывает прогресс, день за днем. Этот скрипт … 1. Выбирает всех отдельных субподрядчиков из этой таблицы истории и вставляет их в табличную переменную. 2. Выбирает все отдельные даты в таблице истории. 3. Создает запрос в виде переменной для вставки ежедневного объема для каждого субподрядчика (изготовителя) 4. Пытается вывести на экран встроенную переменную 5. Выполняет nvarchar’d SQL (закомментирован)

 use database666
-- in-memory employee table to hold distinct PHFabricator 
DECLARE @i int;
DECLARE @f int;
DECLARE @CreateTonnageTableQuery NVARCHAR(MAX);
DECLARE @TonnageTableQuery VARCHAR(MAX);
DECLARE @CurrentTonnageQuery VARCHAR(MAX);

DECLARE @SubbsTable TABLE ( sdx int Primary Key IDENTITY(1,1), OrgID int);
DECLARE @DatesTable TABLE ( idx int Primary Key IDENTITY(1,1), History_date datetime);
INSERT @SubbsTable SELECT distinct PHFabricator FROM tblpackagehistory ORDER BY PHFabricator;
INSERT @DatesTable SELECT distinct PHHistory_Date FROM tblpackagehistory ORDER BY PHHistory_Date;

SET @CreateTonnageTableQuery = 'DECLARE @TonnageTable TABLE ([Fabricator_ID] int primary key';
SET @i = 1;
WHILE (@i <= (SELECT COUNT(*) FROM @DatesTable))
BEGIN
    SET @CreateTonnageTableQuery = @CreateTonnageTableQuery   ', ['   (SELECT 'COL' CONVERT(varchar(6),idx) FROM @DatesTable WHERE idx = @i)   '] float';
    SET @i = @i   1;
END
SET @CreateTonnageTableQuery = @CreateTonnageTableQuery   '); '   CHAR(13) CHAR(10);

DECLARE @currentSubbie int
DECLARE @currentDate datetime
SET @TonnageTableQuery = '';
SET @CurrentTonnageQuery = '';
SET @f = 0
WHILE (@f <= (SELECT COUNT(*) FROM @SubbsTable))
BEGIN
    SET @f = @f   1;
    SET @currentSubbie = (SELECT OrgID FROM @SubbsTable WHERE sdx = @f);
    SET @CurrentTonnageQuery = 'INSERT INTO @TonnageTable VALUES ('   CONVERT(varchar(6),@currentSubbie);
    SET @i = 1;
    WHILE (@i <= (SELECT COUNT(*) FROM @DatesTable))
    BEGIN
        SET @currentDate = (SELECT History_date FROM @DatesTable WHERE idx = @i); 
        SET @CurrentTonnageQuery = @CurrentTonnageQuery   ', '   
        (   SELECT CONVERT(varchar(20),(sum(PHIssued_Tonnage * PHPercent_Overall_Fabricated))) 
            FROM tblpackagehistory 
            WHERE PHFabricator = @currentSubbie AND PHHistory_Date = @currentDate           
        );
        SET @i = @i   1;
    END
    SET @CurrentTonnageQuery = @CurrentTonnageQuery   '); '   CHAR(13) CHAR(10);
    PRINT @CurrentTonnageQuery;
    SET @TonnageTableQuery = @TonnageTableQuery   @CurrentTonnageQuery;
    PRINT CHAR(13) CHAR(10)   @TonnageTableQuery   CHAR(13) CHAR(10);
END
print 'just work dammit';
print 'omg '   @TonnageTableQuery   ' omg';
print 'omfg';
--DECLARE @statement nvarchar(max);
--SET @statement = @CreateTonnageTableQuery   @TonnageTableQuery   'SELECT * FROM @TonnageTable;';
--EXEC sp_executesql @statement;
  

Подводя итог, вы заметите некоторые инструкции print по всему коду, а не только те, что ближе к концу. Все это работает, запрос строится так, как задумано, в итоге я получаю по одной строке для каждого разработчика с идентификатором разработчика и по одному столбцу тоннажа на дату в таблице истории.
Однако после последнего цикла, похоже, он не сохраняет никаких переменных данных:

 print 'just work dammit';
print 'omg '   @TonnageTableQuery   ' omg';
print 'omfg';
  

выводит:

 just work dammit

omfg
  

Где я ошибаюсь?

Комментарии:

1. SQL server оптимизирует выполнение вашего запроса, и именно от него зависит, когда выполнять разные части вашего запроса. В частности, нет гарантии, что инструкции print будут выполняться в том же порядке относительно ваших других инструкций. Это было удивительно для меня 5 лет назад, когда я обнаружил этот факт, но с тех пор он не изменился. Обходной путь заключается в включении переменной в вашу инструкцию print. В этом случае ваша инструкция print не будет выполнена до тех пор, пока значение переменной не станет доступным.

Ответ №1:

Похоже, что вы объединяете NULL и строку, которая приводит к NULL. Это приведет к распространению недействительности по всему вашему алгоритму. Вы можете использовать функцию ISNULL, чтобы заменить нулевое значение соответствующей строкой (например, пустой строкой или буквенной строкой NULL).

Значение NULL может появиться из-за выпадения из конца вашей таблицы переменных. Попробуйте изменить свой оператор WHILE на:

 WHILE (@f < (SELECT COUNT(*) FROM @SubbsTable))
  

Комментарии:

1. РЕДАКТИРОВАТЬ: Я идиот и не дочитал ваш комментарий до конца. Это была проблема, СПАСИБО! Переменная table возвращала только всю строку, кроме последней, поэтому, должно быть, она обрезала конец. Еще раз спасибо!

Ответ №2:

Перейдите в Параметры запроса и установите для CONCAT_NULL_YIELDS_NULL значение false и посмотрите, приведет ли это к получению выходных данных. Если это так, одно из ваших выражений, вероятно, принимает значение null.

ПРИМЕЧАНИЕ Я не рекомендую оставлять для него значение false, кроме как для диагностики, это параметр уровня подключения и может привести к трудным для отладки ошибкам в производственных процессах.

Комментарии:

1. Я попробовал это, и это указало мне в правильном направлении, которое заключалось в том, что моя табличная переменная обрезалась в конце цикла. Спасибо =)