Можно ли продублировать строку на основе значения столбца и изменить другое значение столбца? - PullRequest
0 голосов
/ 28 мая 2019

У меня есть таблица со столбцом INT времени в секундах, другой столбец с типом этой записи и внешним идентификатором.

Я хочу выбрать одну и ту же строку, повторяемую каждый раз, когда ее строка секунд больше X, и в первой строке она сохраняет X секунд с типом 1, а во второй строке показывает оставшиеся секунды (секунды - X, до X) с типом 2. То же самое с Y. Не более 3 строк. Таким образом, строка 1 - до x, строка 2 - до Y, а строка 3 - Y + 1 и более

Например:

Х = 5. Y = 9. Я хочу это:

| id | type | seconds |
|----|------|---------|
|  1 |  10  |   19    |
|  2 |  10  |   12    |
|  3 |  10  |    7    |

чтобы стать таким:

| id | type | seconds |
|----|------|---------|
|  1 |   1  |    5    |
|  1 |   2  |    4    |
|  1 |   3  |   10    |
|  2 |   1  |    5    |
|  2 |   2  |    4    |
|  2 |   3  |    3    |
|  3 |   1  |    5    |
|  3 |   2  |    2    |

Это возможно?

Я видел решения этого (синтаксиса) исключительно для оракула. Но как мне сделать это в SQL Server?

Редактировать: только для этого идентификатора типа (в примере 10), оставляя другие без изменений.

Ответы [ 2 ]

1 голос
/ 28 мая 2019

Это не очень красиво, но делает свое дело.Для дублирования строк мы используем подсчетные таблицы.В этом случае я использовал жестко закодированный только с 3 рядами.Затем сделали расчеты на его основе.Возможно, есть более простой способ его кодирования, но я сегодня не в лучшем виде.

--Creating sample data
CREATE TABLE SampleData(
    id      int,
    [type]  int,
    seconds int
);

INSERT INTO SampleData
VALUES
( 1, 10, 19),
( 2, 10, 12),
( 3, 10,  7),
( 4, 10, 5),
( 5, 10,  3);
GO

--Actual solution
DECLARE @X int = 5;

WITH CTE AS(
    SELECT id,
        CASE WHEN [type] =  10 THEN n ELSE [type] END AS [type],
        CASE WHEN [type] <> 10 THEN seconds
             WHEN n = 1 AND seconds > @X THEN @X
             WHEN n = 1 AND seconds <= @X THEN seconds
             WHEN n = 2 AND seconds - @X >= @X THEN @X-1
             WHEN n = 2 AND seconds - @X > 0 THEN seconds - @X
             WHEN n = 3 AND seconds > @X*2-1 THEN seconds - (@X*2-1)
             END AS seconds
    FROM SampleData
    CROSS JOIN( VALUES(1),(2),(3))AS x(n)
    WHERE [type] = 10 OR n = 1
)
SELECT *
FROM CTE
WHERE seconds IS NOT NULL;
0 голосов
/ 28 мая 2019

Для задач такого типа мне нравится использовать рекурсивный CTE .Заимствовал дополнительные тестовые случаи от @Luis Cazares.Также добавлены тестовые примеры для типа 15, о котором вы упоминали в комментариях.В приведенном ниже решении вы можете поменять местами значения X и Y, и он будет рассчитан соответственно.

CREATE TABLE #TestData
(
    id INT
    , type INT
    , seconds int
);

INSERT INTO #TestData VALUES
(1, 10, 19)
, (2, 10, 12)
, (3, 10, 7)
, (4, 10, 5)
, (5, 10, 3)
, (6, 15, 54)
, (7, 15, 8);

DECLARE 
    @X INT = 5
    , @Y INT = 9;

SET @Y = @Y - @X;

WITH CTE AS
(
    SELECT id, CASE WHEN type = 10 THEN 0 ELSE type END AS type, seconds, seconds AS ov 
    FROM #TestData
    UNION ALL
    SELECT 
        id
        , type + 1
        , CASE
            WHEN type = 0 THEN seconds - @X
            WHEN type = 1 THEN seconds - @Y
            WHEN type = 2 THEN seconds
            END
        , ov
    FROM CTE
    WHERE seconds > 0
)

SELECT
    id
    , type
    , CASE
        WHEN type = 1 AND seconds > 0 THEN @X
        WHEN type = 2 AND seconds > 0 THEN @Y
        WHEN type = 2 AND seconds < 0 THEN ov - @X
        WHEN type = 3 AND seconds > 0 THEN seconds
        ELSE ov
        END
FROM CTE
WHERE type <> 0 AND CTE.seconds IS NOT NULL
ORDER BY id, type

DROP TABLE #TestData;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...