« Поставить закладку » « Сделать стартовой »

« Форумы » « Блоги » « Статьи » « Новости » « Файлы » « Realcoding IRC » « Site map » « Поиск »



Рубрика: Базы данных




Вышел MySQL 5.1.30, первый стабильный рели....

MySQL

После публикации 29 тестовых версий анонсирован первый стабильный релиз MySQL 5.1, пригодный для промышленной эксплуатации и обеспечивающий увеличение производительности для "тяжелых" SQL запросов, по сравнению с MySQL 5.0, примерно на 15-20%. Главные новшества появившиеся в MySQL 5.1:


Подробнее... | Рубрика: MySQL | Добавлено: 28.11.2008

Тестирование параллельных программ.

Тестирование

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


Подробнее... | Рубрика: Тестирование | Добавлено: 28.11.2008

Архитектура AMD64 (EM64T).

Архитектура AMD

Аннотация. В статье кратко рассматривается архитектура AMD64 компании AMD и ее реализация EM64T компании Intel. Описаны особенности архитектуры, ее возможности, достоинства и недостатки.


Подробнее... | Рубрика: Архитектура AMD | Добавлено: 27.11.2008

Остальные статьи:



Главная Главная
Анонсы Анонсы
Форумы Форумы
Каталог Каталог
Поиск Поиск
Опросы Опросы
Книжный магазин Книжный магазин
Реклама на сайте
Публикации Публикации
Партнеры Партнеры
Карта Карта сайта
Рассылки Рассылки
RSS экспорт
Настройки Настройки
О нас пишут О нас пишут
Контакты Контакты
Гостевая книга Гостевая книга


ПнВтСрЧтПтСбВс
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
    Популярное
Просмотр табличной базы данных

Руководство по работе с БД Firebird с использованием библиотеки ADO .Net 2.0

Фотомонтажим на PHP

Защита приложений от крупных шрифтов.

Проeкт - шифровка

Работа с WDDX в РНР

ГЛАВА 6 Определение и использование примитивов

Использование resx ресурсов в Visual Studio .NET

Функция ValidateFreeSpaces

ИСПОЛЬЗОВАНИЕ ШАБЛОНОВ ПРИ ПРОГРАММИРОВАНИИ WEB-ПРИЛОЖЕНИЙ В СРЕДЕ PERL




    Архив файлов



    Сообщества

    Документация

    Кто на сайте
Вы не зарегистрированы.
Имя:

Пароль:

Запомнить

Регистрация позволит Вам пользоваться дополнительными сервисами.
Сейчас на сайте:
Гостей: 197
Пользователей: 0

Статьи:: Базы данных :: Работа с множествами в Transact-SQL



отправить ссылку другу версия для печати  Обсудить на форуме

Работа с множествами в Transact-SQL



Автор: Александр Уз (usalex@mail.ru)

Один из недостатков MS SQL Server (по сравнению с ORACLE) – почти полное отсутствие готовых функций для работы с  множествами (здесь и далее подразумеваются уникальные множества, в которых нет повторяющихся значений). Чтобы, например, получить разность двух множеств (в ORACLE  операция MUNUS), приходится писать довольно сложные SQL выражения. При изменении операции (когда, вместо (A – B) надо выполнить (B – A)) выражение приходится переписывать. А сконструировать выражение для 3 и более множеств – задача совсем не из простых.

Данная статья предлагает «унифицированный» способ операций с множествами. Становится возможным построение операций по единому шаблону, не зависящему от типа выполняемой операции и количества множеств (но не более чем с 64 множествами). Построение выражений для операции со многими множествами становятся легче. Тип операции указывается параметром, не затрагивая само выражение.

Статья состоит из 3 частей:

  1. Обзор операций с множествами
  2. Обзор традиционных приёмов операций над множествами для T-SQL
  3. Предлагаемый автором унифицированный метод работы с множествами


Части 1 и 2 рассчитаны на начинающих.

Часть 1. Операции над множествами.

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

Рассмотрим следующий пример: в Субботу и Воскресенье у Вас были гости:

СБ (Множество А)

ВС (Множество В)

Ольга

Светлана

Пётр

Пётр

(если бы в один день пришли 2 Петра, Вы записали бы, например, так: Пётр_1 и Пётр_2)

Графически некоторые очевидные операции над этими множествами можно представить следующим образом:

Объединение Пересечение Разность A-B Симметричная разность
Все гости, которые приходили на выходных

Гости, которые приходили в СБ и в ВС. Т.е. только те, кто был оба дня подряд

Гости, которые пришли в СБ, но не пришли в ВС

Гости, которые пришли только в один из выходных, но не оба дня подряд

Ольга, Пётр, Светлана

Пётр

Ольга

Ольга, Светлана

Часть 2. Традиционные приёмы работы с множествами для Transact-SQL

Создадим таблицы:

  CREATE TABLE #A(FName varchar(10)Primary key) 
  INSERT #A(FName) values('Olga') 
  INSERT #A(FName) values('Peter') 
  CREATE TABLE #B(FName varchar(10) Primary key) 
  INSERT #B(FName) values('Svetlana')
  INSERT #B(FName) values('Peter')
  
Объединение:

(точнее было бы сказать слияние)

Для этого есть стандартный оператор SQL – UNION.

Если выполняем

  SELECT FName FROM #A
  UNION ALL
  SELECT FName FROM #B 
  

то получаем элементы всех множеств «слепленные» вместе:

Olga
Peter
Peter
Svetlana

Обратите внимание, что Peter попал в результат дважды.

если выполняем

  SELECT FName FROM #A 
  UNION 
  SELECT FName FROM #B
  

то в результирующем множестве каждый элемент будет повторен только один раз:

Olga
Peter
Svetlana

Пересечение:

Эту задачу можно выполнить с помощью т.н. JOIN-объединения (не путать с предыдущим объединением), обычного или коррелированного подзапроса:

С помощью JOIN-объединения:

  SELECT #A.FName 
  FROM #A INNER JOIN #B on #A.FName = #B.FName
  

