htl258 请进 专家级高效SQL语句(500分)(第四贴共五贴)

dongdongxiao 2010-06-05 10:26:37
接上贴
http://topic.csdn.net/u/20100604/11/c7715bbb-95a3-4124-845b-a3358c115d93.html

希望不用游标,解决以下问题(本人花了两天没有解决,搜索了网络也没有找到解决方法)。解决后另外开贴给分。(此为第三贴共五贴,每贴100分,解决问题后一起结贴)

tb_a
owner skuid lot quality vol_exchange mysort
78 1000164481 071203 0 70.00 1
78 1000164481 071202 0 0.00 2
78 1000164479 081203 0 30.00 3
78 1000164479 081202 0 20.00 4
78 1000164479 081201 0 10.00 5

tb_b
owner skuid lot quality vol_exchange mysort
01 1000164479 091201 0 6.00 6
04 1000164481 091201 0 0.00 5
03 1000164479 091201 0 26.00 4
02 1000164479 091201 0 28.00 3
08 1000164481 091201 0 0.00 2
06 1000164481 091201 0 70.00 1

tb_a中的skuid与tb_b中的skuid要匹配
现有多个公司间出库时指定批号,出库完成后互相换批号以满足到批号的库存进销匹配。
tb_a是换出的批号表,tb_b是从其他公司换入的批号。

现在希望能得出到明细的换货记录。
owner_a owner_b skuid in_lot out_lot vol_exchange
78 06 1000164481 091201 071203 70 (tb_a中skuid:1000164481 lot:071203 换出70,tb_b中skuid:1000164481 lot:091201换入70,注意skuid必须匹配)
78 02 1000164479 091201 081203 28 (tb_a中skuid:1000164479 lot:081203 换出28,tb_b中skuid:1000164479 lot:091201换入28,注意skuid必须匹配,以下类似)
78 03 1000164479 091201 081203 2
78 03 1000164479 091201 081202 20
78 03 1000164479 091201 081201 4
78 01 1000164479 091201 081201 6

网友i9998 和playwarcraft都给出了以下解决方法。(当然i9998先于playwarcraft)
SQL code

select * from
(
select a.owner as owner_a,b.owner as owner_b,b.skuid,b.lot as in_lot,a.lot as out_lot,
case when a.v2+b.V2<=0 then
case when a.v2+b.V1<=a.vol_exchange then a.v2+b.V1 else a.vol_exchange end
else case when -(a.v1+b.V2)<= -b.vol_exchange then -(a.v1+b.V2) else -b.vol_exchange end
end as vol_exchange
from
(select top 100 percent * ,isnull((select sum(vol_exchange) from tb_a where mysort<A.mysort and vol_exchange>0),0) as V1,
isnull((select sum(vol_exchange) from tb_a where mysort<=A.mysort and vol_exchange>0),0) as V2
from tb_a A
where vol_exchange>0
order by mysort) as A,
(select top 100 percent owner,skuid,lot,quality,vol,-vol_exchange as vol_exchange,mysort ,-isnull((select sum(vol_exchange) from tb_b where mysort<B.mysort and vol_exchange>0),0) as V1,
-isnull((select sum(vol_exchange) from tb_b where mysort<=B.mysort and vol_exchange>0),0) as V2
from tb_b B
where vol_exchange>0
order by mysort) as B
where a.V2+b.V1>=0 and a.V1+b.V2<=0
and a.skuid=b.skuid
) X
where vol_exchange>0




A表
select * ,isnull((select sum(vol_exchange) from tb_a where mysort<A.mysort and vol_exchange>0),0) as V1,
isnull((select sum(vol_exchange) from tb_a where mysort<=A.mysort and vol_exchange>0),0) as V2
from tb_a A
where vol_exchange>0
order by mysort

==============================================================================
owner skuid lot quality vol vol_exchange mysort V1 V2
78 1000164481 071203 0 80.00 70.00 1 0.00 70.00
78 1000164479 081203 0 30.00 30.00 3 70.00 100.00
78 1000164479 081202 0 20.00 20.00 4 100.00 120.00
78 1000164479 081201 0 10.00 10.00 5 120.00 130.00



V1是按mysort排序后到本行之前(不含本行)的vol_exchange累计
V2是按mysort排序后到本行之前的(含本行)vol_exchange累计

