2016-05-23 20 views
2

我有一個ms-sql表格,它看起來像這樣(weight = kg)。計算給定的一組項目(權重)所需的盒子數量

sample table

我希望能夠計算每需要一個給定的標識符盒箱數和重量。一個盒子最多可以容納30公斤。該標識符的所有項目可以在一個框中混合。我僅限於sql(2008),但一切都可以使用(CTE,函數,StoredProcs等)。我嘗試了不同的方法(CTE,函數),但我無法獲得正確的結果。任何形式的幫助表示讚賞。

預期輸出選擇時

標識符100001:

enter image description here

選擇標識符100002時:

enter image description here

選擇時標識符100003:

enter image description here

選擇標識符100004時:

enter image description here

UPDATE

試樣臺

CREATE TABLE [dbo].[tblTest](
    [position] [int] NOT NULL, 
    [item] [varchar](31) NOT NULL, 
    [quantity] [money] NOT NULL, 
    [weight] [money] NOT NULL, 
    [identifier] [varchar](50) NOT NULL, 
CONSTRAINT [PK_tblTest] PRIMARY KEY CLUSTERED 
(
    [position] ASC, 
    [identifier] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

樣本數據

INSERT [dbo].[tblTest] ([position], [item], [quantity], [weight], [identifier]) VALUES (1, N'0000001', 4.0000, 10.0000, N'100001') 
INSERT [dbo].[tblTest] ([position], [item], [quantity], [weight], [identifier]) VALUES (1, N'0000003', 3.0000, 15.0000, N'100002') 
INSERT [dbo].[tblTest] ([position], [item], [quantity], [weight], [identifier]) VALUES (1, N'0000006', 7.0000, 25.0000, N'100003') 
INSERT [dbo].[tblTest] ([position], [item], [quantity], [weight], [identifier]) VALUES (1, N'0000007', 1.0000, 1.5000, N'100004') 
INSERT [dbo].[tblTest] ([position], [item], [quantity], [weight], [identifier]) VALUES (1, N'0023021', 2.0000, 14.5000, N'100005') 
INSERT [dbo].[tblTest] ([position], [item], [quantity], [weight], [identifier]) VALUES (2, N'0000002', 1.0000, 15.0000, N'100001') 
INSERT [dbo].[tblTest] ([position], [item], [quantity], [weight], [identifier]) VALUES (2, N'0000004', 1.0000, 5.0000, N'100002') 
INSERT [dbo].[tblTest] ([position], [item], [quantity], [weight], [identifier]) VALUES (2, N'0000008', 1.0000, 2.5000, N'100004') 
INSERT [dbo].[tblTest] ([position], [item], [quantity], [weight], [identifier]) VALUES (2, N'0023022', 3.0000, 17.5000, N'100005') 
INSERT [dbo].[tblTest] ([position], [item], [quantity], [weight], [identifier]) VALUES (3, N'0000005', 3.0000, 2.5000, N'100002') 
INSERT [dbo].[tblTest] ([position], [item], [quantity], [weight], [identifier]) VALUES (3, N'0000009', 3.0000, 6.0000, N'100004') 
INSERT [dbo].[tblTest] ([position], [item], [quantity], [weight], [identifier]) VALUES (4, N'0000010', 1.0000, 1.0000, N'100004') 
+3

這是(幾乎是字面上)垃圾包裝問題。我沒有一個有效的SQL精確解決方案。 –

+2

有關裝箱問題的更多信息... https://en.wikipedia.org/wiki/Bin_packing_problem –

+0

謝謝您的提示與裝箱。目前閱讀https://gertjans.home.xs4all.nl/sql/binpacking/intro.html – Belial09

回答

0

這裏有一個選項:

在這裏看到演示:http://rextester.com/THP2733

設置:

create table tbl 
(position integer, item integer, quantity integer, weight decimal(10,2), identifier integer); 

insert into tbl 
    select 1, 1, 4, 10, 100001 union all 
    select 2, 2, 1, 15, 100001 union all 
    select 1, 3, 3, 15, 100002 union all 
    select 2, 4, 1, 5, 100002 union all 
    select 3, 5, 3, 2.5, 100002 union all 
    select 1, 6, 7, 25, 100003 union all 
    select 1, 7, 1, 1.5, 100004 union all 
    select 2, 8, 1, 2.5, 100004 union all 
    select 3, 9, 3, 6, 100004 union all 
    select 4, 10, 1, 1, 100004 ; 

查詢:

with cte(position, item, quantity, weight, identifier, cntr) 
as(select position, item, quantity, weight, identifier, quantity 
    from tbl t1 
    union all 
    select t2.position, t2.item, t2.quantity, t2.weight, t2.identifier, cte.cntr - 1 
    from tbl t2 
    join cte 
    on t2.identifier = cte.identifier 
    and t2.item = cte.item 
    and cte.cntr > 1 
) 

select 
identifier, 
sum(flg) over (partition by identifier order by item, cntr desc) package, 
case when rolling_weight - lag(rolling_weight) over (partition by identifier order by cntr desc) is NULL then rolling_weight 
    else rolling_weight - lag(rolling_weight) over (partition by identifier order by cntr desc) 
end weight 
from 
(
    select temp1.*, 
    case when rolling_weight % 30 = 0 then 1 
      when rolling_weight = total_weight then 1 
      when weight + lead(weight) over (partition by identifier order by cntr desc) > 30 then 1 
      else 0 end as flg 
    from 
    (
     select 
      cte.*, 
      sum(weight) over (partition by identifier order by item, cntr desc) rolling_weight, 
      sum(weight) over (partition by identifier) total_weight 
     from cte 
    ) temp1 
) temp2 
where flg = 1 
order by identifier, package 
+0

感謝您付出的巨大努力mo2!不幸的是,你可以在sql 2008的im問題的標籤中看到。我不想粗魯,但是有沒有機會再次看看它?根據msdn,LEAD和LAG都是MSSQL 2012。 – Belial09

+0

如果我添加這兩個例子的結果是不正確的。 選擇1,11,17.5,3,100005工會全部 選擇2,12,14。5,2,100005 結果將是然後1包與30和一個與49kg – Belial09

+0

這裏是一個樣本http://rextester.com/QSQ73630 – Belial09

相關問題