如何转换SQL语句“从不存在someID的TABLE中删除(通过property1,property2从Table group中选择someID)

时间:2015-07-21 15:19:50

标签: ios sql core-data

我正在尝试将以下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核心数据方法,而不是尝试改进,纠正或评论上述SQL,这是非常重要的。

谢谢。

9 个答案:

答案 0 :(得分:8)

听起来你要求SQL来实现你的目标。您的起始查询将不会执行您所描述的内容,并且由于聚合子查询尝试选择不属于组的函数的列,大多数数据库根本不会接受它。

<强>更新

我最初认为请求是删除包含dupes的每个组的所有成员,并相应地编写代码。重新解释原始SQL将像MySQL一样,似乎目标是为(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)上的索引)和其他替代方案。

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

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

我建议你尽量避免这样做。在SomeTable(property1, property2, property3)上定义一个唯一索引,并执行您需要做的任何事情,以避免尝试创建重复项或从(失败)尝试中正常恢复。

答案 1 :(得分:3)

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

答案 2 :(得分:1)

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

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

最终结果将是一个字典数组,每个字典都包含您的主要记录的propertiesToFetch值(即您不想删除的那些),然后您可以从中获取重复数据。有各种各样的方法,但没有一种方法会非常有效。

正如另一个答案所说的那样,首先要避免重复。在这方面,请注意iOS 9允许您指定您想要独特的属性(单独或集体)。

如果您希望我详细说明上述任何内容,请与我们联系。

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

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)
      );

答案 5 :(得分:0)

我认为您可以通过创建派生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
        );

答案 6 :(得分:0)

简单地说,如果您想从表中删除重复项,可以在Query:

下执行

从SomeTable中删除 rowid不在哪里(     选择max(rowid)     来自SomeTable     按property1,property2,property3分组 )

答案 7 :(得分:0)

如果您想删除所有重复记录,请尝试以下代码

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

希望有所帮助

答案 8 :(得分:0)

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

从SomeTable中删除someID不在的地方 (从SomeTable中选择Min(someID) group by property1 + property2 + property3)