B表
select owner,skuid,lot,quality,vol,-vol_exchange as vol_exchange,mysort ,-isnull((select sum(vol_exchange) from tb_b where mysort<B.mysort and vol_exchange>0),0) as V1,
-isnull((select sum(vol_exchange) from tb_b where mysort<=B.mysort and vol_exchange>0),0) as V2
from tb_b B
where vol_exchange>0
order by mysort

==============================================================================
owner skuid lot quality vol vol_exchange mysort V1 V2
06 1000164481 091201 0 80.00 -70.00 1 0.00 -70.00
02 1000164479 091201 0 28.00 -28.00 3 -70.00 -98.00
03 1000164479 091201 0 26.00 -26.00 4 -98.00 -124.00
01 1000164479 091201 0 18.00 -6.00 6 -124.00 -130.00

V1是按mysort排序后到本行之前(不含本行)的 - vol_exchange累计
V2是按mysort排序后到本行之前的(含本行)- vol_exchange累计


select a.owner as owner_a,b.owner as owner_b,b.skuid,b.lot as in_lot,a.lot as out_lot,
case when a.v2+b.V2<=0 then
case when a.v2+b.V1<=a.vol_exchange then a.v2+b.V1 else a.vol_exchange end
else case when -(a.v1+b.V2)<= -b.vol_exchange then -(a.v1+b.V2) else -b.vol_exchange end
end as vol_exchange
from A,B
where a.V2+b.V1>=0 and a.V1+b.V2<=0 and a.skuid=b.skuid

为什么条件要这样写?这样写是什么意思? 谢谢!
...全文
170 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
永生天地 2010-06-07
  • 打赏
  • 举报
回复


if object_id('tb_a') is not null drop table tb_a
go
create table tb_a
( owner char(2) null,
skuid varchar(10) null,
lot varchar(50) null,
quality varchar(2) null,
vol decimal(18,2) null,
vol_exchange decimal(18,2) null,
mysort int
)
if object_id('tb_b') is not null drop table tb_b
go
create table tb_b
( owner char(2) null,
skuid varchar(10) null,
lot varchar(50) null,
quality varchar(2) null,
vol decimal(18,2) null,
vol_exchange decimal(18,2) null,
mysort int
)
set nocount on
INSERT INTO tb_a(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '78 ', '1000164481 ', '071203 ', '0 ',80.00,70.00,1)
INSERT INTO tb_a(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '78 ', '1000164481 ', '071202 ', '0 ',60.00,0.00,2)
INSERT INTO tb_a(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '78 ', '1000164481 ', '081203 ', '0 ',30.00,30.00,3)
INSERT INTO tb_a(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '78 ', '1000164481 ', '081202 ', '0 ',20.00,20.00,4)
INSERT INTO tb_a(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '78 ', '1000164481 ', '081201 ', '0 ',10.00,10.00,5)

INSERT INTO tb_b(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '01 ', '1000164479 ', '091201 ', '0 ',18.00,6.00,6)
INSERT INTO tb_b(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '04 ', '1000164481 ', '091201 ', '0 ',20.00,0.00,5)
INSERT INTO tb_b(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '03 ', '1000164479 ', '091201 ', '0 ',26.00,26.00,4)
INSERT INTO tb_b(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '02 ', '1000164479 ', '091201 ', '0 ',28.00,28.00,3)
INSERT INTO tb_b(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '08 ', '1000164481 ', '091201 ', '0 ',60.00,0.00,2)
INSERT INTO tb_b(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '06 ', '1000164481 ', '091201 ', '0 ',80.00,70.00,1)
set nocount off
GO


--这段我简单看了一下阿,因为我也写过,只是写法不同,但是思路完全相同。但是很难理解

