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

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


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

Выпуск 237 от 11 апреля 2009 г.

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

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

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

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

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


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

§ Привел все строковые данные проверочных баз к единой коллации. Это устранит некоторые проблемы, иногда возникающие с проверкой запросов.
Пишите, если возникнут подозрения, что я что-то упустил.

§ Автор изменила формулировку задачи 141.

§ На этой неделе добавил еще несколько ссылок на соответствующие разделы справки к упражнениями обучающего этапа.

§ Собираюсь выставить несколько новых задач. Надеюсь, что изменения коснутся всех этапов. :-)

§ Изменения среди лидеров (решенные за неделю задачи третьего этапа):
6. Ozzy (151)
7. Umrikhina (151)

§ Продвижение ближайших претендентов на попадание в ТОР 100:
133. Avtolic (задач 134, время 16.190)
136. maar (119, 88.582)
140. _irina_ (119, 27.138)

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

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

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

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

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

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

No Person Number of
Sel_ex
Last_Sel Number of
DML_ex
Scores Days Days_2 Days_3 S_3 LastSolved LastVisit
1 Креславский О.М. (Arcan)1 154 154 21 376 782 65.266 46.391 53 22 Mar 2009 10 Apr 2009
2 Карасёва Н.В. (vlksm)1 154 154 21 376 1049 90.124 61.061 53 20 Mar 2009 10 Apr 2009
3 Сальников С.А. ($erges)1 153 153 21 372 392 3.854 4.191 49 24 Mar 2009 10 Apr 2009
4 Сенкевич С.В. (GreyC)1 152 152 21 369 358 57.860 27.102 46 26 Jan 2009 10 Apr 2009
5 Селезнёв А.С. (Артём С.)1 150 152 21 363 444 47.248 37.524 46 25 Jan 2009 03 Mar 2009
6 Зотов П.Г. (Ozzy)6 147 153 21 356 395 136.260 153.974 46 09 Apr 2009 10 Apr 2009
7 Умрихина Е.В. (Umrikhina)6 151 151 21 366 349 23.045 25.404 43 08 Apr 2009 10 Apr 2009
8 Дроздков А.Н. (anddros)7 150 154 21 365 309 6.461 7.110 42 01 Apr 2009 10 Apr 2009
9 Никотин В.М. (@Nikotin)1 150 150 21 363 108 8.371 3.751 40 13 Dec 2008 10 Apr 2009
10 Печатнов В.В. (pvv)1 146 149 21 350 357 30.849 17.490 36 10 Oct 2008 09 Apr 2009
11 Мурашкин И.В. (lepton)1 144 152 21 346 1066 68.477 57.992 36 21 Feb 2009 10 Apr 2009
12 Муллаханов Р.Х. (rem)9 149 152 21 358 483 14.427 20.056 35 05 Jan 2009 10 Apr 2009
13 Шиндин А.В. (AlShin)10 147 150 21 353 79 20.458 7.203 30 05 Jan 2009 28 Jan 2009
14 Держальцев В.А. (MadVet)7 137 146 21 331 1257 60.783 28.482 28 24 Sep 2008 30 Dec 2008
15 Любченко В.А. (IAS56)6 136 146 21 330 615 403.343 373.617 28 11 May 2008 01 Dec 2008
16 Голубин Р.С. (Roman S. Golubin)3 141 145 21 336 1260 93.162 58.822 25 29 Jan 2009 08 Feb 2009
17 Nikolaenko A.V. (Shadow77)12 142 147 21 337 436 77.451 14.010 23 22 Oct 2008 11 Dec 2008
18 Солдатенков Ю.С. (SolYUtor)2 138 146 21 329 819 22.615 6.102 20 14 Aug 2008 01 Apr 2009
19 Белогурова К. (Katy_Ekb)19 133 143 21 319 552 10.666 4.673 18 27 Nov 2008 18 Jan 2009
20 Егоров А.Б. (ABEgorov)20 137 144 21 327 180 12.897 8.815 18 03 Aug 2008 12 Aug 2008

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

