Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Новости сайта "Упражнения по SQL" (http://www.sql-ex.ru) 252


Новости сайта "Упражнения по SQL (http://www.sql-ex.ru)"

Выпуск 252 от 25 июля 2009 г.

Новым посетителям сайта

SQL Exercises Сайт посвящен изучению языка, с помощью которого осуществляется взаимодействие с реляционными (и не только) СУБД. Суть обучения состоит в выполнении заданий на написание запросов к учебным базам данных; при этом система контролирует правильность выполнения заданий. В настоящее время реализованы все операторы подъязыка манипуляции данными (DML), которые включают в себя оператор извлечения данных SELECT, а также операторы модификации данных - INSERT, DELETE и UPDATE.

Мы надеемся, что справочного материала сайта окажется достаточно для самостоятельного обучения. Кроме того, свои решения вы можете обсудить на форуме сайта. Опытных же специалистов приглашаем проверить (продемонстрировать) свое мастерство и принять участие в соревновании, обеспечиваемом рейтинговой системой учета времени выполнения заданий. Фактически, рейтинг ведется на втором этапе тестирования, который начинается сейчас после решения 48-ми задач первого этапа. При подсчете рейтинга каждого участника отбрасывается один самый худший показатель среди всех решенных им упражнений.

Демонстрация плана выполнения запроса и сравнительная оценка эффективности решений поможет вам освоить принципы оптимизации запросов, которые пригодятся на третьем рейтинговом этапе, который начинается после 138 задачи.

Имеется возможность получить сертификат по SQL DML при выполнении определенного количества заданий.


Новости сайта

§ Под номером 35 на обучающий этап выставлена новая задача.

§ Изменения среди лидеров (решенные за неделю задачи третьего этапа):
4. $erges (157)
6. Umrikhina (155)

§ К 3-му этапу подошел:
54. Lohmatyi (задач 138, время 3.994)

§ Одна задача до третьего этапа осталась:
102. burnall (137, 19.319)

§ Продвинулись в рейтинге:
55. Vasilko (138, 10.480)
58. Fencer (136, 267.589)
65. AlexPhil (133, 10.832)
78. SoVa (130, 259.702)
81. Eka (127, 20.538)
92. Cергей L (125, 119.077)

§ Новые лица в ТОР 100 и вернувшиеся туда:
64. danilko (133, 3.326)
75. niko2 (129, 10.447)

§ Продвижение ближайших претендентов на попадание в ТОР 100:
102. burnall (137, 19.319)
175. amg__ (112, 12.493)

§ На этой неделе сертифицированы:
Валдай (A09050634) [BK] - г.Москва, Россия

§ Число подписчиков - 3913

Число участников рейтинга - 22305

Число участников второго этапа - 1879

Число участников третьего этапа - 52

Сертифицировано на сайте - 383

Лучшие результаты (ТОР 20)

No Person Number of
Sel_ex
Last_Sel Number of
DML_ex
Scores Days Days_2 Days_3 S_3 LastSolved LastVisit
1 Карасёва Н.В. (vlksm)1 159 159 22 384 1148 98.325 69.172 62 27 Jun 2009 24 Jul 2009
2 Креславский О.М. (Arcan)1 159 158 22 384 888 91.939 73.969 62 06 Jul 2009 25 Jul 2009
3 Зотов П.Г. (Ozzy)1 152 157 21 368 480 189.522 206.391 61 03 Jul 2009 24 Jul 2009
4 Сальников С.А. ($erges)1 158 157 22 381 510 5.048 5.348 59 20 Jul 2009 24 Jul 2009
5 Дроздков А.Н. (anddros)5 156 159 22 376 398 6.964 7.600 54 29 Jun 2009 24 Jul 2009
6 Умрихина Е.В. (Umrikhina)4 155 155 22 376 453 38.456 56.104 54 21 Jul 2009 24 Jul 2009
7 Сенкевич С.В. (GreyC)1 145 152 21 356 358 57.860 27.102 44 26 Jan 2009 08 Jul 2009
8 Селезнёв А.С. (Артём С.)1 143 152 21 350 444 47.248 37.524 44 25 Jan 2009 03 Mar 2009
9 Никотин В.М. (@Nikotin)1 146 150 21 353 283 8.371 3.751 38 06 Jun 2009 22 Jul 2009
10 Мурашкин И.В. (lepton)1 139 156 21 336 1139 69.490 59.005 36 05 May 2009 05 May 2009
11 Печатнов В.В. (pvv)1 142 149 21 340 584 30.849 17.490 34 25 May 2009 24 Jul 2009
12 Муллаханов Р.Х. (rem)9 149 152 22 355 649 14.627 20.056 33 20 Jun 2009 14 Jul 2009
13 Шиндин А.В. (AlShin)10 140 150 21 340 79 20.458 7.203 28 05 Jan 2009 25 May 2009
14 Держальцев В.А. (MadVet)7 132 146 21 320 1509 60.783 28.482 26 03 Jun 2009 16 Jun 2009
15 Любченко В.А. (IAS56)6 142 96 21 337 1048 420.338 373.617 26 18 Jul 2009 24 Jul 2009
16 Голубин Р.С. (Roman S. Golubin)3 136 145 21 326 1413 93.162 58.822 23 01 Jul 2009 11 Jul 2009
17 Тарасов Д.Б. (Gavrila)17 146 156 22 344 1419 41.261 10.993 22 15 Jul 2009 24 Jul 2009
18 Nikolaenko A.V. (Shadow77)12 135 147 21 324 436 77.451 14.010 21 22 Oct 2008 11 Dec 2008
19 Солдатенков Ю.С. (SolYUtor)2 131 146 21 316 819 22.615 6.102 18 14 Aug 2008 01 Apr 2009
20 Кудряков А.И. (AKudrakov)19 142 152 21 334 483 94.015 52.909 18 07 May 2009 07 May 2009

Лучшие результаты за неделю

No surname n_sel sel_all sel_scores dml_scores scores rating last_visit
1 >Putin (danilko) 45 133 107 0 107 64 24 Jul 2009
2 Demyanov R. (RX) 27 41 60 18 78 1254 24 Jul 2009
3 Smirnov G.V. (Gleb V Smirnov) 14 50 27 35 62 945 24 Jul 2009
4 Елизаров С.А. (Sorkus) 28 28 59 0 59 3477 24 Jul 2009
5 Иванов И.И. (sas__71) 28 80 57 0 57 373 24 Jul 2009
6 Шрамко А.С. (Fj0rD) 28 28 57 0 57 3646 24 Jul 2009
7 >diegom D.D. (diegom) 23 32 53 1 54 3052 24 Jul 2009
8 Яценко Д.А. (profesla) 25 29 51 0 51 3906 22 Jul 2009
9 Гладких М.В. (Xail) 24 24 47 0 47 4748 18 Jul 2009
10 Василец Е. (algedi) 20 36 45 0 45 2198 23 Jul 2009
11 oltean A. (andreea_ita) 6 35 13 30 43 1529 24 Jul 2009
12 Орлов М.В. (Eagleoff) 14 105 30 0 30 225 24 Jul 2009
13 Skurydin M. (Maxok) 12 21 30 0 30 5628 24 Jul 2009
14 Дворянинов В. (Валдай) 13 81 29 0 29 360 24 Jul 2009
15 Paul P. (paulpacurar[YIM]) 16 67 27 0 27 1064 24 Jul 2009
16 Нагимов Т. (enzo) 12 69 25 1 26 522 24 Jul 2009
17 Филипцов А.В. (AlexPhil) 10 133 22 0 22 65 24 Jul 2009
18 >de jong D. (Daan) 14 14 22 0 22 8703 24 Jul 2009
19 daaq (fra) 12 15 21 0 21 8198 24 Jul 2009

Изучаем SQL

Как удалить дубликаты строк при наличии первичного ключа?

Моисеенко С.И.

В предыдущей статье мы рассмотрели решение проблемы с дубликатами, вызванной отсутствием первичного ключа. Рассмотрим теперь более тяжелый случай, когда ключ вроде бы есть, но он является синтетическим, что при неправильном проектировании тоже может привести к появлению дубликатов с точки зрения предметной области.

Странное дело, но, рассказывая на лекциях о недостатках синтетических ключей, я, тем не менее, постоянно сталкиваюсь с тем, что студенты в своих первых проектах с базами данных их неизменно используют. Видимо, в человеке заложена генетическая потребность все перенумеровывать, и помочь здесь может только психотерапевт. :-)

