Повторите строки на основе диапазона двух столбцов - PullRequest
2 голосов
/ 30 марта 2020

Я создал скрипку здесь для приведенных ниже данных и для запроса, который я пробовал.

У меня есть таблица, как показано ниже.

enter image description here

Мой ожидаемый результат такой, как показано ниже

enter image description here

Logi c:

Я должен создать отчет, как показано выше. Логика c должна повторять те же строки от начального номера до конечного номера материала. Найдите разницу, и если есть разница, повторите строки для каждого номера материала. Все остальные значения столбца останутся прежними.

Формат данных.

  1. MaterialNo будет иметь только один дефис (тип varchar)
  2. Количество символов до и после дефиса может варьироваться.
  3. Разница может go до 150.

Итак, что я пытался

WITH cte
AS (
    SELECT Materialno_start,Materialno_end,name,mtype,noofstock
        ,starts.st AS ns,ends.ed AS nd,diff.s AS d,i = 1
        ,n = convert(VARCHAR(30), starts.st)
        ,n.base AS bs
    FROM data
    CROSS APPLY (VALUES (len(Materialno_start))) leng(mn)
    CROSS APPLY (VALUES (charindex('-', Materialno_start)) ) s(hyp)
    CROSS APPLY (VALUES (substring(Materialno_start, s.hyp - leng.mn + 1, leng.mn))) n(base)
    CROSS APPLY (VALUES (substring(Materialno_start, s.hyp + 1, leng.mn)) ) starts(st)
    CROSS APPLY (VALUES (substring(coalesce(Materialno_end, Materialno_start), s.hyp + 1, leng.mn)) ) ends(ed)
    CROSS APPLY (VALUES (convert(INT, ends.ed) - convert(INT, starts.st))) diff(s)

    UNION ALL

    SELECT Materialno_start,Materialno_end,name,mtype,noofstock ,ns,nd,d,i = i + 1
        ,n = convert(VARCHAR(30), n + 1)
        ,bs
    FROM cte
    WHERE i <= d
    )
SELECT Materialno_start
    ,Materialno_end
    ,bs + n AS MaterialNo
    ,Name
    ,mtype
    ,noofstock
FROM cte
ORDER BY 1

Это дает мне необходимый вывод. Но я не уверен, что он эффективен, так как их так много CROSS APPLY, и мои производственные данные могут иметь около 70 тыс. Строк, а после разбиения могут составлять go до 120 тыс. Строк. Я хотел бы знать, может ли это быть сделано любым другим способом более эффективно или что я могу улучшить в этом запросе. У меня нет доступа к производственным данным или QA. Так что я не могу проверить это на реальных данных. Мне дали примерные данные из 100 строк, и я использовал этот запрос для получения результата.

1 Ответ

2 голосов
/ 30 марта 2020

Проще говоря, Tally выглядит следующим образом:

WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
    SELECT TOP (200)
           ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
    FROM N N1, N N2, N N3)
SELECT *
FROM Tally;

Тогда я подозреваю , что вы хотите сделать, чтобы заменить rCTe (и некоторые из Крестов применимы), было бы что-то вроде этого:

WITH N AS
    (SELECT N
     FROM (VALUES (NULL),
                  (NULL),
                  (NULL),
                  (NULL),
                  (NULL),
                  (NULL),
                  (NULL),
                  (NULL),
                  (NULL),
                  (NULL)) N (N) ),
Tally AS
    (SELECT TOP (200)
            ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
     FROM N N1,
          N N2,
          N N3),
cte AS
    (SELECT D.Materialno_start,
            D.Materialno_end,
            D.Name,
            D.MType,
            D.Noofstock,
            CONCAT(LEFT(D.Materialno_start,CHARINDEX('-',D.Materialno_start)),V.NoStart + ISNULL(T.I,0)) AS NewID
     FROM dbo.[data] D
          CROSS APPLY (VALUES(TRY_CONVERT(int,STUFF(D.Materialno_start,1,CHARINDEX('-',D.Materialno_start),'')),TRY_CONVERT(int,STUFF(D.Materialno_end,1,CHARINDEX('-',D.Materialno_end),'')))) V(NoStart,NoEnd)       
          LEFT JOIN Tally T ON T.I <= V.NoEnd - V.NoStart)
SELECT Materialno_start,
       Materialno_end,
       Materialno_start AS MaterialNo,
       Name,
       mtype,
       noofstock,
       NewID
FROM cte
ORDER BY cte.Materialno_start;
...