#sql #sql-server #loops
Вопрос:
Я пытаюсь создать хранимую процедуру, которая возвращает результаты, основанные на вводе данных пользователем. Допустим, пользователь выбирает начальный год 2016 и конечный год 2018, хранимая процедура будет циклически повторять эти годы, чтобы вернуть результаты. Однако для этого мне нужно только выбрать, чтобы просмотреть несколько столбцов.
Например, я ищу что-то похожее на логику, лежащую в основе приведенного ниже.
SELECT column A, column B WHILE (@CurrentYr lt;= @MaxYr) BEGIN ,CASE WHEN(Year = @CurrentYr THEN, columnC) SET @CurrentYr = @CurrentYr 1 END FROM Table1
что вернет столбцы
ColumnA, ColumnB, 2016's ColumnC, 2017's ColumnC, 2018's Column8
Возможно ли это?
Спасибо
Комментарии:
1.Вы не можете использовать оператор
WHILE
внутри оператора; это оператор логического потока. Похоже, настоящая проблема в том, что у вас денормализованный дизайн и есть столбец для каждого года. Если вы исправите свой дизайн, у вас не будет этой проблемы. Если вы этого не сделаете, то вам нужно будет перейти к динамическому подходу SQL; что просто делает вещи намного сложнее, чем они должны быть.2. @Larnu Я думаю, что на самом деле у них нормализованный дизайн, но они пытаются создать денормализованный вывод. Им нужна новая колонка для каждого года в результате.
3. Похоже, вам нужно заглянуть в динамическую перекрестную вкладку, чтобы выполнить то, что вы хотите здесь. Я могу помочь вам, если вы сможете опубликовать некоторые расходные данные и желаемый результат.
4. Возможно, @SeanLange . Без значимых выборочных данных и ожидаемых результатов очень трудно узнать. Даже если это так, ему все равно понадобится динамический SQL, который, как я бы предположил, является путем, по которому операция не идет. Если им нужен динамический разворот, им было бы (на мой взгляд) лучше сделать это на уровне представления/отчетности.
Ответ №1:
Вот пример кода, который создает временную таблицу «#MyTemp» с базовыми столбцами, а затем содержит цикл для добавления дополнительных столбцов за годы на основе переменных текущего года и максимального года. После добавления каждого столбца с помощью динамического SQL вы можете обновить этот столбец данными, используя дополнительный динамический SQL.
DECLARE @YearCurrent int DECLARE @YearMax int DECLARE @YearCounter INT DECLARE @ColumnName VARCHAR(20) DECLARE @Sql varchar(100) SELECT @YearCurrent = 2018 SELECT @YearMax = 2021 SELECT SettingID AS ColumnA, SettingValue AS ColumnB INTO #MyTemp FROM ApplicationSetting SELECT @YearCounter = @YearCurrent WHILE @YearCounter lt;= @YearMax BEGIN SELECT @ColumnName = 'Year_' CAST(@YearCounter AS VARCHAR(20)) SELECT @SQL = 'ALTER TABLE #MyTemp ADD [' @ColumnName '] VarChar(100) NULL ' PRINT @SQL EXEC ( @SQL ) SELECT @SQL = 'UPDATE #MyTemp SET ' @ColumnName '= OrderHeader.SomeColumn FROM OrderHeader WHERE #MyTemp.ColumnA = OrderHeader.ColumnA' PRINT @SQL EXEC ( @SQL ) SELECT @YearCounter = @YearCounter 1 END SELECT * FROM #MyTemp
Я не уверен, что вы хотите поместить в столбцы года, но заявление об обновлении дает вам основную идею, и вы можете настроить заявление об обновлении по мере необходимости.
Ответ №2:
Вы не можете использовать WHILE
в SELECT
инструкции. Однако вот шаблон, который может помочь вам создать динамичный:
DECLARE @CurrentYr int = 2019, @MaxYr int = 2021, @sql varchar(MAX); SELECT @sql = 'SELECT columnA, columnB, ' ( SELECT STRING_AGG ( CASE YearIncrement WHEN 0 THEN CONCAT ( 'columnC AS Year_', @CurrentYr YearIncrement ) WHEN 1 THEN CONCAT ( 'columnD AS Year_', @CurrentYr YearIncrement ) WHEN 2 THEN CONCAT ( 'columnE AS Year_', @CurrentYr YearIncrement ) -- WHEN...etc END , ', ' ) AS cols FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL ) ) - 1 AS YearIncrement FROM STRING_SPLIT ( ( SELECT REPLICATE ( ',', @MaxYr - @CurrentYr ) ), ',' ) ) AS x ) ' FROM Table1;'; PRINT @sql;
С принтами
SELECT columnA, columnB, columnC AS Year_2019, columnD AS Year_2020, columnE AS Year_2021 FROM Table1;
С помощью комбинации
REPLICATE
(создает список запятых на основе разницы в годах)STRING_SPLIT
(разбивает указанный список запятых на строки)ROW_NUMBER
(предоставляет число (-1, чтобы начать приращение с нуля) для добавления в каждый год по указанным строкам)STRING_AGG
(объединяет их все обратно в список, разделенный запятыми)
мы можем создать динамическую инструкцию SQL, которая может быть выполнена. К сожалению, я не знаю, как обойти эти CASE
условия, поскольку имена ваших столбцов будут отличаться.