Обновление табличной переменной без дублирования данных в T- SQL - PullRequest
3 голосов
/ 28 марта 2020

У меня есть 2 табличных переменных @Items и @Locations. Обе таблицы содержат столбец объема для элементов и местоположений.

Я пытаюсь найти места с доступным объемом на единицу. Я бы хотел, чтобы это место было исключено из результатов, если у него больше нет места для хранения любого другого элемента. Цель состоит в том, чтобы обновить @Items с доступными местоположениями на основе объема и игнорировать местоположение, если он не может хранить больше элементов.

Вот T- SQL, который я написал для этого сценария:

DECLARE @Items TABLE
(
    Id INT,
    Reference NVARCHAR(255),
    Volume DECIMAL(18, 4),
    IdLocation INT
)

DECLARE @Locations TABLE
(
    Id INT,
    Reference NVARCHAR(255),
    Volume DECIMAL(18, 4)
)

INSERT INTO @Locations (Id, Reference, Volume)
    SELECT 100, 'Location 1', 50000
    UNION SELECT 101, 'Location 2', 100000
    UNION SELECT 102, 'Location 3', 300000

INSERT INTO @Items (Id, Reference, Volume)
    SELECT 1, 'Item 1', 50000
    UNION SELECT 2, 'Item 2', 50000
    UNION SELECT 3, 'Item 3', 100000
    UNION SELECT 4, 'Item 4', 100000
    UNION SELECT 5, 'Item 5', 300000
    UNION SELECT 6, 'Item 6', 300000
    UNION SELECT 7, 'Item 7', 300000

UPDATE I
SET I.IdLocation = (SELECT TOP 1 L.Id 
                    FROM @Locations L
                    WHERE L.Volume >= I.Volume)
FROM @Items I

SELECT *
FROM @Items

Результаты, которые я получаю:

NotExpectedResults

Результаты, которые я ожидаю получить:

ExpectedResults

Если у кого-то есть решение этой проблемы, я был бы очень признателен.

1 Ответ

1 голос
/ 29 марта 2020

Вероятно, есть хитрый способ сделать это, включающий оконные функции и промежуточный итог выделенного тома. Лично, когда мне приходится так распределять акции, я часто прибегаю к ал oop например

declare @Count int;

-- How many items are there to update?
select @Count = count(*) from @Items where IdLocation is null

while exists (select 1 from @Items where IdLocation is null) begin
  UPDATE I SET
    I.IdLocation = (
      SELECT TOP 1 L.Id 
      FROM @Locations L
      WHERE (L.Volume - coalesce((select sum(I1.Volume) from @Items I1 where I1.IdLocation = L.id),0)) >= I.Volume
    )
  FROM @Items I
  where I.id in (select top 1 id from @Items where IdLocation is null);

  -- Did we update any items? If not exit the loop as we have allocated all space.
  if @Count = (select count(*) from @Items where IdLocation is null) break;

  -- If so, update the new count for the next loop
  select @Count = count(*) from @Items where IdLocation is null;
end

SELECT *
FROM @Items;
...