整数数组正负抵扣问题

Lamcelot 2018-07-16 04:56:49
https://bbs.csdn.net/topics/390257447
参考了之前的帖子,没能解决多个数字和为0的问题,如1+1+1+(-3)=0

但是这应该算是很日常的问题,诸如各类计费系统,退费数据必然涉及抵扣正数数据,请问下大佬该如何解决呢,能提供个思路也好,
还有尽量不要使用多层游标。

放上随便写的一些测试数据
insert into #test_data
select 1 union all
select 1 union all
select 1 union all
select -3 union all
select 4 union all
select -4 union all
select 8 union all
select 7 union all
select 6 union all
select -8 union all
select -3 union all
select -3
...全文
179 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
二月十六 2018-07-17
  • 打赏
  • 举报
回复
引用 11 楼 yenange 的回复:
还是邹老大厉害, 看明白都不容易

同感……得研究下整理整理……
吉普赛的歌 2018-07-17
  • 打赏
  • 举报
回复
还是邹老大厉害, 看明白都不容易
zjcxc 2018-07-17
  • 打赏
  • 举报
回复
-- 测试数据(要有主键或唯一键)
create table #test_data(
id int identity primary key,
value int
);
insert into #test_data
select 1 union all
select 1 union all
select 1 union all
select -3 union all
select 4 union all
select -4 union all
select 8 union all
select 7 union all
select 6 union all
select -8 union all
select -3 union all
select -3
;
GO

WITH DATA AS( -- 所有的组合
SELECT id, value,
ids = CONVERT(varchar(max), '<c>' + rtrim(id) + '</c>'), level = 0
FROM #test_data
UNION ALL
SELECT A.id, A.value + DATA.value,
DATA.ids + '<c>' + rtrim(A.id) + '</c>', DATA.level + 1
FROM DATA, #test_data A
WHERE DATA.value <> 0
AND DATA.id < A.id -- 通过主键或唯一键避免在同一组中多次使用同一记录
),
REQ AS( -- 可抵扣的组合
SELECT id=ROW_NUMBER()OVER(ORDER BY level, id), ids = CONVERT(xml, ids)
FROM DATA
WHERE value = 0
),
DEL_REQ AS( -- 筛选方案选择,按照组合顺序选择最早能抵扣的组合
SELECT REQ.ids, next_id = 2,
flag_del = 1, ids_next = REQ.ids
FROM REQ
WHERE id = 1
UNION ALL
SELECT REQ.ids, DEL_REQ.next_id + 1,
ISNULL(FLAG_DEL.value, 1),
CASE FLAG_DEL.value WHEN 0 THEN DEL_REQ.ids_next
ELSE CONVERT(xml, CONVERT(nvarchar(max), DEL_REQ.ids_next) + CONVERT(nvarchar(max), REQ.ids))
END
FROM REQ
INNER JOIN DEL_REQ ON REQ.id = DEL_REQ.next_id
OUTER APPLY(
SELECT 0 as flag WHERE EXISTS(
SELECT * FROM(
SELECT id = T.c.value('.[1]', 'int')
FROM REQ.ids.nodes('/c/text()') T(c)
) X WHERE DEL_REQ.ids_next.exist('/c[text()=sql:column("X.id")]') = 1
)

)FLAG_DEL( value )
),
DEL_ID AS( -- 最终确定删除的 主键或唯一键 列表
SELECT id = T.c.value('.', 'int')
FROM(
SELECT TOP 1 ids_next
FROM DEL_REQ
WHERE flag_del = 1
ORDER BY next_id DESC
) D
CROSS APPLY D.ids_next.nodes('/c/text()') T(c)
)
-- 删除
-- DELETE DATA FROM #test_data DATA, DEL_ID WHERE DATA.id = DEL_ID.id
-- 查看删除列表
SELECT ids FROM DEL_REQ WHERE flag_del = 1
OPTION( MAXRECURSION 0 )
GO

SELECT * FROM #test_data;
-- 删除测试数据
DROP TABLE #test_data

zjcxc 2018-07-17
  • 打赏
  • 举报
回复
如果一定要抵掉,那么多个值的情况你要确定详细的规则,因为多值可能某个值在多组方案中可用
zjcxc 2018-07-17
  • 打赏
  • 举报
回复
引用 6 楼 shinger126 的回复:
不明白你们究竟想要干啥,不过你们的目的最终不是统计出最后的算术和么?业务不要搞得那么复杂

就是,不管抵不抵掉,这就是简单的所有数值相加,SUM之后就是最终结果嘛
吉普赛的歌 2018-07-17
  • 打赏
  • 举报
回复
引用 6 楼 shinger126 的回复:
不明白你们究竟想要干啥,不过你们的目的最终不是统计出最后的算术和么?业务不要搞得那么复杂

你说的也有道理。你可以用你的简单办法做出来, 贴脚本出来给大家看看
shinger126 2018-07-17
  • 打赏
  • 举报
回复
不明白你们究竟想要干啥,不过你们的目的最终不是统计出最后的算术和么?业务不要搞得那么复杂
zbdzjx 2018-07-17
  • 打赏
  • 举报
回复
引用 2 楼 Lamcelot 的回复:
引用 1楼zbdzjx 的回复:
要什么样的结果?
正负抵扣的数据去掉,剩下的数据

那如果数据是-1、-1、3,结果要什么?
按目前的数据来看,只能用两个游标(一个查正数,一个查负数),互相抵消。
更好的办法,是在计费系统中处理,每增、删、改数据,就处理一下。
吉普赛的歌 2018-07-17
  • 打赏
  • 举报
回复
还有 11+2-5-8 = 0 这种正负数都是多个的情况。
涉及到全排列,想一次循环非常困难
二月十六 2018-07-16
  • 打赏
  • 举报
回复
目前就想到游标循环的方法,在琢磨琢磨。楼主这个对数据先后有关系吗?例如消除负数必须是负数后边的正数。
Lamcelot 2018-07-16
  • 打赏
  • 举报
回复
引用 1楼zbdzjx 的回复:
要什么样的结果?
正负抵扣的数据去掉,剩下的数据
zbdzjx 2018-07-16
  • 打赏
  • 举报
回复
要什么样的结果?

22,210

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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