Logo    
Деловая газета CitCity.ru CITKIT.ru - все об Open Source Форумы Все публикации Учебный центр Курилка
CitForum    CITForum на CD    Подписка на новости портала Море(!) аналитической информации! :: CITFORUM.RU
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

22.05.2017

Google
WWW CITForum.ru
С Новым годом!

Уважаемые читатели!

Журнал Database Programming and Design уже второй месяц предоставляет возможность электронного доступа к колонке Кристофера Дейта "According to Date". В майском выпуске господин Дейт начал публиковать интересную заметку по поводу избыточности средств языка SQL. Мне показалось полезным предложить вашему вниманию первую часть этой заметки. Прошу обратить внимание, что в примерах используется SQL-92. Думаю, что многие из вас не обращали внимание на соответствующие возможности этого языка. Если вас интересуют другие работы К.Дейта, обращайтесь в электронный книжный магазин www.mistral.ru.

С уважением, Сергей Кузнецов


DataBase Programming & Design OnLine, May 1998

www.dbpd.com

A discussion of some redundances in SQL

Greevous Bodily Harm (Part 1 of 2)

C.J. Date
оригинал статьи можно найти по адресу
http://www.dbpd.com/9805date.htm

Кристофер Дейт является независимым автором, лектором, исследователем и консультантом, специализирующимся в области систем реляционных баз данных. Корресподенцию ему можно послать по почте по адресу: Database Programming & Design, 411 Borel Ave., Ste. 100, San Mateo, CA 94402.

Известно ли вам, что разделы GROUP BY и HAVING (для их совместного названия далее используется аббревиатура GBH) в языке SQL избыточны? Другими словами, любой осмысленный запрос, который можен быть выражен с использованием одного из этих разделов или их обоих может быть выражен и без их применения. (Ниже поясняется значение слова "осмысленный".)

Раздел GROUP BY

