Разбейте строку на несколько строк с максимальным значением столбца в SQL - PullRequest
0 голосов
/ 05 февраля 2019

Столбец [A] может быть любым значением, но если оно превышает 55, его необходимо разбить, чтобы ни одна строка не имела значения столбца [A], превышающего 55, и чтобы ни одно из значений не было потеряно.

Как можно достичь этой цели в SQL?

Пройдя некоторое время в поисках и пробуя разные вещи, я теряюсь.Я в основном разработчик C # и никогда не пытался сделать этот уровень логики в SQL.

select '01' as id, 65 as cnt into #temptbl 
insert into #temptbl values
 ('02',100),
 ('03',200),
 ('04',45)

insert into #temptbl
select id, cnt - 55 from #temptbl where cnt > 55

update #temptbl set cnt = 55 where cnt > 55

    select * from #temptbl order by id
    select id, sum(cnt) as newCnt from #temptbl group by id

drop table #temptbl

Допустим, у меня есть строка, в которой значение столбца [A] равно 200. Максимальное значение столбца[A] должно быть 55. Мне нужно разбить этот ряд на 4 ряда.3 строки будут иметь столбец [A] со значением 55, а последняя строка будет иметь столбец [A] со значением 35.

Ответы [ 3 ]

0 голосов
/ 05 февраля 2019

Версия без использования цикла

DECLARE @limit INT = 55;

SELECT '01' AS id, 65 AS cnt INTO #temptbl;

INSERT INTO #temptbl VALUES ('02', 100), ('03', 200), ('04', 45);

INSERT INTO #temptbl
SELECT       dupl.id
           , dupl.cnt
  FROM       #temptbl                                      AS t
 CROSS APPLY (   SELECT id
                      , @limit AS cnt
                   FROM (   SELECT ROW_NUMBER() OVER (ORDER BY S.object_id) AS row_num
                              FROM sys.all_objects AS S) AS a
                  WHERE a.row_num <= (t.cnt - 1) / @limit) AS dupl
 WHERE       t.cnt > @limit;

UPDATE #temptbl SET cnt = cnt % @limit WHERE cnt > @limit;

SELECT * FROM #temptbl ORDER BY 1, 2;

DROP TABLE #temptbl;
0 голосов
/ 05 февраля 2019

Вы также можете использовать для этого рекурсив CTE .

В примере для демонстрации используется табличная переменная.

declare @VarTable table (code varchar(2) primary key, cnt int);

insert into @VarTable (code, cnt) values
('01', 65),
('02',100),
('03',200),
('04', 45);

declare @Limit int = 55;

WITH RecursiveCTE AS
(
   SELECT code, IIF(cnt > @Limit, @Limit, cnt) AS cnt, (cnt - @Limit) AS Remaining
   FROM @VarTable

   UNION ALL

   SELECT code, IIF(Remaining > @Limit, @Limit, Remaining), (Remaining - @Limit)
   FROM RecursiveCTE
   WHERE Remaining > 0
)
SELECT code AS id, cnt
FROM RecursiveCTE
ORDER BY id, cnt DESC;

Результат:

id  cnt
--  ---
01  55
01  10
02  55
02  45
03  55
03  55
03  55
03  35
04  45
0 голосов
/ 05 февраля 2019

Кажется, я понял это:

    select '01' as id, 65 as cnt into #temptbl 
    insert into #temptbl values
    ('02',100),
    ('03',200),
    ('04',45)

    declare @temptbl2 TABLE (id  varchar(2), cnt  bigint)
    while Exists(select 1 from #temptbl where cnt > 55)
    BEGIN
        insert into @temptbl2 select id, 55 as cnt from #temptbl where cnt > 55
        update #temptbl set cnt = cnt - 55 where cnt > 55
        insert into #temptbl select * from @temptbl2
        delete from @temptbl2
    END
            select * from #temptbl order by id
            select id, sum(cnt) as newCnt from #temptbl group by id

    drop table #temptbl
...