我正在尝试将以下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,这是非常重要的。谢谢。
答案 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)
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)