В качестве основы примеров используется известная по книгам К. Дейта база данных "поставщики и детали":

	 S ( S#, SNAME, STATUS, CITY )
	    PRIMARY KEY ( S# )
	 
	 P ( P#, PNAME, COLOR, WEIGHT, CITY )
	    PRIMARY KEY ( P# )
	 
	 SP ( S#, P#, QTY )
	     PRIMARY KEY ( S#, P# )
	     FOREIGN KEY ( S#) REFERENCES S
	     FOREIGN KEY ( P#) REFERENCES  P

Вот запрос к этой базе данных, для которой люди "естественно" используют раздел GROUP BY:

	 Q1: Для каждой поставляемой детали выдать номер детали,
	 максимальное и минимальное число поставок.

"Естественной" (с применением GROUP BY) формулировкой запрса является следующая:

	 SELECT SP.P#, MAX(SP.QTY) AS MXQ, MIN(SP.QTY) AS MNQ
	 FROM SP
	 GROUP BY SP.P# ;
Предположим, что база данных содержит следующие значения:
	 S                                        SP
	 
	 S#   SNAME   STATUS     CITY              S#   P#   QTY
	 -------------------------------           --------------
	 S1   SMITH     20      LONDON             S1   P1   300
	 S2   JONES     10      PARIS              S1   P2   200
	 S3   BLAKE     30      PARIS              S1   P3   400
	 S4   CLARK     20      LONDON             S1   P4   200
	 S5   ADAMS     30      ATHENS             S1   P5   100
	                                           S1   P6   100
	 P                                         S2   P1   300
	                                           S2   P2   400
	 P#   PNAME   COLOR   WEIGHT    CITY       S3   P2   200
	 ------------------------------------      S4   P2   200
	 P1    Nut     Red      12     London      S4   P4   300
	 P2    Bolt   Green     17      Paris      S4   P5   400
	 P3   Screw    Blue     17      Rome
	 P4   Screw    Red      14     London
	 P5    Cam     Blue     12      Paris
	 P6    Cog     Red      19      Rome
Тогда результатом запроса будет следующая таблица:
	 P#   MXQ   MNQ
	 ---------------
	 P1   300   300
	 P2   400   200
	 P3   400   400
	 P4   300   200
	 P5   400   100
	 P6   100   100
Вот другая формулировка того же самого запроса без использования GROUP BY:
	 SELECT DISTINCT SP.P#,
	            (SELECT MAX(SPX.QTY)
	              FROM SP AS SPX
	              WHERE SPX.P# = SP.P#) AS MXQ,
	            (SELECT MIN(SPX.QTY)
	              FROM SP AS SPX
	              WHERE SPX.P# = SP.P#) AS MXQ
	 FROM SP ;

Конечно, эта формулировка немного дленнее предыдущей, но логически они эквивалентны. Обобщая этот пример, можно вывести следующее заключение:

Пусть имеется таблица R { A, B, ... } и пусть agg - это агрегатная функция (например, SUM, MAX или MIN), применимая к столбцу R.B. Тогда выражение

	 SELECT R.A, agg(R.B) AS C
	 FROM R
	 GROUP BY R.A ;
может быть логически преобразовано в эквивалентное выражение
	 SELECT DISTINCT R.A
	            (SELECT agg(RX.B)
	              FROM R AS RX
	              WHERE RX.A = R.A) AS C)
	 FROM R) ;
Будем далее называть это преобразование преобразованием Типа 1.

Теперь рассмотрим, что произойдет, если в исходной формулировке с GROUP BY будет присутствовать раздел WHERE. Расширим запрос Q1:

	 Q2: Для каждой поставляемой детали выдать номер детали,
	 максимальное и минимальное число поставок, но при этом не
	 принимать во внимание поставки поставщика S1.
Вот формулировка с GROUP BY:
	 SELECT SP.P#, MAX(SP.QTY) AS MXQ, MIN(SP.QTY) AS MNQ
	 FROM SP
	 WHERE SP.S# <> 'S1'
	 GROUP BY SP.P# ;

Эквивалентная формулировка запроса без GROUP BY (не единственная из числа возможных) не намного хитрее:

	 SELECT DISTINCT SP.P#,
	            (SELECT MAX(SPX.QTY)
	              FROM SP AS SPX
	              WHERE SPX.P# = SP.P#
	              AND SPX.S# <> 'S1') AS MXQ,
	            (SELECT MIN(SPX.QTY)
	              FROM SP AS SPX
	              WHERE SPX.P# = SP.P#
	              AND SPX.S# <> 'S1') AS MNQ,
	 FROM SP
	 WHERE SP.S# <> 'S1' ;

Как видно, раздел WHERE из исходной формулировки с GROUP BY размножился в двух вложенных выражениях раздела SELECT. В исходной формулировке раздел WHERE управляет как разделом SELECT, так и разделом GROUP BY. Последовательность записи разделов в языке SQL несколько нелогична. В общем случае выражение, включающее разделы SELECT-FROM-WHERE-GROUP BY вычисляется в последовательности FROM-WHERE-GROUP BY-SELECT, и имело бы смысл писать именно в таком порядке. Но язык SQL этого не позволяет.

Как видно из приведенного выше примера, преобразование Типа 1 нуждается лишь в незначительных расширениях, чтобы включать возможность использования раздела WHERE. Детали очевидны. Еще раз изменим наш пример:

	Q3: Для каждой поставляемой детали выдать максимальное число
	поставок, но без номера детали.
Формулировка с GROUP BY:
	SELECT MAX(SP.QTY) AS MXQ
	 FROM SP
	 GROUP BY SP.P# ;
С использованием преобразования Типа 1 мы получим следующую формулировку:
	 SELECT DISTINCT (SELECT MAX(SPX.QTY)
	                  FROM SP AS SPX
	                  WHERE SPX.P# = SP.P# AS MXQ
	 FROM SP ;
Вот результаты выполнения этих двух запросов:
	  С GROUP BY               Без GROUP BY
	 
	     MXQ                       MXQ
	    -----                     -----
	     300                       300
	     400                       400
	     400                       100
	     300
	     400
	     100

Как видно, результаты разные, т.е. запросы не совсем эквивалентны, и преобразование Типа 1 не работает в этом частном случае. Но действительной причиной отсутствия эквивалентности является то, что результат выполнения запроса с GROUP BY не есть отношение, поскольку содержит строки-дубликаты. Более существенно то, что дубликаты осмысленны. Например, у двух строк "300" разный смысл: одна из них означает, что у некоторой детали максимальный объем поставок равен 300, а другая - что имеется некоторая другая деталь с тем же самым максимальным объемом поставок. Эти "осмысленные дубликаты" представляют собой очень существенный отход от базовых принципов реляционной модели данных. Возможность их наличия говорит о том, что SQL не является и никогда не был истинно реляционным языком.

Заметим, что при использовании SQL "осмысленные дубликаты" могут появляться в ряде других случаев. Например, даже такое простое выражение как

	SELECT CITY
	 FROM S ;
в общем случае производит результат с "осмысленными дубликатами".

Еще раз осмыслим запрос Q3. Что он на самом деле означает? Похоже, что нас интересовало множество максимальных поставок из SP. Формулировка без GROUP BY корректно производит эту информацию. Конечно, в результате не показывается, для каких конкретных деталей производились максимальные поставки, но требуемая информация предоставляется.

Формулировка с GROUP BY дает ту же самую информацию. Поэтому она допустима. Но некоторые люди (к числу которых не относится господин Дейт) могли бы сказать, что поскольку поставляются данные о шести деталях, то эта формулировка предпочтительнее той, которая без GROUP BY. Следует заметить, что эта информация представлена в нереляционной форме. Было бы корректнее получать ее по-другому, например, с использованием запроса Q1.

По мнению автора, запросы вида Q3, хотя и являются допустимыми, не слишком осмысленны. Такие запросы игнорируют существенную информацию. Обычно это связано с тем, что в раздел SELECT входят не все столбцы, используемые в разделе GROUP BY. Для подобных формулировок преобразование Типа 1 "работает некорректно". Но это преобразование работает правильно для всех "осмысленных" запросов.

Раздел HAVING

Вот запрос, для формулировки которого большинство людей использовало бы раздел HAVING:

	Q4: Для каждой детали, поставляемой более чем одним поставщиком,
	выдать номер детали.
Возможной формулировкой с использованием GHB могла бы быть следующая:
	SELECT SP.P#
	 FROM SP
	 GROUP BY SP.P#
	 HAVING COUNT(*) > 1 ;
Результатом такого запроса является таблица
	    P#
	  -----
	    P1
	    P2
	    P4
	    P5
Вот формулировка без использования разделов GROUP BY и HAVING:
	SELECT DISTINCT SP.P#
	 FROM SP
	 WHERE (SELECT COUNT(*)
	         FROM SP AS SPX
	         WHERE SPX.P# = SP.P#) > 1 ;

Снова эта формулировка длиннее варианта с GBH, но логически они эквивалентны. И опять легко обобщить пример. Если использовать обозначения из предыдущего раздела, то выражение

	SELECT R.A
	 FROM R
	 GROUP BY R.A
	 HAVING agg(R.B) comp scalar ;

(где comp является некоторой операцией скалярного сравнения, а scalar - некоторое скалярное выражение) может быть логически преобразовано к эквивалентному выражению

	SELECT DISTINCT R.A
	 FROM R
	 WHERE (SELECT agg(R.B)
	         FROM R AS RX
	         WHERE RX.A = R.A) comp scalar ;

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

	Q5: Для каждой детали, поставляемой более чем одним поставщиком
	(кроме поставщика S1), выдать номер детали.
Формулировка с GBH:
	SELECT SP.P#
	 FROM SP
	 WHERE SP.P# <> 'S1'
	 GROUP BY SP.P#
	 HAVING COUNT(*) > 1 ;
Формулировка без GBH лишь немного хитрее:
	SELECT DISTINCT SP.P#
	 FROM SP
	 WHERE (SELECT COUNT(*)
	         FROM SP AS SPX
	         WHERE SPX.P# = SP.P#
	         AND SPX.S# <> 'S1') > 1 ;

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

	Q6: Для каждой детали, поставляемой более чем одним поставщиком,
	выдать номер детали и общее число поставок этой детали.
Формулировка запроса с использованием GBH:
	SELECT SP.P#, SUM(SP.QTY) AS TQY
	 FROM SP
	 GROUP BY SP.P#
	 HAVING COUNT(*) > 1 ;
Применяя правила преобразований Типа 1 и 2, получим следующее:
	SELECT DISTINCT SP.P#,
	             (SELECT SUM(SPX.QTY)
	               FROM SP AS SPX
	               WHERE SPX.P# = SP.P#) AS TQY
	 FROM SP
	 WHERE (SELECT COUNT(*)
	         FROM SP AS SPX
	         WHERE SPX.P# = SP.P#) > 1 ;
И еще один пример:
	Q7: Для каждой детали, поставляемой более чем одним поставщиком,
	выдать общее число поставок этой детали, но без номера детали.
Вот формулировка с применением GBH:
	SELECT SUM(SP.QTY) AS TQY
	 FROM SP
	 GROUP BY SP.P#
	 HAVING COUNT(*) > 1 ;
Преобразованный вариант:
	SELECT (SELECT SUM(SPX.QTY)
	               FROM SP AS SPX
	               WHERE SPX.P# = SP.P#) AS TQY
	 FROM SP
	 WHERE (SELECT COUNT(*)
	         FROM SP AS SPX
	         WHERE SPX.P# = SP.P#) > 1 ;

В результате выполнения этих запросов были бы получены следующие результаты:

	  С GROUP BY               Без GROUP BY
	  и HAVING                 и HAVING
	 
	     TQY                       TQY
	    -----                     -----
	     600                       600
	    1000                      1000
	     500                       500
	     500

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

Размещение рекламы — тел. +7 495 4119920, ICQ 232284597

Подписка на новости IT-портала CITForum.ru
(библиотека, CITKIT.ru, CitCity)

Новые публикации:

24 декабря

CITKIT.ru:

  • Новогодние поздравления
  • Сергей Кузнецов. Цикл Операционные системы: Ностальгия по будущему:

  • Алексей Федорчук. OpenSolaris 2008.11 Release

  • Сергей Голубев:

  • Евгений Чайкин aka StraNNik (Блогометки):

    17 декабря

  • С.Д.Кузнецов. Базы данных. Вводный курс

    10 декабря

    CITKIT.ru:

  • OpenSolaris 2008.11 Release

  • Альтернативные ОС: две грустные истории (С.Кузнецов)
  • Nokia N810 — доведение до ума
  • CitCity:

  • Платформа 2009: заоблачные перспективы Microsoft

    4 декабря

  • Лекция С.Д.Кузнецова Понятие модели данных. Обзор разновидностей моделей данных

    CITKIT.ru:

  • OpenSolaris 2008.11 Release. Первые впечатления

  • Linux vs FreeBSD: продолжим "Священные войны"?

  • Nokia N810 as is

  • Индульгенция для FOSS

  • Друзья СПО'2008

    26 ноября

  • Нечеткое сравнение коллекций: семантический и алгоритмический аспекты

    CitCity:

    CITKIT.ru:

  • Глава из книги А.Федорчука
    Сага о FreeBSD:
  • 19 ноября

  • Проблемы экономики производства крупных программных продуктов

  • Язык модификации данных формата XML функциональными методами

    CITKIT.ru:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:

    Заметки к книге:

  • FreeBSD: монтирование сменных устройств и механизм HAL
  • Текстовый редактор ee

    12 ноября

  • Правило пяти минут двадцать лет спустя, и как флэш-память изменяет правила (Гоц Грейф, перевод: Сергей Кузнецов)

    CITKIT.ru:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:
  • OSS в России: взгляд правоведа (В.Житомирский)

  • Новая статья из цикла С.Голубева "Железный марш":

    29 октября

  • О некоторых задачах обратной инженерии

  • Веб-сервисы и Ruby

  • Тестирование web-приложений с помощью Ruby

    CITKIT.ru:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:

  • PuppyRus Linux - беседа с разработчиком (С.Голубев)

  • Сергей Кузнецов. Заметка не про Linux

    22 октября

  • Обзор методов описания встраиваемой аппаратуры и построения инструментария кросс-разработки

    CITKIT.ru:

  • Сергей Кузнецов. Почему я равнодушен к Linux

  • Глава из книги А.Федорчука
    Сага о FreeBSD:
  • Что надо иметь
    3. Базовые познания

    CitCity:

  • Управление IT-инфраструктурой на основе продуктов Microsoft

    15 октября

  • Методы бикластеризации для анализа интернет-данных

    CitCity:

  • Разъемы на ноутбуках: что они дают и зачем их так много?
  • AMD Puma и Intel Centrino 2: кто лучше?

    CITKIT.ru:

  • Новый цикл статей С.Голубева
    Железный марш:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:

    8 октября

  • Автоматизация тестирования web-приложений, основанных на скриптовых языках
  • Опыт применения технологии Azov для тестирования библиотеки Qt3

    Обзоры журнала Computer:

  • SOA с гарантией качества
  • Пикоджоуль ватт бережет
  • ICT и всемирное развитие

    CitCity:

  • Пиррова победа корпорации Microsoft

    CITKIT.ru:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:

    Статья из архива:

  • Я живу в FreeBSD (Вадим Колонцов)

    Новые Блогометки:

  • Перекройка шаблона Blogger или N шагов к настоящему
  • Blogger. Comment style
  • Screenie или глянцевый снимок экрана

    2 октября

    CITKIT.ru:

  • Сага о FreeBSD (А. Федорчук)

    Zenwalk: пакет недели

  • Банинг — интеллектуальное развлечение (С.Голубев)

    CitCity:

    25 сентября

  • Клермонтский отчет об исследованиях в области баз данных

    CITKIT.ru:

  • Пользователям просьба не беспокоиться... (В.Попов)

  • Снова про ZFS: диск хорошо, а два лучше
  • Командная оболочка tcsh (А.Федорчук)

    Zenwalk: пакет недели

    17 сентября

  • T2C: технология автоматизированной разработки тестов базовой функциональности программных интерфейсов
  • Технология Azov автоматизации массового создания тестов работоспособности

    CITKIT.ru:

  • FreeBSD: ZFS vs UFS, и обе-две — против всех (А.Федорчук)

    Zenwalk: пакет недели

  • Дачнет — практика без теории (С.Голубев)

    10 сентября

  • За чем следить и чем управлять при работе приложений с Oracle
  • Планировщик заданий в Oracle
    (В.Пржиялковский)

    CITKIT.ru:

  • Microsoft: ответный "боян" (С.Голубев)

  • Причуды симбиоза, или снова "сделай сам" (В.Попов)

  • Файловые системы современного Linux'а: последнее тестирование
  • Zsh. Введение и обзор возможностей
    (А.Федорчук)

    Описания пакетов Zenwalk: Zsh, Thunar, Thunar-bulk-rename, Xfce4-places-plugin, Xfce4-fsguard-plugin

    Блогометки:

  • Google Chrome
  • Лончер для ASUS Eee PC 701

    3 сентября

    CITKIT.ru:

  • Заметки о ядре (А.Федорчук):

    Добавлены описания пакетов Zenwalk: Galculator, Screenshot, Gnumeric, Pidgin

    В дискуссинном клубе:

  • И еще о Википедии и Google Knol

  • Лекция для начинающего линуксоида (С.Голубев)

    26 августа

  • Транзакционная память (Пересказ: С. Кузнецов)

    CITKIT.ru:

  • Открыт новый проект Zenwalk: пакет недели

  • Статья Текстовые процессоры и их быстродействие: конец еще одной легенды?

    21 августа

    CITKIT.ru:

  • Почему школам следует использовать только свободные программы (Ричард Столлман)
  • Беседа Сергея Голубева с учителем В.В.Михайловым

  • Википедия или Гуглезнание? Приглашение к обсуждению (Алексей Федорчук)
  • Народная энциклопедия от Google (StraNNik)

  • Обзор Mandriva 2009.0 Beta 1 Thornicrofti
  • Новичок в Линукс: Оптимизируем Mandriva 2008.1

  • Книга Zenwalk. Приобщение к Linux:

    13 августа

    CitCity:

  • Мирный Atom на службе человеку. Обзор платы Intel D945GCLF с интегрированным процессором
  • Обзор процессоров Intel Atom 230 на ядре Diamondville

  • iPhone - год спустя. Скоро и в России?

    CITKIT.ru:

  • Интермедия 3.4. GRUB: установка и настройка (из книги Zenwalk. Приобщение к Linux)

    6 августа

  • СУБД с хранением данных по столбцами и по строкам: насколько они отличаются в действительности? (Пересказ: С. Кузнецов)

    CITKIT.ru:

  • Интермедия 2.2. Что неплохо знать для начала (из книги Zenwalk. Приобщение к Linux)

  • И снова про шрифты в Иксах (А.Федорчук)

  • 20 самых быстрых и простых оконных менеджеров для Linux

  • Дело о трех миллиардах (С.Голубев)

    30 июля

  • OLTP в Зазеркалье (Пересказ: С. Кузнецов)

    CitCity:

  • Будущее BI в облаках?
  • Тиражные приложения и заказная разработка. Преимущества для заказчика
  • Дискуссия со сторонниками заказной разработки

    CITKIT.ru:

  • Новые главы книги Zenwalk. Приобщение к Linux:
  • Глава 8. Пакеты: средства установки, системы управления, системы построения
  • Глава 9. Zenwalk: репозитории, пакеты, методы установки

    23 июля

    CITKIT.ru:

  • Все против всех. 64 vs 32, Intel vs AMD, tmpfs vs ext3
  • Две головы от Intel

  • Zenwalk: обзор штатных приложений (глава из книги "Zenwalk. Приобщение к Linux")

  • Нормально, Григорий...

    16 июля

    Обзоры журнала Computer:

  • Перспективы и проблемы программной инженерии в XXI веке
  • Большие хлопоты с большими объемами данных
  • Перспективы наноэлектроники

    CITKIT.ru:

  • Интермедия о лицензиях (А.Федорчук. "Zenwalk. Приобщение к Linux")

  • Есть ли будущее у KDE?

  • Linux в школе: альтернативный вариант в задачах

  • Шифр (приключения агента Никодима)

    10 июля

    CITKIT.ru:

  • Новые разделы книги А. Федорчука Zenwalk. Приобщение к Linux:
  • Интермедия вступительная. Linux или GNU/Linux? Как вас теперь называть?
  • Глава 5. Среда Xfce
  • Глава 6. Xfce: приложения и плагины

  • ZUR (Zenwalk User Repository) FAQ

    2 июля

  • Персистентность данных в объектно-ориентированных приложениях (С. Кузнецов)

    CITKIT.ru:

  • Новые разделы книги А. Федорчука Zenwalk. Приобщение к Linux:
  • Интермедия 1.2. Дорога к Zenwalk'у. Период бури и натиска
  • Интермедия 3.3. Немного о Linux'е и "железе"
  • Глава 4. Настройка: инструментами и руками
  • Интермедия 4.1. Zenpanel и конфиги: поиски корреляции

  • Интервью с Жан-Филиппом Гийоменом, создателем дистрибутива Zenwalk

  • Linux в школе: первые итоги (С. Голубев)

    25 июня

    CITKIT.ru:

  • Zenwalk. Приобщение к Linux (А. Федорчук)

  • Логика и риторика (С.Голубев)

  • Технология Tru64 AdvFS

  • Ханс Райзер предлагает отвести полицейских к телу Нины

    18 июня

  • Проекты по управлению данными в Google (Пересказ: С. Кузнецов)

    CITKIT.ru:

  • ОС и поддержка "железа": мифы и реальность (А. Федорчук)

  • Linux в школе: другие дистрибутивы

  • Пинок (С. Голубев)

    4 июня

  • Ландшафт области управления данными: аналитический обзор (С. Кузнецов)

    CITKIT.ru:

  • Linux в школе: слово заинтересованным лицам

  • SlackBuild: пакеты своими руками

  • Linux от компании Novell. Установка и обзор openSUSE Linux

    Все публикации >>>




  • IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

    Информация для рекламодателей PR-акции, размещение рекламы — тел. +7 495 4119920, ICQ 232284597 Пресс-релизы — pr@citcity.ru
    Послать комментарий
    Информация для авторов
    Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
    Copyright © 1997-2000 CIT, © 2001-2007 CIT Forum
    Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...