选择另一行中没有相反值的行

时间:2018-11-29 16:20:02

标签: sql sql-server

我正在尝试编写一个查询,该查询将仅选择没有相反值的行。例如,如果一列(付款)具有2个负数(-11)和3个正数(11),则两个负数将抵消,而一个正数将保留。我可能在解释这个错误。但是任何帮助都值得赞赏。 表格:

CREATE TABLE hamzachecks(
   ID      VARCHAR(2) NOT NULL
  ,CHECK   VARCHAR(10) NOT NULL
  ,Payment VARCHAR(8) NOT NULL
);
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('1','9549549544','-112.96');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('2','9549549544','-112.96');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('3','9549549544','112.96');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('4','9549549544','112.96');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('5','9549549544','-165.92');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('6','9549549544','225.92');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('7','9549549544','-299.3');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('8','9549549544','-299.3');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('9','9549549544','-299.3');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('10','9549549544','299.3');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('11','9549549544','299.3');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('12','9549549544','-415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('13','9549549544','-415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('14','9549549544','-415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('15','9549549544','-415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('16','9549549544','-415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('17','9549549544','-415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('18','9549549544','-415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('19','9549549544','-415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('20','9549549544','-415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('21','9549549544','-415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('22','9549549544','415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('23','9549549544','415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('24','9549549544','415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('25','9549549544','415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('26','9549549544','415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('27','9549549544','415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('28','9549549544','415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('29','9549549544','415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('30','9549549544','415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('31','9549549544','415.14');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('32','9549549544','-1024.22');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('33','9549549544','1024.22');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('34','9549549578','-253.77');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('35','9549549578','253.77');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('36','9549549578','-3332.16');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('37','9549549578','-6664.29');
INSERT INTO hamzachecks(ID,CHECK,Payment) VALUES ('38','9549549578','6664.29');

2 个答案:

答案 0 :(得分:1)

基本逻辑与@Marty相同,使用相同的chk/payment组合为每行分配一个行号。

SELECT chk
  ,id 
  ,Payment
  ,Row_Number() Over (PARTITION BY chk, Payment ORDER BY Id) AS rn 
FROM hamzachecks 
order by 
   chk
   -- remove the leading '-'', for numeric data: abs(Payment)
  ,substring(Payment, charindex('-', Payment)+1, 8000)
  ,rn
  ,Payment

有一个匹配的行,两行将共享相同的rn

... 
9549549544      3       112.96     1 -- 1st group
9549549544      1      -112.96     1    --  matching value: remove
9549549544      4       112.96     2 -- 2nd group 
9549549544      2      -112.96     2    --  matching value: remove
...
9549549544      10      299.3      1 -- 1st group
9549549544      7      -299.3      1    --  matching value: remove
9549549544      11      299.3      2 -- 2nd group
9549549544      8      -299.3      2    --  matching value: remove
9549549544      9      -299.3      3 -- 3rd group, no matching value: keep
... 

现在使用聚合删除具有两行的组:

;WITH cte AS 
 (
   SELECT chk
     ,id 
     ,Payment
     ,Row_Number() Over (PARTITION BY chk, Payment ORDER BY Id) AS rn 
   FROM hamzachecks 
 )
SELECT
   Min(id)
  ,chk
  ,max(Payment)
FROM cte
GROUP BY
   chk
   -- remove the leading '-'', for numeric data: abs(Payment)
  ,substring(Payment, charindex('-', Payment)+1, 8000)
  ,rn
HAVING count(*) = 1

请参见fiddle

答案 1 :(得分:0)

对于您为什么要以这种特定方式执行此特定工作,我将忽略可能的考虑。

所以基本上:以下SQL将给您您要的结果...

;with b (id, payment, rn) as 
(select id, payment, row_number() over (partition by Payment order by Id) as rn 
from hamzachecks 
where payment < 0),
a (id, payment, rn) as 
(select id, payment, row_number() over (partition by Payment order by Id) as rn 
from hamzachecks 
where payment > 0),
matched_ids (id1,id2) as 
(select a.id id1, b.id id2 
from a 
join b on a.payment = -b.payment and a.rn = b.rn)
select *
from hamzachecks
where id not in (select id1 from matched_ids union select id2 from matched_ids)
order by id

这需要更改架构:将“付款”列定义为MONEY(或其他数字类型)而不是VARCHAR(8)。 这将是进一步工作的起点,因为此解决方案忽略了CHECK列。

说明:首先,我们将源表分为两组:a-零以上(payment > 0)和b-零以下(payment < 0)。这两个组都将获得另一列row_number() ...,该列将根据特定组(partition by Payment)中的位置向每一行获取一个“ rowID”,该行的基本含义是:“这是 n-具有相同付款的行”。然后,联接部分匹配另一组中具有相同(但相反)Payment的所有行,并检查rowID-我们现在知道所有具有相反值的行。因此,主选择仅忽略那些行,而仅返回那些没有相反值的行。