46378 (665526), страница 3

Файл №665526 46378 (MS SQL Server 9 “Yukon”. Интеграция с .NET) 3 страница46378 (665526) страница 32016-07-31СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 3)

Большинству разработчиков для построения своих приложений вполне хватает стандартного набора агрегирующих функций. Однако теперь настал праздник и для редких любителей сделать что-то необычное – в новом MS SQL Server можно реализовать свой способ выйти за пределы SUM, AVG и СOUNT.

Создаются они при помощи оператора CREATE AGGREGATE:

CREATE AGGREGATE [ schema_name. ] aggregate_name

( @param_name )

RETURNS

EXTERNAL NAME assembly_name [ :class_name ]

::=

system_scalar_type | { [ udt_schema_name. ] udt_type_name }

::=

system_scalar_type | { [ udt_schema_name. ] udt_type_name }

На этот раз написания одного метода недостаточно. Вместо этого для подсчета агрегатов используются объекты. Идея проста – по мере просмотра исходных данных мы накапливаем то, что нужно накапливать, а зетем выводим накопленное в выходной набор. Соответственно для каждого из этих действий нужно реализовать по методу:

Имя метода

Описание

public void Init()public void Init(input_type value)

Инициализирует объект. Вызывается один раз на группу агрегируемых значений. Если реализована версия метода с одним параметром, то SQL Server может использовать ее для передачи первого значения в группе. Тип параметра value (input_type) должен быть совместимым с тем типом, который указан как input_sqltype в операторе CREATE AGGREGATE.

public void Accumulate(input_type value)

После инициализации объекта, сервер вызывает этот метод по одному разу для каждого агрегируемого значения. (На список подаваемых на вход значений, помимо состава полей в операторе GROUP BY, оказывает влияние также и наличие ключевого слова distinct перед агрегируемым выражением. Как и для встроенных функций, это ключевое слово приведет к тому, что в список для каждой группы попадут только различные значения агрегируемого выражения). Тип параметра value должен быть совместимым с тем типом, который указан как input_sqltype в операторе CREATE AGGREGATE.

public return_type Terminate()

Несмотря на страшное название, этот метод всего лишь должен вернуть то самое агрегированное значение, которое было вычислено для группы входных значений. Тип результата должен быть совместимым с тем типом, который указан как return_sqltype в операторе CREATE AGGREGATE.

public void Merge(udagg_type group)

Этот метод предназначен для случаев, когда SQL Server создает больше одного агрегирующего объекта на одну группу входных значений. Например, при выполнении запроса на многопроцессорной машине, входные данные могут быть разделены на несколько потоков для одновременной обработки. Перед выводом данных необходимо выполнить слияние рассчитанных агрегатных значений. Именно это и делает этот метод. Он принимает единственный параметр того же класса, в котором объявлен.

Таблица 4.

Помимо этих методов, у класса должен быть определен конструктор без аргументов (иначе SQL Server не сможет создавать объекты этого класса). Кроме того, должна быть обеспечена возможность сериализации объектов – для случаев, когда серверу нужно сохранить промежуточный результат на диске. Мы отложим описание подробностей сериализации до следующего раздела, а пока что попробуем сделать свою функцию для вычисления среднего геометрического.

Тем, кто плохо помнит школьный курс, напомню, что среднее геометрическое из N чисел – это корень N-ной степени из их произведения. (А среднее арифметическое N чисел, которое обычно и подразумевается под термином «среднее значение» - это сумма этих чисел, деленная на N).

ПРИМЕЧАНИЕ

К сожалению, расчет среднего геометрического по определению очень быстро приводит к переполнению даже на очень небольших наборах входных данных – произведение растет слишком быстро. Поэтому мы схитрим и воспользуемся тем математическим фактом, что произведение N чисел равно экспоненте от суммы их логарифмов. Вместо извлечения корня степени N (а это то же самое, что и возведение в степень 1/N) мы поделим на N сумму логарифмов перед применением функции Exp().

[Serializable]

[SqlUserDefinedAggregate(Format.Native, IsInvariantToDuplicates = false, IsInvariantToNulls = true, IsInvariantToOrder = true, IsNullIfEmpty = true)]

[StructLayout(LayoutKind.Sequential)]

public class AvgGeom: INullable

{

private double _agg;

private int _count;

private bool _isNull = true;

#region User-Defined Attribute Required Methods

public void Init()

{

_agg = 0;

_count = 0;

_isNull = true;

}

public void Accumulate(SqlDouble Value)

{

if (!Value.IsNull)

{

_agg += System.Math.Log(Value.Value);

_count++;

_isNull = false;

}

}

public void Merge(AvgGeom Group)

{

if (!Group.IsNull)

{

_agg += Group._agg;

_count += Group._count;

_isNull = false;

}

}

public SqlDouble Terminate()

{

if (IsNull)

return SqlDouble.Null;

else

return new SqlDouble(System.Math.Exp(_agg / _count));

}

#endregion

#region INullable Members

public bool IsNull

{

get

{

return _isNull;

}

}

#endregion

}

В первую очередь обратим внимание на атрибут SqlUserDefinedAggregate, который предваряет описание нашего класса. В нем определено несколько параметров (таблица 5).

Имя параметра

Описание

Format

Формат сериализации объектов этого класса. Подробности – в следующем разделе.

MaxByteSize

Максимальный размер сериализованного объекта. Подробности – в следующем разделе.

IsInvariantToDuplicates

Зависит ли агрегированное значение от наличия дубликатов во входных данных (по умолчанию – да). Например, для функции MIN() совершенно неважно, сколько раз повторяются входные значения, а для функции SUM() – важно. Оптимизатор запросов SQL Server может использовать эту информацию для минимизации количества вызовов метода Accumulate.

IsInvariantToNulls

Влияет ли наличие NULL-значений во входных данных на агрегированное значение. Для большинства встроенных агрегирующих функций (кроме COUNT()) это так.

IsNullIfEmpty

Означает, что агрегирующая функция возвращает NULL для пустых входных наборов. Например, функция MIN при выполнении на пустом наборе возвращает как раз NULL , а функция COUNT() – 0.

IsInvariantToOrder

Данный параметр пока не документирован; судя по названию, он должен определять, влияет ли на результат порядок подачи значений в метод Accumulate(). См. примечание после таблицы

Таблица 5.

ПРЕДУПРЕЖДЕНИЕ

Все встроенные агрегирующие функции (а также наш пример) являются коммутативными, что позволяет серверу выбирать порядок сканирования входных данных по своему усмотрению. Однако, например, результат функций типа First() или Last(), (которые должны возвращать соответственно первое или последнее значение в наборе), очевидным образом зависит от порядка входных значений. Тем не менее, пока непонятно, как можно использовать подобные функции – дело в том, что синтаксис SQL не позволяет определять порядок агрегирования записей. Оператор ORDER BY применим только к выходному набору записей, и использовать в нем можно только те поля, по которым выполняется группировка. В обычных вложенных запросах (по результатам которых можно строить запросы с группировкой) применение ORDER BY запрещено. Скорее всего (это только мое предположение!) разработчики MS SQL Server Yukon предполагают использовать свойство SqlUserDefinedAggregateAttribute.IsInvariantToOrder для тех случаев, когда программист каким-либо способом все же может гарантировать определенное упорядочивание входных данных – это свойство должно убедить сервер воздержаться от переупорядочивания записей перед агрегированием. Пока что мне не удалось обнаружить какого-либо влияния этого свойства на поведение сервера.

Для того, чтобы наш объект мог принимать значение NULL, необходимо реализовать интерфейс INullable. Этот интерфейс определяет единственное read-only свойство bool IsNull. Все классы из System.Data.SqlTypes реализуют этот интерфейс. В нашем примере объект принимает значение NULL при инициализации, и перестает быть Null сразу, как только ему будет передано не-NULL значение в метод Accumulate или Merge.

Пользовательские типы данных

Систему типов SQL Server можно расширить с помощью пользовательских типов данных (User-defined Types, UDT). Пользовательские типы реализуются как управляемый класс на любом из CLR-языков и регистрируются в SQL Server. Такой тип можно использовать для определения типа колонки в таблице, или как переменную (параметр процедуры) в выражении Т-SQL. При этом методы объектов можно вызывать прямо из T-SQL.

Создание пользовательского типа данных

В T-SQL пользовательский тип данных регистрируется при помощи оператора CREATE TYPE:

CREATE TYPE [ type_schema_name. ] type_name

{ [ FROM base_type [ ( precision [ , scale ] ) | ( 'urn:schema-namespace' ) ]

[ NULL | NOT NULL ] ]

| [ EXTERNAL NAME [ assembly_schema_name. ] assembly_name [ :class_name ] ]

}

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

Альтернативой прямому использованию T-SQL, как и в других случаях, служит автоматическое развертывание проектов MS Visual Studio .Net Whidbey. Классы, помеченные атрибутом SqlUserDefinedType (мы подробно рассмотрим его чуть позже – при обсуждении сериализации) автоматически регистрируются в качестве пользовательских типов при развертывании проектов типа SQL Server Project.

Для того, чтобы класс .NET можно было использовать в качестве пользовательского типа данных SQL Server, он должен выполнять некоторые обязанности:

Иметь конструктор без параметров. Как правило, он возвращает экземпляр, соответствующий значению NULL (об этом далее).

Поддерживать NULL-значения. Класс должен реализовывать интерфейс INullable, который описан в предыдущем разделе. Также необходима реализация в классе статического свойства Null, которое возвращает NULL-объект этого класса, т.е. должно быть MyClass.Null.IsNull == true. Все методы должны корректно обрабатывать передачу в параметрах как экземпляра Null, так и значения null.

Поддерживать конверсию в строку и обратно: в классе должен быть определен метод Parse(SqlString s) и должным образом перекрыт метод ToString().

Поддерживать сериализацию. Поскольку объекты этого класса будут храниться на диске, необходимо обеспечить преобразование в «плоский» формат (а также восстановление).

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

В качестве упражнения я реализовал тип «точка на плоскости». Он умеет представлять свои координаты как в декартовых, так и в полярных координатах.

using System;

using System.Data.Sql;

using System.Data.SqlTypes;

using System.Text.RegularExpressions;

using System.Runtime.InteropServices;

[Serializable]

[SqlUserDefinedType(Format.Native)]

[StructLayout(LayoutKind.Sequential)]

public class SqlPoint: INullable

{

#region NULLability

private bool _isNull = true;

public bool IsNull

{

get

{

return _isNull;

}

}

public static SqlPoint Null

{

get

{

return new SqlPoint();

}

}

#endregion

#region Конверсия в строку и обратно

public override string ToString()

{

return IsNull? "null" : String.Format("X: {0}; Y: {1}", x, y);

}

public static SqlPoint Parse(SqlString s)

{ // Я не очень хорошо владею регулярными выражениями,

// тем не менее, этот метод в состоянии преобразовать

// результат вызова метода ToString обратно в SqlPoint.

if (s.IsNull || s.Value.ToLower() == "null")

return Null;

SqlPoint p = new SqlPoint();

Regex t = new Regex(@"x:(?\d*(\.\d+)?)\s*\W*y:(?\d*(\.\d+)?)",

RegexOptions.IgnoreCase);

Match match = t.Match(s.Value);

p.x = SqlDouble.Parse(match.Groups["x"].Value);

p.y = SqlDouble.Parse(match.Groups["y"].Value);

return p;

}

#endregion

#region Наши данные

private double _x=0;

private double _y=0;

public SqlDouble x

{

get

{

return IsNull ? SqlDouble.Null : new SqlDouble(_x);

}

set

{

if (!value.IsNull)

{

_x = value.Value;

_isNull = false;

}

}

}

public SqlDouble y

{

get { return IsNull? SqlDouble.Null: new SqlDouble(_y); }

set

{

if (!value.IsNull)

{

_y = value.Value;

_isNull = false;

}

}

}

public SqlDouble R // А эти свойства мы будем вычислять.

{

get

{

return IsNull

? SqlDouble.Null

: new SqlDouble(System.Math.Sqrt(_y*_y +_x*_x));

}

set

{

if (value.IsNull)

{

_isNull = true;

return;

}

double alpha = Alpha.IsNull? 0 : Alpha.Value;

_x = System.Math.Cos(alpha) * value.Value;

_y = System.Math.Sin(alpha) * value.Value;

}

}

public SqlDouble Alpha

{

get

{

return (IsNull)

? SqlDouble.Null

: new SqlDouble(System.Math.Atan2(_y, _x));

}

set

{

if (value.IsNull)

{

_isNull = true;

return;

}

double r = R.IsNull ? 0 : R.Value;

_x = System.Math.Cos(value.Value) * r;

_y = System.Math.Sin(value.Value) * r;

}

}

#endregion

}

После регистрации данного класса как пользовательского типа выполнение вот таких запросов:

declare @p SqlPoint

set @p::x = 3

set @p::y = 4

select @p::x, @p::y, @p::R, @p::ToString()

set @p::R = 10

select @p::x, @p::y, @p::R, @p::ToString()

set @p::Alpha = 0

select @p::x, @p::y, @p::R, @p::ToString()

set @p = convert(SqlPoint, ' x:6; y:5.00')

select @p::x, @p::y, @p::R, @p::ToString()

Приводит к результатам, приведенным в таблице 6:

@p::x

@p::y

@p::R

@p::ToString()

3.0

4.0

5.0

X: 3; Y: 4

6.0000000000000009

7.9999999999999991

10.0

X: 6; Y: 8

10.0

0.0

10.0

X: 10; Y: 0

6.0

5.0

7.810249675906654

X: 6; Y: 5

Таблица 6

В приведенном выше примере продемонстрирована работа с членами объектов пользовательских типов. Синтаксис достаточно прост – оператором выбора члена объекта выступает двойное двоеточие.

Характеристики

Тип файла
Документ
Размер
263,85 Kb
Тип материала
Учебное заведение
Неизвестно

Список файлов реферата

Свежие статьи
Популярно сейчас
А знаете ли Вы, что из года в год задания практически не меняются? Математика, преподаваемая в учебных заведениях, никак не менялась минимум 30 лет. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6618
Авторов
на СтудИзбе
295
Средний доход
с одного платного файла
Обучение Подробнее