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 EXISTS
或LEFT 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 匹配号码的主要内容,如果未能解决你的问题,请参考以下文章