Вы можете использовать агрегированную функцию COUNT
для удаления всех дублированных строк.
select PRINCIPAL, APELLIDO, NOMBRE,
count(*) over (partition by PRINCIPAL) dup_cnt
from tab
P A N DUP_CNT
- - - ----------
a b c 2
a l m 2
b c d 1
c d e 1
COUNT
подсчитывают строки для каждого уникального ключа, определенного в предложении PARTITION BY
.
В последнем запросе выбираются только уникальные строки, то есть строки с DUP_CNT = 1
with dedup as (
select PRINCIPAL, APELLIDO, NOMBRE,
count(*) over (partition by PRINCIPAL) dup_cnt
from tab)
select PRINCIPAL, APELLIDO, NOMBRE
from dedup
where dup_cnt = 1
Примечание: используя ROW_NUMBER
вместо COUNT
, вы можете сделать дедупликация, т.е. вы позволяете одной из дублированных строк в результате и удаляете дубликаты.
Обратите внимание , что этот метод требует сортировки таблицы (WINDOW SORT
), которая может быть тяжелой для больших таблиц. В этом случае метод, использующий NOT EXISTS
, может дать лучшую производительность, так как он преобразуется и выполняется как антихеш-соединение - HASH JOIN RIGHT ANTI
.
select principal, apellido, nombre
from tab t
where not exists
(select null
from tab
where principal = t.principal and rowid <> t.rowid
)
Необходимо соблюдать осторожность, если столбец дедупликации (principal
) имеет значение NULL. В отличие от первого решения с COUNT
not exusts
оставляет все null
в результате. Если это не требуется, необходимо добавить фильтр:
and t.principal is not NULL
Если у вас есть индекс в столбце pricipal
, оптимальный план выполнения выглядит следующим образом
--------------------------------------
| Id | Operation | Name |
--------------------------------------
| 0 | SELECT STATEMENT | |
|* 1 | HASH JOIN RIGHT ANTI | |
| 2 | INDEX FAST FULL SCAN| IDX |
|* 3 | TABLE ACCESS FULL | TAB |
--------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("PRINCIPAL"="T"."PRINCIPAL")
filter(ROWID<>"T".ROWID)
3 - filter("T"."PRINCIPAL" IS NOT NULL)
Не забывайте, что, начиная с создания новой обертки для каждого возникновения упаковки является довольно дорогим, особенно рассматривая это обычно используемый в единственном объеме метода, Автоупаковывая использование пул общих оберток.
Это - на самом деле реализация шаблона разработки в наилегчайшем весе. Когда упаковка происходит для известного значения, вместо того, чтобы создать новый экземпляр обертки, предварительно созданный экземпляр выбирается от пула и возвращается.
Одно последствие: все еще не рекомендуется использовать автоупаковку для научных вычислений. Например, код d = * b + c использует Целочисленные классы для a, b, c и d, и сгенерированный код является d.valueOf (a.intValue () * b.intValue () + c.intValue ()). Все эти вызовы метода имеют свои собственные издержки, таким образом, обычно рекомендуется использовать автоупаковку при необходимости для хранения примитивов в наборах.
И даже затем, если у Вас есть огромный набор Целочисленного интервала обертывания, издержки могут подразумевать более длительное время выполнения, до 20 раз дольше, как сообщается в этой статье.
Jb добавляет этот важный комментарий:
Также Wrapper.valueOf (примитивный) пул использования оберток. Поэтому предпочтите Integer.valueOf (5) новому Целому числу (5)
Примитивы быстрее, когда они используются, поскольку объекты должны быть распакованы перед использованием; таким образом существует дополнительный шаг для VM для выполнения. Например, В порядке выполняют арифметику на Целом числе, это должно сначала быть преобразовано в интервал, прежде чем арифметика сможет быть выполнена.
Во многих бизнес-приложениях это, вероятно, редко имеет значение. Но если бы Вы писали что-то, очень numnber-уплотняя тяжелый как, скажем, графический процессор преобразования, то Вы, намного более вероятно, заботились бы.
Если Вы должны сохранить примитивы в наборах, Вы могли бы использовать примитивы свободного городского населения.
Я предпочитаю использовать примитивы для оберток, только помещаю, это абсолютно должно иметь обертки, классы объекта. Поддержка баз данных аннулирует, таким образом, объекты должны также.
Я когда-то работал над проектом, который использовал примитивы (и домашнее пиво ORM) в доступе к базе данных:
class Foo{
int xxx = -1;
...
}
И затем Вы имели:
void persist(Foo foo){
...
statement.setInt(15,foo.getXXX()==-1?null:foo.getXXX());
...
}
Бог это было злым.
да, примитивы быстрее, чем объекты. Начиная с java 5 можно даже смешать примитивы и объекты, вручную не преобразовывая один в другого. Механизм автоупаковки заботится о просто этом.
это означает, что при помещении примитива в набор компилятор не будет жаловаться и преобразовывать примитив в объект неявно.
Я сказал бы, что Вы должны быть взволнованы по поводу использования примитивов по оберткам только, когда Вы представляете свое приложение и видите, что автоупаковка является производительностью или проблемой памяти. По моему опыту, память становится проблемой перед циклами ЦП при разговоре о примитивах по сравнению с обертыванием объектов.