Я не хочу обсуждать здесь избитую проблему синтетических ключей. Скажу лишь, что если вы решили использовать их в качестве первичного ключа, то следует также создавать естественный уникальный ключ, чтобы избежать описанной ниже ситуации.

Итак, пусть имеется таблица с первичным ключом id и столбцом name, который в соответствии с ограничениями предметной области должен содержать уникальные значения. Однако если определить структуру таблицы следующим образом

CREATE TABLE T_pk (id INT IDENTITY PRIMARY KEY,
     name VARCHAR(50))

то появлению дубликатов ничто не препятствует. Следовало бы использовать следующую структуру таблицы:

CREATE TABLE T_pk (id INT IDENTITY PRIMARY KEY,
     name VARCHAR(50) UNIQUE)

Все знают, как нужно правильно поступить, однако зачастую приходится иметь с "унаследованной" структурой и данными, которые нарушают ограничения предметной области. Вот пример:

id name 
1 John
2 Smith
3 John
4 Smith
5 Smith
6 Tom

Вы можете спросить: "А чем эта проблема отличается от предыдущей? Ведь здесь есть даже более простое решение - просто удалить все строки из каждой группы с одинаковыми значениями в столбце name, оставив лишь строку с минимальным/максимальным значением id. Например, так:"

DELETE
FROM T_pk
WHERE id > (SELECT MIN(id) FROM T_pk X WHERE X.name = T_pk.name)

