我正在使用SQL Server 2012.我正在编写一个加权优先级队列,我正在尝试根据作为表格给出的最大权重从队列中提取项目。
因此,我将获得一个类似于以下内容的表格,指定要拉出的项目数量和最大权重值。我想首先拉出较大的物品,然后再缩小较小的物品。
选择表
╔════════╦═══════════╗
║ weight ║ numValues ║
╠════════╬═══════════╣
║ 1 ║ 1 ║
║ 2 ║ 0 ║
║ 3 ║ 3 ║
╚════════╩═══════════╝
另一张看起来像这样的表
项目表
╔══════╦══════╦════════╗
║ item ║ val ║ weight ║
╠══════╬══════╬════════╣
║ 1 ║ fish ║ 1 ║
║ 2 ║ goat ║ 1 ║
║ 3 ║ cat ║ 1 ║
║ 4 ║ duck ║ 3 ║
║ 5 ║ pig ║ 2 ║
╚══════╩══════╩════════╝
我需要的是从选择表中选择适合每个类别的权重最大的值。
我希望我的结果看起来像这样
结果
╔══════╦══════╦════════╗
║ item ║ val ║ weight ║
╠══════╬══════╬════════╣
║ 1 ║ fish ║ 1 ║
║ 2 ║ goat ║ 1 ║
║ 4 ║ duck ║ 3 ║
║ 5 ║ pig ║ 2 ║
╚══════╩══════╩════════╝
鸭子,猪和鱼满足3的重量值,山羊满足1个要求的重量。
希望这是有道理的。
我知道我可以用游标做这样的事情,但是这看起来似乎很慢而且有点过分。我认为可以用CTE做到这一点,但我不确定如何处理它。
感谢您的帮助。
修改的 解决方案
使用Jonathan的解决方案作为跳跃点,这是我精心制作的野兽。我认为它应该是“好的”,但可能不那么快。
declare @selection TABLE
([item] int, [val] varchar(4), [weight] int)
;
INSERT INTO @selection
([item], [val], [weight])
VALUES
(1, 'fish', 1),
(2, 'goat', 1),
(3, 'cat', 1),
(4, 'duck', 3),
(5, 'pig', 2)
;
declare @item TABLE
([weight] int, [numValues] int)
INSERT INTO @item
([weight], [numValues])
VALUES
(1, 1),
(2, 0),
(3, 3)
declare @potentialValues TABLE([item] int, [val] varchar(4), [weight] int, queueWeight int, [rn] int)
declare @maxRows INT = (SELECT SUM(numValues) FROM @item)
declare @largestQueueItem INT = (SELECT MAX(weight) from @item where numValues > 0)
;with CTE AS (
Select
s.[weight] as itemWeight,
i.[weight] as queueWeight,
item,
val,
ROW_NUMBER() OVER (PARTITION BY i.weight ORDER BY s.weight desc) AS RN
from @selection s
FULL OUTER JOIN @item i ON s.weight <= i.weight
where i.numValues > 0)
insert into @potentialValues ([item], [val], [weight], queueWeight, [rn])
select item, val, itemweight, queueWeight, rn from CTE
Where rn <= @maxRows
Declare @currentQueueItemSize INT = @largestQueueItem
while (@currentQueueItemSize > 0)
BEGIN
DECLARE @count INT = (SELECT numValues from @item where weight = @currentQueueItemSize)
; WITH T
AS (SELECT p.*
FROM @potentialValues p
WHERE p.queueWeight = @currentQueueItemSize
ORDER BY p.rn
OFFSET @count ROWS)
DELETE FROM T
DELETE p FROM @potentialValues p
INNER JOIN @potentialValues pp
ON pp.item = p.item AND p.queueWeight < @currentQueueItemSize AND pp.queueWeight = @currentQueueItemSize
SET @currentQueueItemSize = @currentQueueItemSize - 1
END
select item, val, weight from @potentialValues order by item
好消息是我没有使用光标。坏消息是我使用带有cte和delete语句的while循环来正确配对表。
任何方式可以在1次传球中获得2次传球?
答案 0 :(得分:1)
declare @selection TABLE
([item] int, [val] varchar(4), [weight] int)
;
INSERT INTO @selection
([item], [val], [weight])
VALUES
(1, 'fish', 1),
(2, 'goat', 1),
(3, 'cat', 1),
(4, 'duck', 3),
(5, 'pig', 2)
;
declare @item TABLE
([weight] int, [numValues] int)
INSERT INTO @item
([weight], [numValues])
VALUES
(1, 1),
(2, 0),
(3, 3)
;with CTE AS (
select T.item,t.val,tt.weight,ROW_NUMBER()OVER(PARTITION BY TT.weight ORDER BY TT.weight)RN from @selection T
FULL OUTER JOIN @item TT
ON T.weight = TT.weight)
SELECT ITEM,
VAL,
COALESCE(weight,ROW_NUMBER()over(PARTITION BY weight ORDER BY item)+1,0)
FROM CTE where ITEM IS NOT NULL AND RN <= 2
答案 1 :(得分:0)
解决方案
使用Jonathan的解决方案作为跳跃点,这是我精心制作的野兽。我认为它应该是“好的”,但可能不那么快。
declare @selection TABLE
([item] int, [val] varchar(4), [weight] int)
;
INSERT INTO @selection
([item], [val], [weight])
VALUES
(1, 'fish', 1),
(2, 'goat', 1),
(3, 'cat', 1),
(4, 'duck', 3),
(5, 'pig', 2)
;
declare @item TABLE
([weight] int, [numValues] int)
INSERT INTO @item
([weight], [numValues])
VALUES
(1, 1),
(2, 0),
(3, 3)
declare @potentialValues TABLE([item] int, [val] varchar(4), [weight] int, queueWeight int, [rn] int)
declare @maxRows INT = (SELECT SUM(numValues) FROM @item)
declare @largestQueueItem INT = (SELECT MAX(weight) from @item where numValues > 0)
;with CTE AS (
Select
s.[weight] as itemWeight,
i.[weight] as queueWeight,
item,
val,
ROW_NUMBER() OVER (PARTITION BY i.weight ORDER BY s.weight desc) AS RN
from @selection s
FULL OUTER JOIN @item i ON s.weight <= i.weight
where i.numValues > 0)
insert into @potentialValues ([item], [val], [weight], queueWeight, [rn])
select item, val, itemweight, queueWeight, rn from CTE
Where rn <= @maxRows
Declare @currentQueueItemSize INT = @largestQueueItem
while (@currentQueueItemSize > 0)
BEGIN
DECLARE @count INT = (SELECT numValues from @item where weight = @currentQueueItemSize)
; WITH T
AS (SELECT p.*
FROM @potentialValues p
WHERE p.queueWeight = @currentQueueItemSize
ORDER BY p.rn
OFFSET @count ROWS)
DELETE FROM T
DELETE p FROM @potentialValues p
INNER JOIN @potentialValues pp
ON pp.item = p.item AND p.queueWeight < @currentQueueItemSize AND pp.queueWeight = @currentQueueItemSize
SET @currentQueueItemSize = @currentQueueItemSize - 1
END
select item, val, weight from @potentialValues order by item
好消息是我没有使用光标。坏消息是我使用带有cte和delete语句的while循环来正确配对表。
任何方式可以在1次传球中获得2次传球?