【问题标题】:SELECT SQL Matching NumberSELECT SQL 匹配号码
【发布时间】: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。感谢您的帮助

【问题讨论】:

    标签: sql sql-server tsql string-matching fuzzy-search


    【解决方案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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-23
      • 2019-04-27
      • 2018-07-14
      • 2023-03-07
      相关资源
      最近更新 更多