SELECT SQL 匹配号码

Posted

技术标签:

【中文标题】SELECT SQL 匹配号码【英文标题】:SELECT SQL Matching Number 【发布时间】:2020-03-13 15:58:54 【问题描述】:

我有数百万行具有类似值的数据,如下所示:

Id    Reff    Amount
1     a1       1000
2     a2      -1000
3     a3      -2500
4     a4      -1500
5     a5       1500

每个数据都必须有正值和负值。问题是,我如何只显示没有相似值的记录?喜欢行 ID 3。感谢您的帮助

【问题讨论】:

【参考方案1】:

你可以使用not exists:

select t.*
from mytable t
where not exists (select 1 from mytable t1 where t1.amount = -1 * t.amount)

left join 反模式也可以完成工作:

select t.*
from mytable t
left join mytable t1 on t1.amount = -1 * t.amount
where t1.id is null

Demo on DB Fiddle

身份证 |参考 |数量 -: | :--- | -----: 3 | a3 | -2500

【讨论】:

这个解决方案需要注意的一点是,它只会找到没有反价值的记录。所以 a6 = -2500 会出现两次。这可能是也可能不是期望的行为 @el_oso:每个数据都必须有正负值:是的,我认为这正是 OP 想要的...... 我同意,这就是为什么我将其选为正确答案的原因。我只是指出了一个潜在的问题,即当您可以多次出现相同的值时。 el_oso - 我明白你的意思。此外,现有的任何单个 +2500 记录都不会选择任何数量的 -2500 记录 - 如果您想要一对一匹配,则需要为相似的值添加 row_numbers,并加入它们。我并不是说这个解决方案中的任何一个都是错误的,它确实可以满足要求。在单个零上还有一个问号(当然不是正数或负数) 我试过这个方法,但问题是处理时间。我有6500万行数据,运行查询确实需要很长时间。【参考方案2】:

SQL Fiddle

MS SQL Server 2017 架构设置

CREATE TABLE Test(
   Id     int  
  ,Reff   varchar(2)
  ,Amount int  
);
INSERT INTO Test(Id,Reff,Amount) VALUES (1,'a1',1000);
INSERT INTO Test(Id,Reff,Amount) VALUES (2,'a2',-1000);
INSERT INTO Test(Id,Reff,Amount) VALUES (3,'a3',-2500);
INSERT INTO Test(Id,Reff,Amount) VALUES (4,'a4',-1500);
INSERT INTO Test(Id,Reff,Amount) VALUES (5,'a5',1500);

查询 1

select t.*
from Test t
left join Test t1 on t1.amount =ABS(t.amount)
where t1.id is null

Results

| Id | Reff | Amount |
|----|------|--------|
|  3 |   a3 |  -2500 |

【讨论】:

对于 a3 = 2500 和 a6 = 2500 以及 a3 = -2500 和 a6 = -2500 的情况,您会得到不同的答案。对于这种方法,您应该 ABS() 双方【参考方案3】:

使用NOT EXISTSLEFT JOIN 可以很好地找到数据中没有相反数量的数量。

但要真正找到与按 ID 排序的金额不平衡的金额? 对于这样的 SQL 谜题,它应该作为一个 Gaps-And-Islands 问题来处理。

所以解决方案可能看起来有点复杂,但实际上非常简单。

它首先计算每个绝对值的排名。

并根据该排名过滤每个排名的 SUM 未平衡的最后一个数量(不是 0)

SELECT Id, Reff, Amount
FROM
(
    SELECT *,
     SUM(Amount) OVER (PARTITION BY Rnk) AS SumAmountByRank,
     ROW_NUMBER() OVER (PARTITION BY Rnk  ORDER BY Id DESC) AS Rn
    FROM
    (
        SELECT Id, Reff, Amount,
         ROW_NUMBER() OVER (ORDER BY Id) -  ROW_NUMBER() OVER (PARTITION BY ABS(Amount) ORDER BY Id) AS Rnk
        FROM YourTable
    ) AS q1
) AS q2
WHERE SumAmountByRank != 0
  AND Rn = 1
ORDER BY Id;

对 rextester 的测试here

如果顺序无关紧要,而只是平衡很重要? 然后可以简化查询。

SELECT Id, Reff, Amount
FROM
(
    SELECT Id, Reff, Amount,
     SUM(Amount) OVER (PARTITION BY ABS(Amount)) AS SumByAbsAmount,
     ROW_NUMBER() OVER (PARTITION BY ABS(Amount) ORDER BY Id DESC) AS Rn
    FROM YourTable
) AS q
WHERE SumByAbsAmount != 0
  AND Rn = 1
ORDER BY Id;

【讨论】:

以上是关于SELECT SQL 匹配号码的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 UNION 和子 SELECT 从查询构造 MySQL 视图

SQL select语句复习

请教怎么用SQL对比两个表中身份证号字段不一样的数据

sql的 select

SQL学习Where语句中的各种匹配方式

联合索引最左匹配