select * from
(
select a.owner as owner_a,b.owner as owner_b,b.skuid,b.lot as in_lot,a.lot as out_lot,
case when a.v2<=b.V2 then --当前B提供总数多与A的需要数量时
case when a.v2-b.V1<=a.vol_exchange -- B的剩余 <= 当前A的需要 显示B可提供的值,否则显示A的数量
then a.v2-b.V1 else a.vol_exchange end
else b.V2 - a.v1 --当前B可提供的和不能满足A的数量时,显示可以提供的数量
end as vol_exchange,
a.mysort asort,b.mysort bsort
from
(select top 100 percent * ,
isnull((select sum(vol_exchange) from tb_a where mysort<A.mysort and vol_exchange>0),0) as V1, --求出当前行之前所有需要分配的数量总合
isnull((select sum(vol_exchange) from tb_a where mysort<=A.mysort and vol_exchange>0),0) as V2 --求出到当前行所有需要分配的数量总合
from tb_a A
where vol_exchange>0
order by mysort) as A,
(select top 100 percent owner,skuid,lot,quality,vol,vol_exchange as vol_exchange,mysort ,
isnull((select sum(vol_exchange) from tb_b where mysort<B.mysort and vol_exchange>0),0) as V1,--求出当前行之前所有可以分配的数量总合
isnull((select sum(vol_exchange) from tb_b where mysort<=B.mysort and vol_exchange>0),0) as V2 --求出到当前行所有可以分配的数量总合
from tb_b B
where vol_exchange>0
order by mysort) as B

--这两个条件和在一起就是,当前A的所有vol_exchange的和要小于等于当前B提供的vol_exchange的和,但一定要大于等于B当前行之前所有vol_exchange的和

where a.V2>=b.V1 --这里就是当前需要分配总数 要大于等于 可提供的数数量(并且是不包含当前那个tb_b的可提供的数量(在第二个条件上判断包括当前B的和),刚好分配到B的最后一个或是倒数第二个合适的数据)
and a.V1<=b.V2 --这里判断B是否可以为A提供数据进行分配,V1是A可以分配的那行前所有 vol_exchange的和。也就是当前提供一定要满足为A当前行之前所有行的和,才能为当前A提供数据,当然这里有等号,包含了一些重复数据(即可以提供的数据是0的数据,这个是在最外层的select里除去)
/*
执行:

A=70
70 >= 0 and 0<= 70 (总需求 70 ,之前需求 0 ,符合但提供数据值为 70 );;2: 70>=70 and 0<=98;3: 70>=98 and 0<=124
A=30
100>=0 and 70<=70 (总需求 100 ,之前需求 70 ,符合但提供数据值为 0 ); 100>=70 and 70<=98 (总需求 100 ,之前需求 70 ,符合提供数据值为 28 );100>=98 and 70<=124 100>=124 and 70<=98
A=20
120>=0 and 124<=70 ...120>=98 and 100<=124 (总需求 100 ,之前需求 70 ,符合提供数据值为 20 );
......
*/
) X
where vol_exchange>0
order by asort,bsort

/*
owner_a owner_b skuid in_lot out_lot vol_exchange asort bsort
------- ------- ---------- -------------------------------------------------- -------------------------------------------------- ---------------------------------------- ----------- -----------
78 06 1000164481 091201 071203 70.00 1 1
78 02 1000164479 091201 081203 28.00 3 3
78 03 1000164479 091201 081203 2.00 3 4
78 03 1000164479 091201 081202 20.00 4 4
78 03 1000164479 091201 081201 4.00 5 4
78 01 1000164479 091201 081201 6.00 5 6

(所影响的行数为 6 行)

*/
dongdongxiao 2010-06-07
  • 打赏
  • 举报
回复
谢谢大家,再开一贴放分,请playwarcraf和htl258来接分,再次谢谢!

下贴
http://topic.csdn.net/u/20100607/11/29dc1dd9-fe2c-4a35-b699-046e2e1cf8c3.html
htl258_Tony 2010-06-07
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 dongdongxiao 的回复:]
引用 14 楼 htl258 的回复:

引用 13 楼 dongdongxiao 的回复:
引用 3 楼 htl258 的回复:

SQL code
那段代码跑出来的结果就以下那条,是对的吗?

owner_a owner_b skuid in_lot out_lot vol_exchange
------- ------- --------……


执行结果应该是:
……
[/Quote]OK,祝贺你了却一桩心事
dongdongxiao 2010-06-07
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 htl258 的回复:]

引用 13 楼 dongdongxiao 的回复:
引用 3 楼 htl258 的回复:

SQL code
那段代码跑出来的结果就以下那条,是对的吗?

owner_a owner_b skuid in_lot out_lot vol_exchange
------- ------- --------……


执行结果应该是:
owner_a owner_b skuid ……
[/Quote]

playwarcraft 的代码是正确的。(请参见第9楼),谢谢!
dongdongxiao 2010-06-07
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 playwarcraft 的回复:]

