Форум FAQ О команде
Поиск по сайту:
 
Sybase
Sybase ASA  
Sybase ASE  
Sybase IQ  
Sybase PowerDesigner  
Sybase PowerBuilder  

Продукты
Наши продукты  
Продукты партнеров портала  

Сообщества
Alef community  

Меню
Регистрация  
Почта  

Вход

Рассылка
Рассылка 'РСУБД Sybase ASA 9 - мощность, легкость и надежность'
Почтовая рассылка
"Технологии обработки данных компании Sybase"


Статистика
Яндекс цитирования

Rambler's Top100
Находится в каталоге Апорт

Главная -> Рассылка
Выпуск 6

Выпуск 6

« РСУБД Sybase ASA 9 - мощность, легкость и надежность »

Рассылка N 6

Здравствуйте, уважаемые коллеги. Представляю Вашему вниманию новый выпуск рассылки.

Содержание рассылки:

  • Новости
  • Дополнения к предыдущему выпуску
  • Оператор SELECT
  • Оператор INSERT
  • Оператор UPDATE
  • Операторы DELETE и TRUNCATE TABLE

Новости

На сайт Sybase.com выложен новый EFB 9.0.1252 для платформ Windows и Netware. Размер 54 мб.Интересное в патче:

  • Добавлена возможность указывать имена полей или алиасов вместо порядкового номера поля в ORDER BY для запросов с UNION, INTERSECT и EXCEPT.
  • В EXECUTE IMMEDIATE добавлена новая опция WITH RESULT SET {ON | OFF}, позволяющая указать, будет ли динамический SQL возвращать набор данных. Эта опция позволяет точно контролировать выполнение динамического SQL. Но самое главное - она позволяет ASA узнать при компиляции хранимых процедур, будут ли они возвращать набор данных. До этого патча любое использование оператора динамического SQL в хранимой процедуре приводило к тому, что ASA считала ее процедурой, возвращающей данные, хотя реально, процедура могла и не возвращать данные, если динамический SQL ничего не возвращал.

Есть и вторая интересная новость: вышел долгожданный драйвер для ASA, позволяющий в Borland Delphi напрямую работать с ASA через dbExpress. Размер 55 кб.

Дополнения к предыдущему выпуску

Некоторые вещи были обнаружены мной после выхода предыдущего выпуска рассылки:

  • Хранимые процедуры и пользовательские функции оказывается в ASA на самом деле полностью идентичны и воспринимаются ASA, как хранимые процедуры. Если посмотреть на системную таблицу SYSPROCEDURE, где хранятся их описания, то видно, что никакого флага принадлежности обьекта к процедуре или функции в этой таблице нет. Если Вам необходимо динамически сгенерить скрипт удаления функций из базы данных, то Вы можете применить оператор DROP PROCEDURE. Так же процедуры, не возвращаюшие наборы данных, могут быть использованны в качестве функций, но я бы не рекомендовал это делать, так как эта возможность явно не документированна.
  • Мной была обнаружена ошибка критическая ошибка сервера, возникающая в случае, если в таблицу заноситься запись с NULL значением в поле NOT NULL, в триггере BEFORE этому полю присваивается NOT NULL значение и существует триггер AFTER. Без триггера AFTER ошибки не происходит. В близжайшее время я выложу этот баг для команды разработчиков ASA, думаю в следующем EFB эта ошибка будет исправлена. В дополнение, если у кого то есть собственная коллекция обнаруженных багов ASA, не исправленных в текущей версии EFB, то можно высылать их описания мне по почте. Можно будет включить в рассылку описания обнаруженных русскоязычными разработчиками багов, централизованно отсылать их в Sybase и отслеживать исправления ошибок в EFB. Более подробно со мной пообщаться можно по почтовому ящику ascrus@mail.ru

Оператор SELECT