Правильно, но я вам еще не все рассказал. :-) Представьте, что у нас имеется дочерняя таблица T_details, связанная с таблицей T_pk по внешнему ключу:

CREATE TABLE T_details (id_pk INT FOREIGN KEY REFERENCES
 T_pk ON DELETE CASCADE,
 color VARCHAR(10),
 PRIMARY KEY (id_pk, color)

Эта таблица может содержать такие данные:

id_pk color 
1 blue
1 red
2 green
2 red
3 red
4 blue
6 red

Для большей наглядности воспользуемся запросом

SELECT id, name, color FROM T_pk JOIN T_details ON id= id_pk

чтобы увидеть имена:

id name color
1 John blue
1 John red
2 Smith green
2 Smith red
3 John red
4 Smith blue
6 Tom red

Таким образом, оказывается, что данные, фактически относящиеся к одному лицу, ошибочно оказались разнесенными по разным родительским записям. Кроме того, дубликаты оказались и в этой таблице:

1 John red
3 John red

Очевидно, что подобные данные приведут к ошибочному анализу и отчетам. Более того, каскадное удаление приведет к потере данных. Например, если мы оставим только строки с минимальным идентификатором в каждой группе в таблице T_pk, то потеряем строку

4 Smith blue

в таблице T_details. Следовательно, мы должны при устранении дубликатов учитывать обе таблицы.

Процедуру "очистки" данных можно провести в два этапа:

  1. Выполнить обновление таблицы T_details, приписав данные, относящиеся к одному имени, к id с минимальным номером в группе.
  2. Удалить дубликаты из таблицы T_pk, оставив только строки с минимальным id в каждой группе с одинаковым значением в столбце name.

Обновление таблицы T_details

Запрос

SELECT id_pk, name, color
    , RANK() OVER(PARTITION BY name, color ORDER BY name, color, id_pk) dup
    ,(SELECT MIN(id)  FROM T_pk WHERE T_pk.name = X.name) min_id
FROM T_pk X JOIN T_details ON id=id_pk

определяет наличие дубликатов (значение dup > 1) и минимальное значение id в группе одинаковых имен (min_id). Вот результат выполнения этого запроса:

id_pk   name    color   dup min_id
1 John blue 1 1
1 John red 1 1
3 John red 2 1
4 Smith blue 1 2
2 Smith green 1 2
2 Smith red 1 2
6 Tom red 1 6

Теперь нам нужно заменить значение id_pk значением min_pk для всех строк, кроме третьей, т.к. эта строка есть дубликат второй строки, о чем говорит значение dup=2. Запрос на обновление можно написать так:

UPDATE T_details
SET id_pk=min_id
FROM T_details T_d JOIN (
  SELECT id_pk, name, color
      , RANK() OVER(PARTITION BY name, color ORDER BY name, color, id_pk) dup
      ,(SELECT MIN(id)  FROM T_pk WHERE T_pk.name = X.name) min_id
  FROM T_pk X JOIN T_details ON id=id_pk
      ) Y ON Y.id_pk=T_d.id_pk
WHERE dup =1

После обновления таблица T_details примет следующий вид:

id_pk   color
1 blue
1 red
2 blue
2 green
2 red
3 red
6 red

Как видно, осталась одна лишняя дубликатная строка:

3 red

Но о ней можно не беспокоиться, так она будет удалена автоматически при каскадном удалении дубликатов из таблицы T_pk:

DELETE
FROM T_pk
WHERE id > (SELECT MIN(id) FROM T_pk X WHERE X.name = T_pk.name)

Последний запрос и является вторым этапом процедуры, в результате выполнения которого мы получим:

Таблица T_pk
id name 
1 John
2 Smith
6 Tom
 
Таблица T_details
id_pk   color
1 blue
1 red
2 blue
2 green
2 red
6 red

Осталось только наложить ограничение, чтобы избежать появления дубликатов в дальнейшем:

ALTER TABLE T_pk
ADD CONSTRAINT unique_name UNIQUE(name)

Полезная информация

§ Приглашаем вас посетить Интерактивный учебник по SQL.
   Ресурс позиционируется как "справочное обеспечение" для сайта SQL-EX.RU, но может использоваться и независимо от него.

§ Онлайновый выпуск рассылки можно почитать на сайте.

§ Все статьи, публикуемые в рассылке, затем выкладываются на сайте Книги и статьи по SQL.

§ Хотите поддержать проект? Вот инструкция по применению.

Контакты

По всем вопросам, связанным с функционированием сайта, проблемами при решении упражнений, идеями вы можете обращаться к Сергею И.Моисеенко msi77[@]yandex.ru. Вы также можете предложить свои задачи для публикации на сайте.

Подписка Subscribe.Ru
Новости сайта "Упражнения по SQL"

В избранное