Как использовать цикл while в запросе select

#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 условия, поскольку имена ваших столбцов будут отличаться.