关于组合来自两个表的数据的复杂查询
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于组合来自两个表的数据的复杂查询相关的知识,希望对你有一定的参考价值。
最近我有以下要求。有两张桌子。
-- lots of items
declare @items table(id varchar(10), pieces integer)
-- boxes
declare @boxes table(num varchar(10), capacity integer)
insert @items(id, pieces)
select 'l1', 5
union all select 'l2', 12
union all select 'l3', 8
insert @boxes(num, capacity)
select 'o1',2
union all select 'o2', 8
union all select 'o3', 2
union all select 'o4', 5
union all select 'o5', 9
union all select 'o6', 5
-- list all pairs of items-boxes. So that item will be put in what order
-- example: o1-l1, o2-l1, o2-l2, o3-l2, ...
请让我解释一下当务之急:有两张桌子。一个带有另一个带盒子的物品。我们需要通过以下方式将所有项目放入框中:
我们取第一个项目l1和第一个方框o1。项目l1有5个,盒子o1容量为2.我们只能在盒子o1中放入最多2个。所以我们创建第一行:
o1-l1
我们已经填满了o1。移动到下一个框o2。它的容量为8,我们有项目l1,剩下3件。将l1的左边部分放入框o2中,因此我们创建了第二条记录:
o2-l1
我们已将项目l1的所有部分放入框中。转到下一个项目l2。它有12件。我们在盒子o2中剩下5个容量。所以我们将5个l2放入o2并创建下一个记录:
o2-l2
然后我们按顺序选择下一个框并创建以下记录:
o3-l2
这样我们就可以生成行,直到我们将所有项目“放”到框中。生成的查询应该是这样的:
o1-l1
o2-l1
o2-l2
o3-l2
...
它可以通过CURSOR和东西在T-SQL中以必要的方式解决,这在性能上并不好。是否有任何SQL查询可以生成所需的输出?
Ilya Sh,我无法确定你自己的问题答案是否正确。但这是我的方法。
最初我认为这可以通过递归查询来解决,但是这就是所有框大小相等并且保证大于项目的位置,并且项目是不可分割的但是大小不同(因此唯一的决定与每个item是否可以打包在当前框中,或者必须进入下一个框)。
在这种情况下,我们有项目组(即指定项目类型和数量的行),其中项目大小相等但组可分割,因此每个项目组可以分布在多个框中,并且每个框可以包含多个项目组的部分,在框和项目组之间存在多对多关系。
我的想法是,每个盒子根据其容量,具有许多可以接收单个物品的单个“槽”(即一定体积的空间)。
我接近解决方案的方法是使用“数字表”将每个盒子/项目组的数量扩展到单独的盒子插槽和单个项目 - 每个盒子一行一行,每个项目一行。在我的机器上,我有一个名为zx_numbers的表 - 但是我在下面包含了代码,为了便于说明,它消除了对该表的依赖。
一旦我们以这种方式对数据进行标准化 - 通过将框扩展到各自的插槽中,并将项目组和汇总数量扩展到单个项目中 - 整个批次中的每个框插槽和项目按顺序编号,然后两者简单地连接在一起在那个序列号上。
我使用了FULL OUTER JOIN
来保存无与伦比的插槽/物品。这为我们提供了一个非常通用且适应性强的问题解决方案,然后我们可以通过各种方式进一步处理以获得我们想要的特定数据(在这种情况下,只是盒子项组组合的摘要)。
我当前编写查询的方式是,未填充空格的框(或在所有框完全填充后留下余数的项目组)将保留在结果中,并放在最后,但如果不需要,可以过滤这些框。
WITH
item_groups(item_group_id, group_qty) AS
(
select 'l1', 5
union all select 'l2', 12
union all select 'l3', 8
--union all select 'l4', 8
)
,boxes(box_id, capacity) AS
(
select 'o1',2
union all select 'o2', 8
union all select 'o3', 2
union all select 'o4', 5
union all select 'o5', 9
union all select 'o6', 5
)
,zx_numbers(zx_number) AS
(
--SELECT * FROM dbo.zx_numbers
--I have a dedicated numbers table on my machine, but I've substituted a
--manual sequence generator for the purposes of a self-contained demonstration
SELECT
(ones.n) + (10 * tens.n) + (100 * hundreds.n) AS zx_number
FROM --range 0 to 999
(VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) AS ones(n)
,(VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) AS tens(n)
,(VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) AS hundreds(n)
)
,items AS
(
SELECT
item_groups.*
,zx_number AS group_item_number
,ROW_NUMBER() OVER (ORDER BY item_group_id, zx_number) AS batch_item_number
FROM
item_groups
INNER JOIN
zx_numbers
ON (zx_number BETWEEN 1 AND item_groups.group_qty)
)
,box_slots AS
(
SELECT
boxes.*
,zx_number AS box_slot_number
,ROW_NUMBER() OVER (ORDER BY box_id, zx_number) AS batch_slot_number
FROM
boxes
INNER JOIN
zx_numbers
ON (zx_number BETWEEN 1 AND boxes.capacity)
)
,box_item_matches AS
(
SELECT
COALESCE(bxsl.batch_slot_number, itms.batch_item_number) AS slot_number
,bxsl.box_id
,bxsl.capacity
,bxsl.box_slot_number
,itms.item_group_id
,itms.group_qty
,itms.group_item_number
FROM
box_slots AS bxsl
FULL OUTER JOIN
items AS itms
ON (bxsl.batch_slot_number = itms.batch_item_number)
)
--SELECT * FROM box_item_matches
SELECT
box_id
,item_group_id
FROM
box_item_matches
GROUP BY
box_id, item_group_id
ORDER BY
IIF(box_id IS NULL OR item_group_id IS NULL, 1, 0) --i.e. NULLS LAST
,box_id
,item_group_id
以上是关于关于组合来自两个表的数据的复杂查询的主要内容,如果未能解决你的问题,请参考以下文章
LINQ to SQL:对来自订购系统的多个表的报告的聚合数据进行复杂查询