如何转换 SQL 语句“从没有 someID 的 TABLE 中删除(从 Table group by property1、property2 中选择 someID)

Posted

技术标签:

【中文标题】如何转换 SQL 语句“从没有 someID 的 TABLE 中删除(从 Table group by property1、property2 中选择 someID)【英文标题】:How to convert SQL statement "delete from TABLE where someID not in (select someID from Table group by property1, property2) 【发布时间】:2015-07-21 15:19:49 【问题描述】:

我正在尝试将以下 SQL 语句转换为 Core Data:

delete from SomeTable
where someID not in (
    select someID
    from SomeTable
    group by property1, property2, property3
)

基本上,如果 property1、property2 和 property3 等于另一条记录,我想检索和删除表中可能的重复记录。

我该怎么做?

PS:正如标题所说,我是在尝试将上面的 SQL 语句转换成 ios Core Data 的方法,而不是尝试对上面的 SQL 进行改进、更正或评论,那是多余的。

谢谢。

【问题讨论】:

您的起始查询似乎没有按照您描述的那样做。您是要求更好的 SQL 查询,还是要求特定于 Core Data 的东西? 另外,我们是否理解 SomeTable.someId 列是唯一的或(更好)PK? 嘿约翰。好吧,我在一个 iOS 项目中使用原始 SQL 选择了这个项目。我不想开始深入研究,所以当我重写应用程序时,我选择了 Core Data 作为后端。现在,我无法判断此方法是否返回它应该返回的内容,但这是用于删除具有相同 3 个属性值的记录重复项的方法,例如属性 1、属性 2 和属性 3。我正在研究如何将其转换为核心数据。哦,还有 SomeTable.someID 是独一无二的。 mysql 是我所知道的唯一一个完全接受该声明的 DBMS。在这种情况下,结果将是从每组欺骗中删除除一个之外的所有内容。 MySQL 没有定义将在每个组中保留哪一行。然而,我不是这样理解你的要求的。我会尽快更新我的答案。 【参考方案1】:

听起来您要求使用 SQL 来实现您的目标。您的起始查询不会按照您的描述进行,并且大多数数据库根本不会接受它,因为聚合子查询试图选择不是组函数的列。

更新

我最初认为请求是删除每个包含欺骗的组的所有成员,并相应地编写了代码。像 MySQL 一样重新解释了原始 SQL,似乎目标是为(property1, property2, property3) 的每个组合保留一个元素。我想无论如何这更有意义。这是执行此操作的标准方法:

delete from SomeTable st1
where someID not in (
    select min(st2.someId)
    from SomeTable st2
    group by property1, property2, property3
  )

这与原来的区别在于使用min() 聚合函数从每个组中选择要保留的someId 值中的一个特定值。这也应该有效:

delete from SomeTable st1
where someID in (
  select st3.someId
  from SomeTable st2
    join SomeTable st3
      on st2.property1 = st3.property1
        and st2.property2 = st3.property2
        and st2.property3 = st3.property3
  where st2.someId < st3.someId
)

这两个查询将保留相同的行。我更喜欢第二个,即使它更长,因为NOT IN 运算符对于从大集合中选择少量元素来说有点讨厌。但是,如果您预计有足够多的行来关注缩放,那么您应该同时尝试这两种方法,并可能考虑优化(例如,(property1, property2, property3) 上的索引)和其他替代方案。

然而,至于根据 Core Data 调用来编写它,我认为您并不完全可以。 Core Data 确实支持分组,因此您可以编写 Core Data 调用,在第一个备选方案中执行子查询并返回实体对象或其 ID,按描述分组。然后,您可以遍历组,跳过每个组的第一个元素,并为所有其余部分调用 Core Data 删除方法。详细信息超出了 SO 格式的范围。

不过,我不得不说,在 Core Data 中做这样的工作将比直接在数据库中做更远的成本,无论是在时间上还是在所需的内存上。然而,直接在数据库中执行它对诸如 Core Data 之类的 ORM 框架并不友好。这种事情是您通过使用 ORM 框架选择的权衡之一。

我建议您尽量避免这样做。在SomeTable(property1, property2, property3) 上定义一个唯一索引,并尽您所能避免尝试创建重复项或从(失败的)尝试中正常恢复。

【讨论】:

显然有些人在 SQL 方面比我好很多!我如何将其转换为正确的核心数据调用? 感谢您抽出宝贵时间回复,约翰。我显然不能直接从数据库中删除行。这显然会搞砸 Core Data。我将看看如何使用您的逻辑来提出 Core Data 可接受的内容。【参考方案2】:
DELETE SomeTable 
FROM SomeTable
LEFT OUTER JOIN (
   SELECT MIN(RowId) as RowId, property1, property2, property3 
   FROM SomeTable 
   GROUP BY property1, property2, property3
) as KeepRows ON
   SomeTable.RowId = KeepRows.RowId
WHERE
   KeepRows.RowId IS NULL

【讨论】:

【参考方案3】:

在 iOS 中执行此操作的几点建议: 在 iOS 9 之前,删除对象的唯一方法是单独删除,即您需要遍历一组重复项并删除每个重复项。 (如果您的目标是 iOS9,有一个新的 NSBatchDeleteRequest 将有助于一次性删除它们 - 它确实直接作用于商店,但也会进行一些清理以确保在必要时更新关系)。

另一个问题是识别重复项。您可以配置提取以对其结果进行分组(参见NSFetchRequestpropertiesToGroupBy),但您必须指定NSDictionaryResultType(因此结果不是对象本身,只是相关属性中的值。)此外,CoreData 将不允许您获取未在 GROUP BY 中指定的属性(聚合除外)。因此,使用min(someId) 的建议(在另一个答案中)将是必要的。 (要获取这样的表达式,您需要使用NSExpression,将其嵌入到NSExpressionDescription 中,并将后者传递到获取请求的propertiesToFetch 中)。

最终结果将是一个字典数组,每个字典都包含您的主要记录(即您不想删除的那些)的someId 值,然后您必须从中计算出重复项。方法有很多种,但没有一种是非常有效的。

因此,正如另一个答案所说,首先最好避免重复。在这方面,请注意 iOS 9 允许您指定您希望是唯一的属性(单独或集体)。

如果您希望我详细说明上述任何内容,请告诉我。

【讨论】:

谢谢,我会试一试。我知道 NSExpressions,尽管我从未使用过它们。【参考方案4】:

Group-wise Maximum:

select t1.someId
      from SomeTable t1
        left outer join SomeTable t2
          on    t1.property1 = t2.property1
            and t1.property2 = t2.property2
            and t1.property3 = t2.property3
            and t1.someId < t2.someId
      where t2.someId  is null;

所以,这可能是答案

delete SomeTable 
where someId not in
 (select t1.someId
  from SomeTable t1
    left outer join SomeTable t2
      on    t1.property1 = t2.property1
        and t1.property2 = t2.property2
        and t1.property3 = t2.property3
        and t1.someId < t2.someId
  where t2.someId  is null); 

Sqlfiddle demo

【讨论】:

【参考方案5】:

您可以使用exists 函数检查每一行是否存在另一行,其 id 不等于当前行,并且定义每行重复条件的所有其他属性都等于当前行。

delete from something 
where
    id in (SELECT 
        sm.id
    FROM
        sometable sm

    where
        exists( select 
            1
        from
            sometable sm2

        where
            sm.prop1 = sm2.prop1
            and sm.prop2 = sm2.prop2
            and sm.prop3 = sm2.prop3
            and sm.id != sm2.id)
      );

【讨论】:

【参考方案6】:

我认为您可以通过创建派生的duplicate_flg 列轻松处理此问题,并在所有三个属性值相等时将其设置为 1。完成后,您可以删除duplicate_flg = 1 的那些记录。以下是有关如何执行此操作的示例查询:

--retrieve all records that has same property values (property1,property2 and property3) 
SELECT *
FROM (
    SELECT someid
        ,property1
        ,property2
        ,property3
        ,CASE 
            WHEN property1 = property2
                AND property1 = property3
                THEN 1
            ELSE 0
            END AS duplicate_flg
    FROM SomeTable
    ) q1
WHERE q1.duplicate_flg = 1;

这是一个示例delete 声明:

DELETE
FROM something
WHERE someid IN (
        SELECT someid
        FROM (
            SELECT someid
                ,property1
                ,property2
                ,property3
                ,CASE 
                    WHEN property1 = property2
                        AND property1 = property3
                        THEN 1
                    ELSE 0
                    END AS duplicate_flg
            FROM SomeTable
            ) q1
        WHERE q1.duplicate_flg = 1
        );

【讨论】:

【参考方案7】:

简单地说,如果你想从表中删除重复,你可以在下面执行查询:

从 SomeTable 中删除 其中rowid不在( 选择最大值(rowid) 来自 SomeTable 按属性 1、属性 2、属性 3 分组 )

【讨论】:

【参考方案8】:

如果你想删除所有重复记录试试下面的代码

WITH tblTemp  as
(
    SELECT ROW_NUMBER() Over(PARTITION BY Property1,Property2,Property3 ORDER BY Property1) As RowNumber,* FROM Table_1
)
DELETE FROM tblTemp where RowNumber >1

希望对你有帮助

【讨论】:

【参考方案9】:

使用以下查询从该表中删除重复数据

从 SomeTable 中删除 someID 不在的位置 (从 SomeTable 中选择 Min(someID) 按属性1+属性2+属性3)分组

【讨论】:

以上是关于如何转换 SQL 语句“从没有 someID 的 TABLE 中删除(从 Table group by property1、property2 中选择 someID)的主要内容,如果未能解决你的问题,请参考以下文章

如何将此sql语句转换为laravel orm?

如何将以下 SQL 语句转换为 LINQ 方法语法

如何将存储过程转换为单个 SQL 语句

sql语句中如何将字符类型转换成数字类型?

Python如何解析SQL语句并转换为Python对象,SQLParse类库的使用

在SQL语句里面如何将字符型转换成数字型