假如有 品种X 的100的库存,以下为需求
id 品种 需求 可分配数量
1 X 30 ? --30
2 X 50 ? --50
3 X 60 ? --20
4 X 20 ? ……
[/Quote]

非常感谢
htl258_Tony 2010-06-07
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 dongdongxiao 的回复:]
引用 3 楼 htl258 的回复:

SQL code
那段代码跑出来的结果就以下那条,是对的吗?

owner_a owner_b skuid in_lot out_lot vol_exchange
------- ------- --------……


执行结果应该是:
owner_a owner_b skuid in_lot out_lot vol_exchange
……
[/Quote]
这么说来,代码出来的结果还是错的是吗?
dongdongxiao 2010-06-07
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 htl258 的回复:]

SQL code
那段代码跑出来的结果就以下那条,是对的吗?

owner_a owner_b skuid in_lot out_lot vol_exchange
------- ------- --------……
[/Quote]

执行结果应该是:
owner_a owner_b skuid in_lot out_lot vol_exchange
78 01 1000164479 091201 081201 6.00
78 03 1000164479 091201 081203 2.00
78 03 1000164479 091201 081202 20.00
78 03 1000164479 091201 081201 4.00
78 02 1000164479 091201 081203 28.00
78 06 1000164481 091201 071203 70.00
feixianxxx 2010-06-07
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 happyflystone 的回复:]

代码是挤 出来的
[/Quote]

一定要有沟沟么。。

没有还能挤出这么强大的代码么。。
playwarcraft 2010-06-07
  • 打赏
  • 举报
回复
假如有 品种X 的100的库存,以下为需求
id 品种 需求 可分配数量
1 X 30 ? --30
2 X 50 ? --50
3 X 60 ? --20
4 X 20 ? --0

解类似的方式

declare @inv int
set @inv=100

Update A
set qty = case when (select sum(需求) from T where 品种=A.品种 and id<=A.id) <= @inv
then 需求
else case when isnull((select sum(需求) from T where 品种=A.品种 and id<A.id),0) <=@inv
then @inv - isnull((select sum(需求) from T where 品种=A.品种 and id<A.id),0)
else 0 end
end
from T as A


同理
V1,V2 就是上述中的case when 中的2种情况 ,在id<=A.id时,有没有这个=的问题,想通了就OK了
-狙击手- 2010-06-07
  • 打赏
  • 举报
回复
代码是挤 出来的
playwarcraft 2010-06-07
  • 打赏
  • 举报
回复

create table tb_a
( owner char(2) null,
skuid varchar(10) null,
lot varchar(50) null,
quality varchar(2) null,
vol decimal(18,2) null,
vol_exchange decimal(18,2) null,
mysort int
)

create table tb_b
( owner char(2) null,
skuid varchar(10) null,
lot varchar(50) null,
quality varchar(2) null,
vol decimal(18,2) null,
vol_exchange decimal(18,2) null,
mysort int
)

INSERT INTO tb_a(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '78 ', '1000164481', '071203 ', '0 ',80.00,70.00,1)
INSERT INTO tb_a(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '78 ', '1000164481', '071202 ', '0 ',60.00,0.00,2)
INSERT INTO tb_a(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '78 ', '1000164479', '081203 ', '0 ',30.00,30.00,3)
INSERT INTO tb_a(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '78 ', '1000164479', '081202 ', '0 ',20.00,20.00,4)
INSERT INTO tb_a(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '78 ', '1000164479', '081201 ', '0 ',10.00,10.00,5)

INSERT INTO tb_b(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '01 ', '1000164479', '091201 ', '0 ',18.00,6.00,6)
INSERT INTO tb_b(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '04 ', '1000164481', '091201 ', '0 ',20.00,0.00,5)
INSERT INTO tb_b(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '03 ', '1000164479', '091201 ', '0 ',26.00,26.00,4)
INSERT INTO tb_b(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '02 ', '1000164479', '091201 ', '0 ',28.00,28.00,3)
INSERT INTO tb_b(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '08 ', '1000164481', '091201 ', '0 ',60.00,0.00,2)
INSERT INTO tb_b(owner,skuid,lot,quality,vol,vol_exchange,mysort)
VALUES ( '06 ', '1000164481', '091201 ', '0 ',80.00,70.00,1)

GO

