簡體   English   中英

查詢以 1 將值從一個表分配到另一個表

[英]Query to distribute value from one table to another by 1

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

什么是設置的基本查詢,我想在哪里避免循環,或者我已經實現的遞歸 function?

這是使用 window 函數的黑客方法,特別是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;

在此處輸入圖像描述

演示

我使用的邏輯背后的想法是使用 window 函數為 B 表中的每個項目生成一個偽食品訂單,編號從 0 到食品的總數。 然后,還為 A 表中的每個人分配一個行號,然后使用此偽序列將人員與食物項進行匹配。

請注意,在我們可能想要多次迭代並將多個食物分配給每個人的情況下,我的回答不足。

你不需要循環。

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)

這是一種使用遞歸 CTE 為每個剩余水果生成包含行的表的方法。 然后它必須通過 row_number 連接到 tableA,tableA 的 row_number 有效地隨機生成:

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

Output:

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 上的演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM