Новости сайта "Упражнения по SQL" (http://www.sql-ex.ru) 232
Новости сайта "Упражнения по SQL (http://www.sql-ex.ru)"
Выпуск 232 от 7 марта 2009 г.
Новым посетителям сайта
Сайт посвящен изучению языка, с помощью которого осуществляется взаимодействие с реляционными (и не только) СУБД. Суть обучения
состоит в выполнении заданий на написание запросов к учебным базам данных; при этом система контролирует правильность выполнения заданий. В настоящее время реализованы все операторы подъязыка манипуляции данными (DML), которые включают в себя оператор извлечения данных SELECT, а также операторы модификации данных - INSERT, DELETE и UPDATE.
Мы надеемся, что справочного материала сайта окажется достаточно для самостоятельного обучения. Кроме того, свои решения вы можете обсудить на форуме сайта. Опытных же специалистов приглашаем проверить (продемонстрировать) свое мастерство и принять участие в соревновании, обеспечиваемом рейтинговой системой учета времени выполнения заданий. Фактически, рейтинг ведется на втором этапе тестирования, который начинается сейчас после решения 50-й задачи первого этапа. При подсчете рейтинга каждого участника
отбрасывается один самый худший показатель среди всех решенных им упражнений.
Демонстрация плана выполнения запроса и сравнительная оценка эффективности решений поможет вам освоить принципы оптимизации запросов, которые пригодятся на третьем рейтинговом этапе, который начинается после 138 задачи.
Имеется возможность получить сертификат по SQL DML при выполнении определенного количества заданий.
С наступающим праздником, дорогие женщины! Любви, счастья и успехов!
Новости сайта
§ Сбой на хосте обернулся в итоге потерей данных за 2 недели после 17 февраля. Два дня сайт работал в декабрьской версии. Данные тех, кто регистрировался в эти два дня, я восстановил. Те из них, кто успел зарегистрироваться еще и после восстановления к текущей версии, к логину и нику повторной регистрации добавлен суффикс "_rep". Потом, когда будет сделан выбор, я удалю второй логин.
§ Повторные решения потеряных задач второго/третьего этапа вносят сумятицу в сложившуюся "систему ценностей" :-), поэтому я прошу тех, кто повторно решает потеряные задачи этих этапов, сообщать мне (хотя бы приблизительно) время, потраченное ПЕРВОНАЧАЛЬНО на их решение. Как это делают те, кто заинтересован в объективности рейтинга, не дожидаясь приглашения.
§ Постепенно восстанавливаю потерянные данные и функциональность сайта. Процесс достаточно трудоемкий и требует времени, но все будет восстановлено.
§ Изменения среди лидеров (решенные за неделю задачи третьего этапа): 10. Umrikhina (147, 148)
§ Одна задача до третьего этапа осталась: 49. SCAT (задач 137, время 7.415)
§ Продвинулись в рейтинге: 61. B o r i s (133, 181.444)
Являясь более быстрым методом, чем итерационная функция, он более труден для понимания и, вероятно, его трудней распространить на более сложные форматы.
Эти функции не имеют столбца, подобного listpos. С этой целью Вы можете использовать функцию row_number:
listpos = row_number() OVER (ORDER BY s.sliceno, N.Number)
Где sliceno - дополнительный столбец счетчика, который следовало бы добавить к таблице @slices. Возможно, что это скажется на производительности, но я не исследовал этот момент.
По сравнению с другими методами, производительность существенно зависит от полной длины строки, так как мы сравниваем каждый символ во входной строке с символом-разделителем. Таким образом, будут иметь значение и дополнительные пробелы, и длина элементов.
Я не включал никакой функции, которая возвращает список чисел. Вы могли бы написать новую функцию, которая использует convert в соответствующих местах, но Вы можете также поступить следующим образом:
CREATE PROCEDURE get_product_names_tblnum @ids varchar(50) AS
SELECT P.ProductName, P.ProductID
FROM Northwind..Products P
JOIN duo_chunk_split_me(@ids, DEFAULT) i ON
P.ProductID = convert(int, i.str)
go
EXEC get_product_names_tblnum '9, 12, 27, 37'
Несмотря на дробление на куски, все же есть некоторые проблемы надежности при работе с таблицей чисел. Пользователи, например, могут удалить числа в середине или добавить числа, которые не должны там быть. Если Вы параноик, то можете ввести ограничение check, для проверки минимального значения, и написать триггер, который будет грязно ругаться, если кто-нибудь залезет в таблицу. С другой стороны, ограничения и триггеры можно отключить, поэтому истинный параноик вероятно предпочтет другой метод... Кстати,
таблица чисел может пригодиться и для решения других задач SQL, а не только для распаковки разделяемого запятыми списка. Таким образом, весьма полезно было бы иметь подобную таблицу в вашей базе данных.
Массив элементов фиксированной длины
Это метод, который был предложен Стивом Кассом (Steve Kass), SQL Server MVP, вдохновленного идеей, изложенной в книге Кена Хендерсона (Ken Henderson) "The Guru's Guide to Transact-SQL".
Точно так же как XML, этот метод требует специального формата входной строки. Вместо использования разделителей, как в других методах, элементы списка имеют фиксированную длину. Это дает два преимущества: 1) Вы никогда не столкнетесь с проблемой, когда разделитель присутствует в данных. 2) производительность. За исключением очень длинных входных строк, этот метод является самым быстрым среди всех, рассмотренных в этой статье.
Основная идея
Вот простой пример, который непосредственно использует этот метод, без функции:
CREATE PROCEDURE get_product_names_fix @ids varchar(8000),
@itemlen tinyint AS
SELECT P.ProductID, P.ProductName
FROM Northwind..Products P
JOIN Numbers n ON P.ProductID = convert(int,
substring(@ids, @itemlen * (n.Number - 1) + 1, @itemlen))
AND n.Number <= len(@ids) / @itemlen
go
EXEC get_product_names_fix ' 9 12 27 37', 4
Каждый элемент в "массиве" имеет одну и ту же длину, что определено параметром @itemlen. Мы используем функцию substring для извлечения каждого отдельного элемента. Таблица Numbers, которая здесь встречается, представляет собой ту самую таблицу, которую мы создали в начале раздела "Использование таблицы чисел".
А вот функция, которая содержит этот метод:
CREATE FUNCTION fixstring_single(@str nvarchar(MAX), @itemlen tinyint)
RETURNS TABLE AS
RETURN(SELECT listpos = n.Number,
str = substring(@str, @itemlen * (n.Number - 1) + 1, @itemlen)
FROM Numbers n
WHERE n.Number <= len(@str) / @itemlen +
CASE len(@str) % @itemlen WHEN 0 THEN 0 ELSE 1 END)
Цель выражения в последней строке состоит в том, чтобы учесть вариант, когда последний элемент в массиве оказывается короче других в результате потери концевых пробелов. Вы можете увидеть, что эта функция возвращает положение элемента в списке, которое оказывается просто числом из таблицы. Вот пример, использующий fixstring_single со списком строк:
CREATE PROCEDURE get_company_names_fix @customers nvarchar(2000) AS
SELECT C.CustomerID, C.CompanyName
FROM Northwind..Customers C
JOIN fixstring_single(@customers, 6) s ON C.CustomerID = s.str
go
EXEC get_company_names_fix 'ALFKI BONAP CACTU FRANK'
(Продолжение следует...)
Полезная информация
§ Приглашаем вас посетить новый проект - Интерактивный учебник по SQL. Ресурс позиционируется как "справочное обеспечение" для сайта SQL-EX.RU, но может использоваться и независимо от него.
§ Онлайновый выпуск рассылки можно почитать на сайте.
§ Все статьи, публикуемые в рассылке, затем выкладываются на сайте Книги и статьи по SQL.
По всем вопросам, связанным с функционированием сайта, проблемами при решении упражнений, идеями вы можете обращаться к Сергею И.Моисеенко msi77[@]yandex.ru. Вы также можете предложить свои задачи для публикации на сайте.