Как интегрировать цикл while в SQL-запрос?(Повторение последнего результата в столбце) - PullRequest
1 голос
/ 24 марта 2019

Я пытаюсь построить запрос в SQL Server Management Studio, используя цикл while для получения окончательного столбца Result.

Допустим, у меня уже есть запрос (My_query), в котором я извлекаю следующую информацию.

Выходная выборка

My_query уже дает мне всю информацию ниже без столбца Result . Мой план состоял в том, чтобы включить цикл while, который позволял бы мне определять правильный статус для каждого Периода и ID. Логика, которую я пытался использовать, была следующей:

Declare i int = 0
Declare j int = 0
Declare buffer int = 0

With My_query as (My query code is here)

Select *,
       Result = 

 while (i <= 12) --This will be the number of rows coming from My_query.
    Begin
    set buffer = 0 -- Resetting the status variable for the next ID
        while (j <= 6) -- This will be the number of periods for every ID. Max(Block)
        Begin
            If (Block = 1 and Status_History IS NULL) -- Block = 1 always will be the higher period consulted in My_query.
                Set Result = Current_Status
                Set buffer = Result
            If (Block = 1 and Status_History IS NOT NULL)
                Set Result = Status_History
                Set buffer = Result
            If (Block <> 1 and Status_History IS NULL)
                Set Result = buffer
            If (Block <> 1 and Status_History IS NOT NULL)
                Set Result = Status_History
                Set buffer = Result
        Set j = j+1
        END
    Set i = i+1
    END
From My_query

Решение: Лучшим способом, который я нашел для решения этой проблемы, было создание индекса (помимо «блочного»), который позволяет мне определять конкретные изменения по группам. Индекс присваивает 0 значениям NULL, и каждый раз, когда значение, отличное от NULL, определяется как SUM 1 для индекса. Когда идентификатор меняется, индекс сбрасывается. Это решение намного проще в использовании ресурсов.

Индекс

SUM(CASE 
WHEN(Status_History) IS NULL THEN 0 ELSE 1 END) OVER (PARTITION BY ID ORDER BY Period DESC) AS IND

Решение

WITH DAT AS (My_query)

SELECT *,
CASE WHEN IND = 0 THEN DAT.Current_Status ELSE MAX(DAT.Status_History) OVER ( PARTITION BY DAT.ID, DAT.IND ORDER BY DAT.Period DESC) END AS Result
FROM DAT
ORDER BY ID, Period DESC 
 ID Period  Current_Status  Status_History  IND Block   Result
1012    201903  32  NULL    0   1   32
1012    201902  32  NULL    0   2   32
1012    201901  32  16  1   3   16
1012    201812  32  NULL    1   4   16
1012    201811  32  NULL    1   5   16
1012    201810  32  10  2   6   10
1012    201809  32  NULL    2   7   10
5124    201903  25  NULL    0   1   25
5124    201902  25  23  2   2   23
5124    201901  25  29  3   3   29
5124    201812  25  NULL    4   4   29
5124    201811  25  NULL    5   5   29
5124    201810  25  NULL    6   6   29
5124    201809  25  NULL    7   7   29

Спасибо всем!

Ответы [ 2 ]

1 голос
/ 24 марта 2019

На самом деле вам не нужен цикл для итерации по результирующему набору, поскольку функции в инструкции SELECT выполняются для каждой записи результата.

Вы можете использовать функции потока управления, как описано в документации MySQLстраница для обработки соответствующих данных в вашем результате.В этом вопросе stackoverflow есть несколько примеров этого 'IF' в операторе 'SELECT' - выберите выходное значение на основе значений столбца , или вы также можете использовать комбинацию различных операторов комбинации данных в MySQL

Мне удалось получить ожидаемый результат на основе предоставленного вами изображения, используя комбинацию UNION, JOIN и подзапросов.

Код


  SELECT *, mqa.Current_Status as Result 
  FROM MyQuery mqa
  WHERE 
    mqa.Block = 1 
    AND mqa.Status_History IS NULL
  UNION
  SELECT mqb.*, mqb.Status_History as Result 
  FROM MyQuery mqb
  WHERE 
    Status_History IS NOT NULL
  UNION
  SELECT mqc.ID,
       mqc.Period,
       mqc.Current_Status,
       mqc.Status_History,
       mqc.Block,
       (SELECT TOP 1 mqd.Status_History FROM MyQuery mqd
                    WHERE mqd.ID = mqc.ID
                        AND mqd.Block < mqc.Block
                        AND mqd.Status_History IS NOT NULL
                     ORDER BY Block DESC)
        FROM MyQuery mqc
                  WHERE 
                    mqc.Status_History IS NULL
                    AND mqc.Block <> 1

Результаты

|     ID | Period | Current_Status | Status_History | Block | Result |
|--------|--------|----------------|----------------|-------|--------|
| 012014 | 201710 |              5 |         (null) |     6 |      7 |
| 012014 | 201711 |              5 |              7 |     5 |      7 |
| 012014 | 201712 |              5 |         (null) |     4 |      3 |
| 012014 | 201810 |              5 |         (null) |     3 |      3 |
| 012014 | 201811 |              5 |              3 |     2 |      3 |
| 012014 | 201812 |              5 |         (null) |     1 |      5 |
| 012015 | 201710 |              2 |         (null) |     6 |     10 |
| 012015 | 201711 |              2 |         (null) |     5 |     10 |
| 012015 | 201712 |              2 |         (null) |     4 |     10 |
| 012015 | 201810 |              2 |         (null) |     3 |     10 |
| 012015 | 201811 |              2 |         (null) |     2 |     10 |
| 012015 | 201812 |              2 |             10 |     1 |     10 |

Вы можете поиграть с кодом выше в этом SQLFiddle

0 голосов
/ 26 марта 2019

Кажется, что вы возвращаетесь к первому ненулевому значению предыдущей записи, когда условие не выполняется. Теоретически это может быть результатом объединения предыдущих значений и текущих значений, ищущих первое ненулевое значение в желаемом порядке.

With My_query as (My query code is here)

SELECT i,Block,
    Result = 
        CASE WHEN (Block=1) THEN 
            COALESCE(Status_History,Current_History) 
        ELSE 
            COALESCE(Status_History, LAG(Status_History) OVER (PARTITION BY Block ORDER BY i),LAG(Current_Status) OVER (PARTITION BY Block ORDER BY i)
        END
FROM
    My_Query
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...