No surname n_sel sel_all sel_scores dml_scores scores rating last_visit
1 >Мартыненко В.Ю. (Fuddy-Duddy) 52 52 96 0 96 1830 10 Apr 2009
2 >Поляков С.Г. (Ivanoff Alex) 44 44 83 6 89 1271 10 Apr 2009
3 Битюков Г.С. (Kopernik) 42 42 83 0 83 2321 09 Apr 2009
4 Гарифзянов Т. (garifzyanov) 44 44 82 0 82 2357 09 Apr 2009
5 Петренко (reazon) 16 50 30 32 62 1092 07 Apr 2009
6 puzikov 1.2. (tulup) 26 39 62 0 62 2700 09 Apr 2009
7 Димка (Димка) 33 33 62 0 62 3722 07 Apr 2009
8 >Рогачёв А.А. (aint) 27 51 55 3 58 1775 10 Apr 2009
9 Федосов В.В. (Федосов В) 19 40 39 17 56 1920 10 Apr 2009
10 Купцов А.В. (Digger) 29 29 54 0 54 4485 09 Apr 2009
11 >St D. (Dmitriy_S) 23 48 46 6 52 1476 10 Apr 2009
12 Вишневский И.С. (hot-dee) 23 29 45 5 50 4333 10 Apr 2009
13 Лабутин П.А. (Лабутин П.А.) 16 50 28 21 49 1164 10 Apr 2009
14 Szen K. (occulta) 15 68 27 16 43 837 10 Apr 2009
15 >marat (lMn) 6 82 10 32 42 355 10 Apr 2009
16 >Streicher (vonstr) 25 25 41 0 41 6058 10 Apr 2009
17 >Орлов М.В. (Орлов Михаил) 23 53 40 0 40 1002 10 Apr 2009
18 Жуков (zadachi-11) 17 28 40 0 40 4729 08 Apr 2009
19 Ноздрачев Д.В. (DenZ) 22 22 36 3 39 6310 09 Apr 2009
20 >Смирнов М.А. (MADpro) 15 35 36 0 36 3406 10 Apr 2009
21 Tesher (VadimT) 15 29 35 0 35 4610 07 Apr 2009
22 >Sinyayeva Y. (OrmhaXan) 11 21 18 16 34 5506 10 Apr 2009
23 >Кононов А.Е. (AlexSoft) 17 17 30 4 34 6843 10 Apr 2009
24 Кошкарова Е.А. (sonne_shko) 15 24 33 0 33 5834 08 Apr 2009
25 >Antanevich Y. (Avtolic) 14 134 32 0 32 133 10 Apr 2009
26 >Валеев М.А. (mksv) 8 67 16 14 30 803 10 Apr 2009

Изучаем SQL

Массивы и списки в SQL Server 2005 (начало в вып.217-229, 231-236)

Erland Sommarskog (оригинал: Arrays and Lists in SQL Server 2005 )
Перевод: Моисеенко С.И.

Превращение списка в набор операторов SELECT

Вставка большого числа строк

Теперь давайте посмотрим на метод с точки зрения необходимости вставки многих строк.

Скажем, по некоторым причинам Вы не хотите использовать XML. Вы понимаете, что передача по одному оператору INSERT на каждую добавляемую строку не очень эффективна, помимо прочего, из-за большого числа сообщений, передаваемых по сети; поэтому Вы хотите передать за одно обращение весь пакет строк.

Самый быстрый способ сделать это состоит в использовании массовой вставки. Для этого вы можете воспользоваться утилитой BCP, оператором BULK INSERT или процедурами массовой вставки клиентского API. Кроме того, Вы можете использовать службу SQL Server Integration Services. Массовая вставка и SSIS выходят за рамки этой статьи, поэтому я не буду вдаваться в детали. В любом случае это методы, которые Вы используете, когда Вы импортируете большие файлы данных. Если Вы имеете сетку на 8 000 строк, использование API для массовой вставки может привести к краху.

Бесхитростный подход состоит в том, чтобы запустить пакет с большим числом операторов INSERT VALUES. Только не забудьте включить в пакет SET NOCOUNT ON, иначе каждый INSERT будет генерировать сообщение (1 row affected), возвращаемое клиенту, и Вы опять придете к увеличению сетевого трафика. Это не бог весть что, не более чем по одной вставке строки за раз. А как можно вставить много строк одним оператором? Вот способ:

INSERT tbl (...)
   SELECT val1a, val2a, val3a
   UNION ALL
   SELECT val1b, val2b, val3b
   UNION ALL
   ...

То есть вместо большого количества операторов INSERT Вы имеете один большой толстый SELECT с множеством предложений UNION ALL. Увы, это не даст хорошей производительности. Для небольших пакетов размером около 20 элементов, это решение будет быстрее множественных операторов INSERT. Но по мере роста пакета, время, которое требуется оптимизатору для компиляции пакета, резко возрастает, и общее время выполнения может в несколько раз превысить время пакета, состоящего из INSERT VALUES. Один из способов преодоления этого состоит в генерации множества пакетов типа INSERT SELECT UNION с разумным размером каждого в пределах 20-50 элементов. Это даст Вам лучший из рассмотренных методов.