То же, но с помощью обычного подзапроса:

  SELECT FName 
  FROM #A 
  WHERE FName IN(SELECT FName FROM #B)
  

То же, но с помощью коррелированного подзапроса:

  SELECT FName FROM #A 
  WHERE EXISTS
  (SELECT * FROM #B WHERE #B.FName = #A.FName)
  

Примечание:

Коррелированный подзапрос отличается от обычного тем, что он выполняется как подпрограмма, по разу для каждой строки в таблице #A. При этом значение каждой строки #A.FName передаётся в подзапрос как параметр.

Разность

В MS SQL Server2000 нет операции MINUS, как в ORACLE. Поэтому приходится изощряться, чтобы получить тот же результат:

С помощью обычного подзапроса:

  SELECT FName FROM #A 
  WHERE 
  FName NOT IN(SELECT FName FROM #B)
  

Пояснение: вначале выполняется подзапрос. Затем выполняется основной запрос, который ищет и выводит все строки таблицы #A, отсутствующие в таблице #B.

С помощью коррелированного подзапроса:

  SELECT * FROM #A 
  WHERE 
  NOT EXISTS (SELECT * FROM #B WHERE #B.FName = #A.FName)
  

Пояснение: Каждая строка из таблицы #A по одной передаётся в подзапрос. Там ищется, есть ли такая запись в таблице #B. Если нет, то соответствующая строка из таблицы #A будет приобщена к результату.

С помощью LEFT OUTER JOIN:

  SELECT #A.FName FROM 
  #A LEFT OUTER JOIN #B ON (#A.FName = #B.FName)
  WHERE
  #B.FName IS NULL
  
Симметричная разность

Эту операцию придётся выполнить как комбинацию из нескольких предыдущих операций. Как и ранее, есть выбор в вариантах реализации:

разность #A минус #B объединить с разностью #B минус #A:

  SELECT FName FROM #A 
  WHERE 
  FName NOT IN(SELECT FName FROM #B)
  UNION
  SELECT FName FROM #B
  WHERE 
  FName NOT IN(SELECT FName FROM #A)
  

из объединения #A с #B вычесть пересечение #A с #B

Итак, пересечение #A с #B

  SELECT FName FROM #A
  UNION
  SELECT FName FROM #B
  

Объединение #A с #B

  SELECT #A.FName 
  FROM #A, #B
  WHERE #A.FName = #B.FName
  

и всё вместе:

  SELECT BIGTAB.FName 
  FROM 
  (SELECT FName FROM #A
  UNION
  SELECT FName FROM #B)BIGTAB
  WHERE 
  FName NOT IN(SELECT #A.FName 
  FROM #A, #B 
  WHERE  
  #A.FName = #B.FName)
  

Литература для части 2:
Ken Henderson, The Guru’s Guide to Transact-SQL ISBN 0-201-61576-2

Часть 3. Унифицированный метод работы с множествами

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

Присвоим каждому первоначальному множеству (т.е. A и B) бинарный идентификатор как степень 2:  1 для A, 2 для B. Если имеем большее количество множеств, например A,B,C,D то 4 для C и 8 для D и т.д.

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

Унифицированная конструкция приобретает вид:

  SELECT Column1, Column2, и т.д.  FROM 
  ( 
     SELECT Column1, Column2, и т.д., 1 as TAB_ID from TABLE1 
     UNION ALL 
     SELECT Column1, Column2, и т.д., 2 as TAB_ID from TABLE2 
     UNION ALL 
     SELECT Column1, Column2, и т.д., 4 as TAB_ID from TABLE3 
     и т.д.,   
  )SUPERTAB 
  group by Column1, Column2, и т.д. 
  HAVING SUM(TAB_ID) in (перечисление или выражение) 
  

Для удобства работы с перечислением (в операторе HAVING) можно использовать следующую схему:

Для двух множеств Для трёх множеств

Посмотрите на пример для 3 множеств: Примитивные множества 1,2,4 назовём «первичными», а множества 3,5,6,7 «вторичными», так как они состоят из пересечений «первичных» множеств. Идентификатор таблицы, собственно, не что иное, как обычная битовая маска. Каждая битовая позиция соответствует определённому примитивному первичному множеству.

Все варианты для 4 и более множеств рисунком на плоскости не представить, но схема действий – та же.

Теперь выполним несколько операций по этому способу.

Для ясности сопроводим каждую операцию рисунком. Закрашенная область показывает, какие примитивные подмножества должны попасть в результирующий набор.

На нашем примере (изменённая часть маркирована цветом):

Пересечение:
	  SELECT FName FROM 
        (
           SELECT FName, 1 as TAB_ID from #A
           UNION ALL 
           SELECT FName, 2 as TAB_ID from #B
        )SUPERTAB 
        group by FName 
        HAVING SUM(TAB_ID) in (3)
		
Разность А – В:
	  SELECT FName FROM
        ( 
           SELECT FName, 1 as TAB_ID from #A 
           UNION ALL 
           SELECT FName, 2 as TAB_ID from #B 
        )SUPERTAB 
        group by FName 
        HAVING SUM(TAB_ID) in (1)
		
Разность В – А:
	  SELECT FName FROM 
        ( 
           SELECT FName, 1 as TAB_ID from #A 
           UNION ALL 
           SELECT FName, 2 as TAB_ID from #B 
        )SUPERTAB 
        group by FName 
        HAVING SUM(TAB_ID) in (2)
		
Симметричная разность:
	  SELECT FName FROM 
        ( 
           SELECT FName, 1 as TAB_ID from #A 
           UNION ALL 
           SELECT FName, 2 as TAB_ID from #B 
        )SUPERTAB 
        group by FName 
        HAVING SUM(TAB_ID) in (1,2)
		

Теперь несколько операций с 3 множествами:

  CREATE TABLE #T1(Col1 varchar(1), Col2 varchar(1), primary key(col1,Col2)) 
  insert #T1 values('a','a') 
  insert #T1 values('b','b') 
  insert #T1 values('c','c') 
  CREATE TABLE #T2(Col1 varchar(1), Col2 varchar(1), primary key(col1,Col2)) 
  insert #T2 values('b','b') 
  insert #T2 values('c','c') 
  insert #T2 values('d','d') 
  CREATE TABLE #T3(Col1 varchar(1), Col2 varchar(1), primary key(col1,Col2)) 
  insert #T3 values('c','c') 
  insert #T3 values('d','d') 
  insert #T3 values('e','e')
  
Пересечение A, B и C:
	  SELECT Col1, Col2 FROM 
        ( 
           SELECT Col1, Col2, 1 as TAB_ID from #T1 
           UNION ALL 
           SELECT Col1, Col2, 2 as TAB_ID from #T2 
           UNION ALL 
           SELECT Col1, Col2, 4 as TAB_ID from #T3 
        )SUPERTAB 
        group by Col1,Col2 
        HAVING SUM(TAB_ID) in (7)
		
Разность Т1 – Т2 – Т3
	  SELECT Col1, Col2 FROM 
        ( 
           SELECT Col1, Col2, 1 as TAB_ID from #T1 
           UNION ALL 
           SELECT Col1, Col2, 2 as TAB_ID from #T2 
           UNION ALL 
           SELECT Col1, Col2, 4 as TAB_ID from #T3 
        )SUPERTAB 
        group by Col1,Col2 
        HAVING SUM(TAB_ID) in (1)
		
Симметричная разность для T1, T2 и T3
	  SELECT Col1, Col2 FROM 
        ( 
           SELECT Col1, Col2, 1 as TAB_ID from #T1 
           UNION ALL 
           SELECT Col1, Col2, 2 as TAB_ID from #T2 
           UNION ALL 
           SELECT Col1, Col2, 4 as TAB_ID from #T3 
        )SUPERTAB 
        group by Col1,Col2 
        HAVING SUM(TAB_ID) in (1,2,4)
		
Симметричная разность T1 с T2 объединяется с T3
	  SELECT Col1, Col2 FROM 
        ( 
           SELECT Col1, Col2, 1 as TAB_ID from #T1 
           UNION ALL 
           SELECT Col1, Col2, 2 as TAB_ID from #T2 
           UNION ALL 
           SELECT Col1, Col2, 4 as TAB_ID from #T3 
        )SUPERTAB 
        group by Col1,Col2 
        HAVING SUM(TAB_ID) in (1,2,4,5,6,7)
		

Заключение

Как Вы заметили, существуют некоторые закономерности.

Пересечению множеств всегда соответствует сумма идентификаторов. Разности - идентификатор вычитаемого. Симметричной разности – перечисление идентификаторов первичных множеств. И т.д. Пользуясь этими закономерностями, можно было бы даже написать некую процедуру, что-то типа калькулятора множеств. Как параметр она принимала бы имена таблиц и выражение, которое надо вычислить.  

К достоинствам предлагаемого способа можно отнести его лёгкую «программируемость» в динамическом SQL. Особенно в случаях, когда заранее не известно, какую операцию придётся выполнять. Удобно работать с таблицами, содержащими много столбцов, так как не надо связывать соответствующие столбцы из разных таблиц, как при использовании JOIN.

Производительность способа пока не измерялась. Возможно, она ниже, чем с JOIN. Если кто измерит, пожалуйста, сообщите.

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

Буду раз узнать Ваше мнение.

Платформа 2009. Определяя будущее
Windows Vista Bridge Sample Library - упра...
Оптимизация 64-битных программ
Подгрузка через AJAX HTML-кода, содержащег...
Обзор нового релиза самой мощной Ajax библ...
Firebug 1.3 и 1.4 alpha — что нового и инт...
Релиз Microsoft Silverlight 2.0. Что новог...
XML документация в C#
Курсоры в MySQL 5
Microsoft опубликовала подробности о сесси...
Microsoft делится подробностями о том, что...
Тестируем новый javascript от нового брауз...
MySQL Query Cache
Использование провайдеров компиляции в As...
Чего мы ждем от C# 4.0
Delphi 2009 и C++Builder 2009
Джоэл Спольски и Джеф Этвуд запустили новы...
Поиск кода Google /* что нового? */
10 jQuery скриптов для улучшения интерфейс...
Генераторы отчетов FastReport 4 и QuickRep...


Цитата дня (все,добавить):

Портал фрилансеров

работа на дому


    Рубрикатор

Программирование

C/С++
Обучение
Windows API
XAML
Моделирование
Паттерны
Visual Basic 7 .NET
WxWidgets
Функции WinApi
Функции С++
Разработка под Mac OS
Eiffel
Visual Studio 2008
UI дизайн
Алгоритмы
Конкурсные статьи
Turbo Pascal
Visual Studio
CASE-средства
Visual Studio 2005
Без VCL
Delphi
Тех. документация
Тестирование
Software Testing
ООП
TCP/IP
Google Android
Windows Installer
.NET Framework
Драйвера
C# C Sharp
Справка
Проектирование
Информ. системы
Visual Basic
Assembler
Оптимизация кода
Gtk+
Компоненты
Реинжиниринг
Управление проектами
Extreeme programming
Lotus Notes
Алгебраическое проектирование


Интернет технологии

PHP
Perl
ASP
WAP
Cookies
SSI
CGI
Web Servers
VB Script
DNS
CSS
XML
Html
Java Script
Java2ME
Firewall
Flash
.htaccess
Apache
VRML
Протоколы
Поисковые системы
Технология JAVA
Учебник по PHP
Учебник по JavaScript
Учебник по XML
Java Q&A
AJAX
DHTML
XHTML
Dreamweaver
Web 2.0
Python
Вебмастеру
Cisco
Ruby on Rails
Silverlight

Базы данных

Access
InterBase
MySQL
Oracle
ADO .NET
Основы SQL
Учебник по Access 2002
MS
Microsoft FoxPro
Доступ к данным
XML в MS SQL Server 2000
ODBC и MyODBC
Обучение
Caché
DB2
PostgresSQL
Sybase
Теория
Хранилища данных
Безопасность
Реляционные данные
MySQL и mSQL

Остальное:

Разное
Обзоры книг
Безопасность
Графика и дизайн
Юмор
Linux
Фракталы
Microsoft Axapta
Многоядерность
Сети
Microsoft Office
Работа
MS-DOS
Криптография
Графика и игроделание
Новости SDK
Системы защиты
Учебник по AutoCad
CVS
Windows XP
Windows Server 2003
Windows Vista
Windows 7
Мероприятия