Оператор выборки данных в ASA обладает достаточно большой функциональностью. Я не буду рассматривать его реализацию на диалекте TSQL, она полностью совместима с реализацией SELECT в MSSQL и ASE. Гораздо интересней будет описать отличия его реализации на WatcomSQL от TSQL:

  • Расширенная реализация JOIN
      Поддерживаются 3 вида способов соединения таблиц в JOIN - по связи таблиц (KEY JOIN) , по совпадающим именам полей (NATURAL JOIN) и по определенным связям таблиц (обычные JOIN стандарта ANSISQL):

      -- Запрос 1 - обычный INNER JOIN
      SELECT *
      FROM fin_code c
        INNER JOIN fin_data d ON d.code = c.code;

      -- Запрос 2 - обычный LEFT JOIN с фильтром по году
      SELECT *
      FROM fin_code c
        LEFT JOIN fin_data d ON d.code = c.code AND d.year = 2000;

      -- KEY INNER JOIN, аналогичен запросу 1
      SELECT *
      FROM fin_code c
        KEY JOIN fin_data d;

      -- KEY INNER JOIN, аналогичен запросу 1
      SELECT *
      FROM fin_code c
        JOIN fin_data d;

      -- KEY LEFT JOIN, аналогичен запросу 2
      SELECT *
      FROM fin_code c
        KEY LEFT JOIN fin_data d ON d.year = 2000;

      -- KEY LEFT JOIN, аналогичен запросу 2
      SELECT *
      FROM fin_code c
        LEFT JOIN fin_data d
      WHERE d.year = 2000;

      -- LEFT JOIN, не аналогичен запросу 2, так как
      -- пропущено ключевое слово KEY и в ON указано
      -- условие соединения. В данном случае запрос
      -- является ошибочным
      SELECT *
      FROM fin_code c
        LEFT JOIN fin_data d ON d.year = 2000;

      -- NATURAL INNER JOIN, аналогичен запросу 1
      SELECT *
      FROM fin_code c
        NATURAL JOIN fin_data d;

      -- NATURAL LEFT JOIN, аналогичен запросу 2
      SELECT *
      FROM fin_code c
        NATURAL LEFT JOIN fin_data d ON d.year = 2000;

      Из вышеприведенных примеров видно, что если ключевое слово ON для JOIN не указано, то такое обьединение таблиц будет восприниматься в запросе как KEY JOIN, ASA попробует связать таблицы по FOREIGN KEY и если внешний ключ не будет обнаружен, то ASA возбудит ошибку. Если Вы хотите, чтобы связь поисходила по совпадающим именам полей, то всегда необходимо писать ключевое слово NATURAL, хотя я бы не рекомендовал такой рискованный способ соединения таблиц в запросе, так как любое переименование полей в таблице приведет к неправильной работе таких запросов, где она участвует. При явном указании ключевых слов KEY или NATURAL можно писать дополнительные условия соединения в ON. В отличие от NATURAL, KEY JOIN наоборот позволяет не только упростить читабельность запросов, но и при изменении структуры таблиц (переименование полей, изменение внешнего ключа и т.д.) сохранить работоспособность обьединения в запросах.

      KEY и NATURAL JOIN можно так же использовать для соединения в запросах таблиц с представлениями, (для KEY JOIN представления не должны содержать групповые операции). Однако я бы не рекомендовал пользоваться этой возможностью - в отличие от таблиц, для представлений предпочтительней явное соединение. Это гарантирует, что соединение произойдет по указанным Вами полям, в случае же с KEY JOIN поля для соединения будут выбраны ASA неявно для Вас, что будет больше напоминать гадание на кофейной гуще и гарантировать проблемы при изменении скрипта представления.
  • Возможность работы с алиасами
      Не так редко приходиться в запросах возвращать вычисляемое выражение, используя его в разных местах запроса:
      /* Сумма продаж продукции на 16.03.2000 с их оценкой, но без учета продукции, сумма которой превышает 1500 */
      SELECT p.name, Sum(p.unit_price * p.quantity) as Summa,
        CASE WHEN sum(p.unit_price * p.quantity) >= 1000 THEN 'Отлично'
          ELSE 'Так себе' END as Descript
      FROM product p
        KEY JOIN sales_order_items i ON i.ship_date = '2000-03-16'
      GROUP BY p.name
      HAVING Sum(p.unit_price * p.quantity) <= 1500
      В вышеприведенном запросе выражение, возвращающее колонку Summa используется три раза, что не удобно с точки зрения читабельности запросов и простоты его написания. В WatcomSQL в запросе разрешается обращаться к алиасу возвращаемой колонки наравне с полями.

      Перепишем вышепереведенный запрос:
      /* Сумма продаж продукции на 16.03.2000 с их оценкой, но без учета продукции, сумма которой превышает 1500 */
      SELECT p.name, Sum(p.unit_price * p.quantity) as Summa,
        CASE WHEN Summa >= 1000 THEN 'Отлично'
          ELSE 'Так себе' END as Descript
      FROM product p
        KEY JOIN sales_order_items i ON i.ship_date = '2000-03-16'
      GROUP BY p.name
      HAVING Summa <= 1500

      Запрос гораздо легче пишется и читается. Единственное, хочу заметить, что при встрече в запросе имен, без явного указания алиаса и совпадения имен полей и имен алиасов, имена алиасов будут иметь более высокий приоритет, чем имена полей.
  • Расширения с помощью WITH
      Судя по всему WITH перекочевал в ASA из IBM DB2, однако с учетом того, что он появиться в новой версии MSSQL, этот оператор уже постепенно становиться стандартом SQL. Данный оператор расширяет возможности команды SELECT по работе с подзапросами по технологии Common Table Expression (CTE). Чтобы лучше понять его назначение рассмотрим пример:
      SELECT dept_id, n
      FROM (
        SELECT dept_id, count(*) AS n
        FROM employee GROUP BY dept_id ) AS a
      WHERE a.n = (
              SELECT max(n)
              FROM (
                SELECT dept_id, count(*) AS n
                FROM employee GROUP BY dept_id
              ) AS b
            )

      С точки зрения семантики запрос правильный, однако с точки зрения читабельности и легкости написания запрос нельзя назвать легким. Конечно, если подзапрос на получение кол-ва dept_id по employee используется во многих запросах, легче всего его оформить как представление (view) и дальше уже использовать его, вместо подзапроса. Однако создание представления может быть нежелательно по следующим причинам:

      • Запрос генерируется динамически и вызывается в динамическом SQL из хранимой процедуры. Создание или удаление представления вызывает блокирование системных таблиц, что не желательно делать во время выполнения хранимой процедуры.
      • У подзапроса есть фильтр по динамическим значениям параметров, переданным например в хранимую процедуру. Конечно можно использовать глобальные переменные в представлениях или оформить подзапрос в виде хранимой процедуры, однако в предыдущем выпуске рассылки я уже не рекомендовал без серьезного обоснования использовать эти решения. В данном случае такие решения не подходят.
      • Усложняется читабельность. Чтобы понять логику действия запроса, ссылающегося на представление, придется посмотреть на исходный скрипт представления.
      • Усложняется модифицируемость. Если подзапрос необходимо изменить, то придется изменять представления, что может гарантировать множество проблем, если на представление есть ссылки из других запросов.

      Думаю уже причин достаточно, чтобы показать, что использование представлений не всегда желательно. Для решения этих проблем как раз и существует оператор WITH, который дает возможность описать к запросу временное (локальное) представление:
      WITH CountEmployees(dept_id, n) AS (
        SELECT dept_id, count(*)
        FROM employee GROUP BY dept_id )
      SELECT dept_id, n
      FROM CountEmployees
      WHERE n = ( SELECT max(n)
      FROM CountEmployees )

      В данном примере оператор WITH описывает локальное для данного запроса представление CountEmployees, на которое и ссылается сам запрос. Оператор WITH позволяет описать множество представлений и использовать их в одном запросе. Над такими представлениями можно проводить в запросе любые операции так, как если бы они были реальными представлениями.

      Оператор WITH позволяет реализовать еще одну полезную функцию в запросах - возможность написания иерархических запросов. Думаю всем приходилось сталкиваться с трудностями реализации таких запросов в ANSISQL. Решения получались трудоемкие и неэффективные. В данном случае WITH позволяет писать такие запросы простым и элегантным способом:
      WITH RECURSIVE
        manager ( emp_id, manager_id,
                  emp_fname, emp_lname, mgmt_level ) AS
          ( ( SELECT emp_id, manager_id, -- главный запрос
                     emp_fname, emp_lname, 0
              FROM employee AS e
              WHERE manager_id = emp_id )
              UNION ALL
            ( SELECT e.emp_id, e.manager_id, -- рекурсивный запрос
                     e.emp_fname, e.emp_lname, m.mgmt_level + 1
              FROM employee AS e JOIN manager AS m
                    ON e.manager_id = m.emp_id AND
                       e.manager_id <> e.emp_id AND
                       m.mgmt_level < 20 ) )
      SELECT * FROM manager
      ORDER BY mgmt_level, emp_lname, emp_fname




Дата публикации: Monday 27 March 2006 16:06:27
Материал прочитан: 10035 раз(а)
[ Назад ]



Продвижение сайтов
Биржа ссылок

Copyright©2005 phpMS. Все права защищены.
hosted on pets-tree

Warning: Unknown: write failed: Disk quota exceeded (122) in Unknown on line 0

Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/var/www/rusug-ru/data/bin-tmp) in Unknown on line 0