select * from
(
select a.owner as owner_a,b.owner as owner_b,b.skuid,b.lot as in_lot,a.lot as out_lot,
case when a.v2+b.V2<=0 then
case when a.v2+b.V1<=a.vol_exchange then a.v2+b.V1 else a.vol_exchange end
else case when -(a.v1+b.V2)<= -b.vol_exchange then -(a.v1+b.V2) else -b.vol_exchange end
end as vol_exchange
from
(select top 100 percent * ,isnull((select sum(vol_exchange) from tb_a where skuid =A.skuid and mysort<A.mysort and vol_exchange>0),0) as V1,
isnull((select sum(vol_exchange) from tb_a where skuid=A.skuid and mysort<=A.mysort and vol_exchange>0),0) as V2
from tb_a A
where vol_exchange>0
order by mysort) as A,
(select top 100 percent owner,skuid,lot,quality,vol,-vol_exchange as vol_exchange,mysort ,-isnull((select sum(vol_exchange) from tb_b where skuid =B.skuid and mysort<B.mysort and vol_exchange>0),0) as V1,
-isnull((select sum(vol_exchange) from tb_b where skuid=B.skuid and mysort<=B.mysort and vol_exchange>0),0) as V2
from tb_b B
where vol_exchange>0
order by mysort) as B
where a.V2+b.V1>=0 and a.V1+b.V2<=0
and a.skuid=b.skuid
) X
where vol_exchange>0

/*
78 06 1000164481 091201 071203 70.00
78 02 1000164479 091201 081203 28.00
78 03 1000164479 091201 081203 2.00
78 03 1000164479 091201 081202 20.00
78 03 1000164479 091201 081201 4.00
78 01 1000164479 091201 081201 6.00

*/
GO
drop table tb_a,tb_b


LZ看来要学会如何表达需求,幸亏我碰到过差不多的问题,
否则也无法理解LZ的需求了。
简单看来,可以把A表看成是需求表
B表看成是供应表。
skuid 看成是某种类型,只有同类型的才可供应。

owner skuid lot quality vol_exchange mysort
78 A 071203 0 70.00 1

78 B 081203 0 30.00 3
78 B 081202 0 20.00 4
78 B 081201 0 10.00 5

owner skuid lot quality vol_exchange mysort
06 A 091201 0 70.00 1

02 B 091201 0 28.00 3 --需求30,缺2,只能下笔补上
03 B 091201 0 26.00 4 -- (只剩24,因为2被上面那笔吃掉了),够第三笔需求20的,还剩下4,可供给第四笔需求

01 B 091201 0 6.00 6


所以,第一笔需要A 70, 正好 供应 A 70
第二笔需要B 30,供应的话,第二笔只有B 28 , 缺2
所以会将第三笔供应拆成 26 = 2+24
第三笔需求20,第三笔供应还有24,够的。
第四笔需求10,第三笔供应还多4,给它。加上第四笔供应6.


所以,最后结果
需求 供应
A 70 A 70
B 30 B 28
B 30 B 2 -- 26那借来的
B 20 B 20 --还多4呢
B 10 B 4 --多的4给这了
B 10 B 6



bancxc 2010-06-06
  • 打赏
  • 举报
回复
bandingtony
xyj052 2010-06-06
  • 打赏
  • 举报
回复
只能围观了,看了几遍需求,还是不太明白到底需要什么内容
根据你给出的数据,感觉和你下面提供的数据有点对不上
999朵玫瑰 2010-06-06
  • 打赏
  • 举报
回复
学习了
--小F-- 2010-06-06
  • 打赏
  • 举报
回复
围观高手答题
htl258_Tony 2010-06-06
  • 打赏
  • 举报
回复
说实在,我反复看了三遍,还是没摸清楼主的需求
htl258_Tony 2010-06-06
  • 打赏
  • 举报
回复
那段代码跑出来的结果就以下那条,是对的吗?

owner_a owner_b skuid in_lot out_lot vol_exchange
------- ------- ---------- -------------------------------------------------- -------------------------------------------------- ---------------------------------------
78 06 1000164481 091201 071203 70.00

(1 行受影响)
dongdongxiao 2010-06-05
  • 打赏
  • 举报
回复
htl258
(Tony)

#1楼 得分:20回复于:2010-06-04 11:55:06
先帮顶,留在晚上看
===================================================================

to:htl258,请问你看了吗?能帮我解释吗?请告诉我,谢谢!
dawugui 2010-06-05
  • 打赏
  • 举报
回复
.......

34,575

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