【问题标题】:How do I Compare columns of records from the same table?如何比较同一表中的记录列?
【发布时间】:2016-08-15 10:50:28
【问题描述】:

这是我的测试表数据:

测试

ID      Name            Payment_Date   Fee                Amt
1       BankA           2016-04-01     100                20000
2       BankB           2016-04-02     200                10000
3       BankA           2016-04-03     100                20000
4       BankB           2016-04-04     300                20000

我正在尝试比较每个数据记录的名称、费用和金额字段,以查看是否存在相同的值。如果他们得到相同的值,我想在这些记录上标记“Y”之类的东西。这是预期的结果

ID      Name            Payment_Date   Fee                Amt      SameDataExistYN
1       BankA           2016-04-01     100                20000    Y
2       BankB           2016-04-02     200                10000    N
3       BankA           2016-04-03     100                20000    Y
4       BankB           2016-04-04     300                20000    N

下面这两种方法我都试过了。但我正在寻找任何其他解决方案,以便为我的工作挑选出最好的解决方案。

方法一。

select t.*, iif((select count(*) from testing where name=t.name and fee=t.fee and amt=t.amt)=1,'N','Y') as SameDataExistYN from testing t

方法二。

select t.*, case when ((b.Name = t.Name)
                        and (b.Fee = t.Fee) and (b.Amt = t.Amt)) then 'Y' else 'N' end as SameDataExistYN
from testing t
left join ( select Name,  Fee, Amt
            from testing
            Group By Name,  Fee, Amt
            Having count(*)>1  ) as b on b.Name = t.Name
                                      and b.Fee = t.Fee
                                      and b.Amt = t.Amt

【问题讨论】:

  • 您只是想查找重复记录吗?
  • 是的!我试图找到重复的记录并在上面做标记
  • 我认为您的第一种方法不正确,因为它只是按名称进行比较。
  • 对不起!我在方法 1 中犯了错误,现在已编辑

标签: mysql sql subquery self-join nested-select


【解决方案1】:

有多种方法,其性能特征各不相同。

一种选择是运行相关子查询。如果您有合适的索引,并且您要提取的行数相对较少,则此方法最适合。

SELECT t.id
     , t.name
     , t.payment_date
     , t.fee
     , t.amt
     , ( SELECT 'Y' 
           FROM testing s
          WHERE s.name = t.name
            AND s.fee  = t.fee
            AND s.amt  = t.amt
            AND s.id  <> t.id
          LIMIT 1
        ) AS SameDataExist
  FROM testing t
 WHERE ...
 LIMIT ...

当找到至少一个“匹配”行时,SELECT 列表中的相关子查询将返回 Y。如果未找到“匹配”行,SameDataExist 列的值为 NULL。要将 NULL 转换为“N”,您可以将子查询包装在 IFULL() 函数中。


您的方法 2 是一种可行的方法。 SELECT 列表中的表达式不需要进行所有这些比较,那些已经在连接谓词中完成。您只需要知道是否找到了匹配的行...只需测试其中一列的 NULL/NOT NULL 就足够了。

SELECT t.id
     , t.name
     , t.payment_date
     , t.fee
     , t.amt
     , IF(s.name IS NOT NULL,'Y','N') AS SameDataExists
  FROM testing t
  LEFT
  JOIN ( -- tuples that occur in more than one row
         SELECT r.name, r.fee, r.amt
           FROM testing r
          GROUP BY r.name, r.fee, r.amt
         HAVING COUNT(1) > 1
       ) s
    ON s.name = t.name
   AND s.fee  = t.fee
   AND s.amt  = t.amt
 WHERE ...

您也可以使用 EXISTS(相关子查询)

【讨论】:

    【解决方案2】:

    看看这个

    Select statement to find duplicates on certain fields

    不确定如何将其标记为骗子...

    【讨论】:

      【解决方案3】:

      这是另一种方法,但我认为您必须对数据进行测试才能找出最佳方法:

      SELECT
        t.*,
        CASE WHEN EXISTS(
          SELECT * FROM testing WHERE id <> t.id AND Name = t.Name AND Fee = t.Fee AND Amt = t.Amt
        ) THEN 'Y' ELSE 'N' END SameDataExistYN
      FROM
        testing t 
      ;
      

      【讨论】:

      • 哇!这比我宝贵的方法更完美、更快。谢谢
      【解决方案4】:

      Select t.name ,t.fee,t.amt,if(count(*)>1),'Y','N') from testing t group by t.name,t.fee,t.amt

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多