从 table 中选择下一个小于 table 元素的值
Selecting from a table the next values less than a table element
我正在使用 SQL Server 2012。我正在编写一个加权优先级队列,我正在尝试根据 table 给出的最大权重从队列中提取项目.
所以我会得到一个如下所示的 table,指定要取出的项目数和最大重量值。我想先取出较大的物品,然后再减少到较小的物品。
选择table
╔════════╦═══════════╗
║ weight ║ numValues ║
╠════════╬═══════════╣
║ 1 ║ 1 ║
║ 2 ║ 0 ║
║ 3 ║ 3 ║
╚════════╩═══════════╝
还有一个 table 看起来像这样
项目table
╔══════╦══════╦════════╗
║ item ║ val ║ weight ║
╠══════╬══════╬════════╣
║ 1 ║ fish ║ 1 ║
║ 2 ║ goat ║ 1 ║
║ 3 ║ cat ║ 1 ║
║ 4 ║ duck ║ 3 ║
║ 5 ║ pig ║ 2 ║
╚══════╩══════╩════════╝
我需要的是从 selection table 中 select 适合每个类别的具有最大权重的值。
我希望我的结果看起来像这样
结果
╔══════╦══════╦════════╗
║ item ║ val ║ weight ║
╠══════╬══════╬════════╣
║ 1 ║ fish ║ 1 ║
║ 2 ║ goat ║ 1 ║
║ 4 ║ duck ║ 3 ║
║ 5 ║ pig ║ 2 ║
╚══════╩══════╩════════╝
其中鸭子、猪、鱼满足得到3个重量3的值,山羊满足1个重量的要求。
希望这是有道理的。
我知道我可以用游标做这样的事情,但是这似乎很慢而且有点矫枉过正。我认为可以使用 CTE 来完成,但我不确定如何处理它。
感谢您的帮助。
编辑
一个解决方案
以 Jonathan 的解决方案为起点,这就是我打造的野兽。我认为应该是 "ok" 但可能不会那么快。
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 循环来正确配对 table。
有什么方法可以在 1 次或 2 次通过中得到这个东西?
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
一个解决方案
以 Jonathan 的解决方案为起点,这就是我打造的野兽。我认为应该是 "ok" 但可能不会那么快。
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 循环来正确配对 table。
有什么方法可以在 1 次或 2 次通过中得到这个东西?
我正在使用 SQL Server 2012。我正在编写一个加权优先级队列,我正在尝试根据 table 给出的最大权重从队列中提取项目.
所以我会得到一个如下所示的 table,指定要取出的项目数和最大重量值。我想先取出较大的物品,然后再减少到较小的物品。
选择table
╔════════╦═══════════╗
║ weight ║ numValues ║
╠════════╬═══════════╣
║ 1 ║ 1 ║
║ 2 ║ 0 ║
║ 3 ║ 3 ║
╚════════╩═══════════╝
还有一个 table 看起来像这样
项目table
╔══════╦══════╦════════╗
║ item ║ val ║ weight ║
╠══════╬══════╬════════╣
║ 1 ║ fish ║ 1 ║
║ 2 ║ goat ║ 1 ║
║ 3 ║ cat ║ 1 ║
║ 4 ║ duck ║ 3 ║
║ 5 ║ pig ║ 2 ║
╚══════╩══════╩════════╝
我需要的是从 selection table 中 select 适合每个类别的具有最大权重的值。
我希望我的结果看起来像这样
结果
╔══════╦══════╦════════╗
║ item ║ val ║ weight ║
╠══════╬══════╬════════╣
║ 1 ║ fish ║ 1 ║
║ 2 ║ goat ║ 1 ║
║ 4 ║ duck ║ 3 ║
║ 5 ║ pig ║ 2 ║
╚══════╩══════╩════════╝
其中鸭子、猪、鱼满足得到3个重量3的值,山羊满足1个重量的要求。
希望这是有道理的。
我知道我可以用游标做这样的事情,但是这似乎很慢而且有点矫枉过正。我认为可以使用 CTE 来完成,但我不确定如何处理它。
感谢您的帮助。
编辑 一个解决方案
以 Jonathan 的解决方案为起点,这就是我打造的野兽。我认为应该是 "ok" 但可能不会那么快。
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 循环来正确配对 table。
有什么方法可以在 1 次或 2 次通过中得到这个东西?
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
一个解决方案
以 Jonathan 的解决方案为起点,这就是我打造的野兽。我认为应该是 "ok" 但可能不会那么快。
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 循环来正确配对 table。
有什么方法可以在 1 次或 2 次通过中得到这个东西?