Запрос на распределение значения из одной таблицы в другую на 1 - PullRequest
0 голосов
/ 15 октября 2019

table A будет иметь один фуд из table B b

Table A
Name      | Value  | Food
-----------------------------
Ahmed     | 1      | 
Ali       | 83     | 
Peter     | 19     | 
Sam       | 8      | 
Sara      | 9      | 
Loyel     | 101    | 

Table B
FoodName  | Remaining
-------------------
Apple     | 3   
Mango     | 2




 Table A
Name      | Value  | Food
-----------------------------
Ahmed     | 1      | Apple
Ali       | 83     | Apple
Peter     | 19     | Apple
Sam       | 8      | Mango
Sara      | 9      | Mango
Loyel     | 101    | Null

Что такое заданный базовый запрос, где, как я хочу, чтобы избежать цикла, или рекурсивной функции, что я реализовал?

Ответы [ 3 ]

3 голосов
/ 15 октября 2019

Вам не нужен цикл.

select a.Name, a.Value, b.FoodName
from
  (select *, row_number() over(order by Name) rn
   from tabeA) a
left join
  (select *, sum(Remaining) over(order by FoodName) running_total
   from tableB) b on a.rn between b.running_total - b.Remaining + 1 and b.running_total;

Если вам нужен еще один заказ на TableA, при необходимости измените row_number() over(order by Name).

3 голосов
/ 15 октября 2019

Вот метод, использующий рекурсивный CTE для генерации таблицы со строками для каждого из оставшихся фруктов. Затем он должен быть присоединен к таблице A с помощью row_number, причем номер строки tableA фактически генерируется случайным образом:

with cte as (
select FoodName, Remaining from tableB
union all
select FoodName, Remaining - 1 from cte
where Remaining - 1 > 0)
select a.Name, a.[value], c.FoodName
from (select *,
             row_number() over (order by (select 1)) as rn
      from tableA) a
left join (select *, 
                  row_number() over (order by FoodName, Remaining) as rn
           from cte) c on c.rn = a.rn

Вывод:

Name    value   FoodName
Ahmed   1       Apple
Ali     83      Apple
Peter   19      Apple
Sam     8       Mango
Sara    9       Mango
Loyel   101     

Демонстрация на dbfiddle

Обновление

Поскольку существует столбец идентификаторов id, мы можем вместо этого упорядочить его. Измените (order by (select 1)) на (order by id) в запросе.

Демонстрация по dbfiddle

3 голосов
/ 15 октября 2019

Вот хакерский способ сделать это, используя оконные функции, в частности ROW_NUMBER:

WITH cteB AS (
    SELECT FoodName, Remaining,
        COALESCE(SUM(Remaining) OVER (ORDER BY FoodName ROWS BETWEEN UNBOUNDED PRECEDING AND PRECEDING ROW), 0) AS RemainingStart,
        SUM(Remaining) OVER (ORDER BY FoodName) RemainingEnd
    FROM TableB
),
cteA AS (
    SELECT Name, Value, ROW_NUMBER() OVER (ORDER BY Name) rn
    FROM TableA
)

SELECT
    a.Name,
    a.Value,
    b.FoodName AS Food
FROM cteA a
LEFT JOIN cteB b
    ON a.rn > b.RemainingStart AND a.rn <= b.RemainingEnd;

enter image description here

Демо

Идея, лежащая в основе логики, которую я использовал, состояла в том, чтобы с помощью оконных функций сгенерировать псевдопищевой порядок для каждого элемента в таблице B, который нумеруется от 0 до общего количества продуктов питания. Затем также назначьте номер строки каждому человеку в таблице A, а затем сопоставьте человека с продуктом питания, используя эту псевдопоследовательность.

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

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