Однако есть третий метод, который намного быстрее. Вы получаете преимущество единственного оператора INSERT, и при этом не платите за компиляцию. Трюк заключается в использовании INSERT-EXEC, который был предложен мне Джимом Эбберсом (Jim Ebbers):

INSERT sometable (a, b, c)
   EXEC('SELECT 1, ''New York'', 234
         SELECT 2, ''London'', 923
         SELECT 3, ''Paris'', 1024
         SELECT 4, ''Munich'', 1980')

Обычно, когда Вы используете INSERT-EXEC, у Вас имеется хранимая процедура или пакет динамического SQL, который возвращает один результирующий набор, и этот результирующий набор вставляется в таблицу. Но если хранимая процедура или пакет динамического SQL возвращают множественные результирующие наборы, этот метод работает, если все результирующие наборы имеют одну и ту же структуру. Причина, по которой этот метод намного быстрее использования UNOIN, заключается в том, что каждый оператор SELECT компилируется независимо. Единственная сложность этого метода состоит в необходимости следить за правильностью расстановки вложенных кавычек при генерации оператора.

Вас может удивить, что я предлагаю здесь динамический SQL, учитывая то, насколько прохладным к нему я был в предыдущем разделе. Но дело состоит в том, что все три предложенные здесь метода предполагают, что клиент должен генерировать полный пакет - с операторами INSERT, значениями и т.д., а что это как не динамический SQL? Таким образом, у Вас есть только один путь в ситуациях, когда разрешения не являются проблемой. (Которые могут иметь место, поскольку таблица вставляется во временную таблицу, и позже хранимая процедура вставляет строки из временной таблицы в целевую таблицу.) Очевидно, что Вы должны были бы тут принять меры для борьбы с инъекцией SQL.

Списки с разделителями-запятыми

Это, возможно, не кажется очевидным, но представленные выше методы можно использовать в качестве основы для распаковки разделенных запятыми списков, хотя следует прямо сказать, это больше подходит для раздела "Сумасшедшие вещи, которые Вы можете сделать в T-SQL". Трудно придумать ситуацию, для которой этот метод стал бы лучшим выбором.

Первоначально эта идея была предложена Стивом Кассом (Steve Kass). Процедура состоит в использовании функции replace для замены разделителя пустой строкой. В оригинальном предложении Стив Касс использовал UNION ALL SELECT, и затем добавлял еще некоторые манипуляции со строкой, чтобы в результате получить пакет SQL. После этого Вы можете использовать INSERT EXEC для вставки результата выполнения пакета SQL во временную таблицу, которую Вы затем используете в вашем целевом запросе. Хотя UNION имеет очень плохую производительность, я сначала продемонстрирую хранимую процедуру, которая использует UNION, по одной простой причине - этот код более прост для понимания, чем последующий:

CREATE PROCEDURE unpack_with_union
                 @list      nvarchar(MAX),
                 @tbl       varchar(30),
                 @delimiter nchar(1) = N',' AS
DECLARE @sql nvarchar(MAX),
        @q1  char(1),
        @q2  char(2)
SELECT @q1 = char(39), @q2 = char(39) + char(39)
SELECT @sql = 'INSERT INTO ' + @tbl + ' SELECT ' +
               replace(replace(@list, @q1, @q2), @delimiter,
                       N' UNION ALL SELECT ')
--PRINT @sql
EXEC (@sql)

Внутренний replace используется для обработки потенциально опасной ситуации, когда @list включает одиночные кавычки. Мы их удваиваем в попытке защитить себя от инъекции SQL. Внешний replace заменяет разделитель заглушкой. Название таблицы, куда будут вставлены строки, передается через параметр @tbl. Переменные @q1 и @q2 предохраняют меня от беспорядка одинарных кавычек.

Вот пример использования:

CREATE PROCEDURE get_product_names_union @ids varchar(50) AS
   CREATE TABLE #temp (id int NULL)

   EXEC unpack_with_union @ids, '#temp'

   SELECT P.ProductName, P.ProductID
   FROM   Northwind..Products P
   JOIN   #temp t ON P.ProductID = t.id
go
EXEC get_product_names_union '9, 12, 27, 37'

Причина, по которой мы используем процедуру, а не функцию, очевидна - мы не можем использовать динамический SQL в функциях.

(Продолжение следует...)

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

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

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

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

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

Контакты

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

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

В избранное