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

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


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

Выпуск 227 от 31 января 2009 г.

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

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

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

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

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


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

§ Одна задача до третьего этапа осталась:
47. Vasilko (задач 137, время 9.501)

§ Изменения среди лидеров (решенные за неделю задачи третьего этапа):
Смена лидера!
1. GreyC (151, 152)

§ Продвинулись в рейтинге:
48. AKudrakov (136, 38.815)
55. DeadLock5 (134, 144.918)
80. cmalex (127, 123.930)

§ Новые лица в ТОР 100 и вернувшиеся туда:
47. Vasilko (137, 9.501)

§ Продвижение ближайших претендентов на попадание в ТОР 100:
111. antihero (122, 14.949)
124. EffEct (118, 87.113)
126. Edward_rost (121, 186.382)
164. Madest (113, 45.529)

§ На этой неделе сертифицированы:
Panasonic (A09033475) [BK] - г.Чебоксары, Россия
Dimon77777 (A09010756) [BK] - г.Рыбинск, Россия
STARosta (A09040385) [BK] - г.Самара, Россия

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

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

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

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

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

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

No Person Number of
Sel_ex
Last_Sel Number of
DML_ex
Scores Days Days_2 Days_3 S_3 LastSolved LastVisit
1 Сенкевич С.В. (GreyC) 152 152 21 371 358 57.860 27.102 46 26 Jan 2009 30 Jan 2009
2 Селезнёв А.С. (Артём С.) 150 106 21 365 444 47.248 37.524 46 25 Jan 2009 29 Jan 2009
3 Креславский О.М. (Arcan) 152 152 21 371 707 59.893 41.017 46 06 Jan 2009 30 Jan 2009
4 Карасёва Н.В. (vlksm) 152 152 21 371 975 79.787 50.723 46 05 Jan 2009 30 Jan 2009
5 Никотин В.М. (@Nikotin) 150 150 21 365 108 8.371 3.751 40 13 Dec 2008 30 Jan 2009
6 Сальников С.А. ($erges) 150 150 21 365 291 3.487 3.824 40 13 Dec 2008 30 Jan 2009
7 Печатнов В.В. (pvv) 146 149 21 352 357 30.849 17.490 36 10 Oct 2008 30 Jan 2009
8 Муллаханов Р.Х. (rem) 149 152 21 360 483 14.427 20.056 35 05 Jan 2009 30 Jan 2009
9 Зотов П.Г. (Ozzy) 142 147 21 343 307 88.048 105.763 31 11 Jan 2009 30 Jan 2009
10 Шиндин А.В. (AlShin) 147 150 21 355 79 20.458 7.203 30 05 Jan 2009 28 Jan 2009
11 Мурашкин И.В. (lepton) 142 150 21 342 995 47.797 37.312 30 12 Dec 2008 28 Jan 2009
12 Дроздков А.Н. (anddros) 146 151 21 353 237 5.545 6.193 28 19 Jan 2009 30 Jan 2009
13 Держальцев В.А. (MadVet) 137 146 21 333 1257 60.783 28.482 28 24 Sep 2008 30 Dec 2008
14 Любченко В.А. (IAS56) 136 146 21 332 615 403.343 373.617 28 11 May 2008 01 Dec 2008
15 Голубин Р.С. (Roman S. Golubin) 141 69 21 338 1260 93.162 58.822 25 29 Jan 2009 29 Jan 2009
16 Nikolaenko A.V. (Shadow77) 142 147 21 339 436 77.451 14.010 23 22 Oct 2008 11 Dec 2008
17 Солдатенков Ю.С. (SolYUtor) 138 146 21 331 819 22.615 6.102 20 14 Aug 2008 23 Oct 2008
18 Белогурова К. (Katy_Ekb) 133 143 21 321 552 10.666 4.673 18 27 Nov 2008 18 Jan 2009
19 Егоров А.Б. (ABEgorov) 137 144 21 329 180 12.897 8.815 18 03 Aug 2008 12 Aug 2008
20 Умрихина Е.В. (Umrikhina) 143 143 21 343 265 11.700 14.058 18 14 Jan 2009 30 Jan 2009

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

No surname n_sel sel_all sel_scores dml_scores scores rating last_visit
1 Волков В.В. (voxel99) 39 53 80 28 108 1064 30 Jan 2009
2 >Гуйдо А. (gualex) 49 49 93 0 93 1833 30 Jan 2009
3 >Ilinets (dilinets) 38 38 74 0 74 2715 30 Jan 2009
4 >Великанов Е.А. (Silvit) 38 38 73 0 73 2780 30 Jan 2009
5 >Vlasov D. (birdjess) 33 33 61 0 61 3717 30 Jan 2009
6 Безлер В.М. (Vladimir68) 15 47 34 26 60 1234 27 Jan 2009
7 Телегин (_ted_) 23 36 54 0 54 2999 30 Jan 2009
8 >Кожекин И.И. (Iggi) 24 35 54 0 54 3323 30 Jan 2009
9 >Andreev P.M. (irqx) 25 25 45 9 54 4353 30 Jan 2009
10 Дружинин С.Е. (StarleY) 12 45 21 27 48 1222 30 Jan 2009
11 >Тотьмянин С.А. (SCAT) 22 105 46 0 46 214 30 Jan 2009
12 Луковенков А.В. (luks) 15 42 34 12 46 1705 28 Jan 2009
13 Гладких Д.С. (ЗлобнЫЙ_ДобР) 18 86 40 0 40 323 29 Jan 2009
14 Славутинский В.В. (Vasilko) 1 137 4 30 34 47 30 Jan 2009
15 >Savchenko (Ann_S) 14 34 33 0 33 3366 30 Jan 2009
16 Калюжный В. (Alien UA) 14 26 32 0 32 5410 29 Jan 2009
17 Иванов А.И. (Artic21) 13 24 32 0 32 5534 28 Jan 2009
18 Васильев А.В. (alex_v81) 19 68 31 0 31 587 29 Jan 2009
19 Гумницкий М.Е. (Ferron) 12 12 13 17 30 7436 30 Jan 2009

Изучаем SQL

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

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

Назад к функциям

После этого экскурса в CLR, давайте вернемся к теме функций список-в-таблицу. Каковы особенности функций список-в-таблицу, которые используют Split?

Как можно увидеть, мы не возвращаем положение в списке. Насколько я знаю, мы не можем получить позицию в списке таким образом, хотя могу признать, что не рыл в этом направлении. В целом, Split помещает Вас в некотором смысле в смирительную рубашку. Наши возможности ограничены возможностями Split. Сюда входит определение альтернативного разделителя строк, который может быть многосимвольным, и указание, чтобы пустые элементы не возвращались (что я использую в функции для целых чисел). Но это все.

Собственный подход в CLR

Вместо того, чтобы полагаться на Split, мы можем сами сделать его работу. Наградой будет выигрыш в гибкости. Вот C# файл, который длиннее предыдущего:

using System;
using System.Collections;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public class CLR_iter
{

    private class stringiter : IEnumerator
    {
        string  _str;
        char    delim;
        int     _start_ix;
        int     _end_ix;
        int     _listpos;


        public string str {
           get {
              return this._str;
           }
        }

        public int start_ix {
           get {
              return this._start_ix;
           }
        }

        public int end_ix {
           get {
              return this._end_ix;
           }
        }

        public int listpos {
           get {
              return this._listpos;
           }
        }


        public stringiter(SqlString  str,
                          SqlString  delimiter) {
           this._str  = str.IsNull ? "" : str.Value;
           this.delim = delimiter.IsNull ? '\0'
                               : delimiter.Value.ToCharArray(0, 1)[0];
           Reset();
        }

        public bool MoveNext() {
            this._start_ix = this._end_ix + 1;
            if (delim == ' ') {
               while (this._start_ix < this._str.Length &&
                      this.str[this._start_ix] == ' ') {
                  this._start_ix++;
               }
            }

            if (this._start_ix >= this._str.Length) {
               return false;
            }

            this._end_ix = this.str.IndexOf(this.delim, this._start_ix);
            this._listpos++;
            if (this.end_ix == -1) {
               this._end_ix = this._str.Length;
            }
            return true;
        }

        public Object Current {
          get {
            return this;
          }
        }

        public void Reset() {
           this._start_ix = -1;
           this._end_ix   = -1;
           this._listpos  = 0;
        }
    }

    [SqlFunction(FillRowMethodName="CharlistFillRow")]
    public static IEnumerator CLR_charlist_iter(SqlString str,
                                                SqlString delimiter)
    {
        return new stringiter(str, delimiter);
    }

    public static void CharlistFillRow(object     obj,
                                       out int    listpos,
                                       out string str)
    {
        stringiter iter = (stringiter) obj;
        listpos = iter.listpos;
        str = iter.str.Substring(iter.start_ix,
                                 iter.end_ix - iter.start_ix);
        str = str.Trim();
    }


    [SqlFunction(FillRowMethodName="IntlistFillRow")]
    public static IEnumerator CLR_intlist_iter(SqlString str,
                                               SqlString delimiter)
    {
        return new stringiter(str, delimiter);
    }

    public static void IntlistFillRow(object     obj,
                                      out int    listpos,
                                      out int    number)
    {
        stringiter iter = (stringiter) obj;
        listpos = iter.listpos;
        string str = iter.str.Substring(iter.start_ix,
                                        iter.end_ix - iter.start_ix);
        number = System.Convert.ToInt32(str);
    }
}

Ключ - это внутренний класс stringiter. Отметим сначала само объявление класса:

private class stringiter : IEnumerator

Это означает, что класс реализует интерфейс IEnumerator, что является требованием для табличнозначной функции. (Этот или IEnumerable). Затем следуют внутренние переменные класса, и методы для чтения этих значений извне класса. Следующая значимая часть - конструктор:

public stringiter(SqlString  str,
                  SqlString  delimiter) {

Этот метод создает экземпляр класса stringiter. Этот конструктор вызывается из метода входной точки (entry-point method) табличнозначной функции.

Затем следуют MoveNext, Current и Reset. Это методы, которые реализуют интерфейс IEnumerator, и они должны иметь в точности такие имена и подписи, какие указаны выше. (Подробности относительно IEnumerator вы можете найти в .Net Framework SDK). Интерес представляет MoveNext. Именно здесь мы ищем следующий элемент списка, и здесь мы определяем, находимся ли мы в конце списка. Пока MoveNext возвращает истинное значение, будет вызываться метод Fill табличной функции. Таким образом, MoveNext возвращает ложь не тогда, когда он находит последний элемент, а на следующем шаге. (Надеюсь, что понял это правильно. Я не смог выяснить это в документации, так что пришлось идти экспериментальным путем).

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

После кода для класса stringiter идут два метода входной точки в сопровождении методов заполнения, один для строк, а другой для целых чисел. В противоположность предыдущему примеру с Split, точки входа здесь возвращают IEnumerator, поскольку мы сами реализуем IEnumerator. Но подобно примеру со Split все, что делают точки входа, - это создают объект stringiter.

Наконец, методы Fill извлекают данные из текущего объекта stringiter. Наиболее примечательным является то, что я вытаскиваю позицию в списке, в результате чего она может появиться в выходной таблице.

Для полноты изложения приведу SQL объявления для этих функций:

CREATE FUNCTION CLR_charlist_iter(@list nvarchar(MAX),
                                  @delim nchar(1) = ',')
RETURNS TABLE (listpos int,
               str     nvarchar(4000))
AS EXTERNAL NAME CLR_iter.CLR_iter.CLR_charlist_iter
go
CREATE FUNCTION CLR_intlist_iter(@list nvarchar(MAX),
                                 @delim nchar(1) = ' ')
RETURNS TABLE (listpos int,
               number  int)
AS EXTERNAL NAME CLR_iter.CLR_iter.CLR_intlist_iter
go

Настолько ли лучше эти последние функции, чем первая пара, которая использовала Split? Ну, нет. Вы получаете позицию в списке, и функция intlist имеет параметр для разделителя. Производительность фактически идентична на моем тесте. Главное в том, что вы получаете структуру, с которой можно работать, если Вам требуется обрабатывать более сложные форматы списков или добавить другие функциональные возможности, отсутствующие в данных функциях. Здесь, я использовал тот же самый класс счётчика для строк и целых чисел, но знатоку, которым Вы хотите стать, вероятно, лучше использовать другие классы.

Если Вы добавите больше колокольчиков и звоночков, придется ли заплатить за это производительностью? Отчасти, но если Вы не делаете что-то действительно сложное, то незначительно. Например, если Вы хотите добавить поддержку многосимвольных разделителей, то вам придется использовать отличную перегрузку IndexOf, который выполняет интеллектуальный поиск, и который, вероятно, станет более сложным. Когда я пробовал это делать, то получил рост времени выполнения приблизительно на 5-7 %. Что вряд ли должно сильно встревожить. Даже если Вы удвоите время выполнения, то Вы все еще будете впереди итерационного метода.

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

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

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

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

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

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

Контакты

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

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

В избранное