Главная страница
Навигация по странице:

  • Использование ключевых слов SOME (ANY) и ALL с предикатами сравнения 1. SOME | ANY ( )SOME и ANY

  • Maker E Рассмотрим подробно этот пример. Предикат 1. model = ANY (SELECT model 2. FROM PC 3. ); вернет значение TRUE

  • DISTINCT

  • UNKNOWN . Еще раз о подзапросах Заметим, что в общем случае запрос возвращает множество значений. Поэтому использование подзапроса в предложении WHERE

  • EXISTS , IN , ALL и ANY

  • CONVERT : 1. SELECTCONVERT(NUMERIC(6,2),AVG(launched*1.0))2. FROM Ships; Функция CONVERT

  • CONVERT

  • лекция. Учебник по sql если вы хотите узнать, что такое sql этот сайт для вас


    Скачать 7.88 Mb.
    НазваниеУчебник по sql если вы хотите узнать, что такое sql этот сайт для вас
    Анкорлекция
    Дата21.12.2022
    Размер7.88 Mb.
    Формат файлаpdf
    Имя файлаMoiseenko_SQL.pdf
    ТипУчебник
    #857633
    страница21 из 47
    1   ...   17   18   19   20   21   22   23   24   ...   47
    ALL есть TRUE, если подзапрос не возвращает строк:
    1.
    SELECT
    DISTINCT
    maker
    2.
    FROM
    Product Pr1 3.
    WHERE
    type =
    ALL
    4.
    (
    SELECT
    type
    FROM
    Product
    5.
    EXCEPT
    6.
    SELECT
    type
    FROM
    Product Pr2 7.
    WHERE
    Pr2.maker = Pr1.maker
    8.
    )
    ;
    Для искомых производителей список типов в предикате ALL будет пуст
    (предикат равен TRUE). В остальных случаях он будет содержать типы моделей, отсутствующие у производителя из внешнего запроса, поэтому операция сравнения (равенство "=") для всех его моделей даст FALSE.
    Существование
    Не должно существовать такого типа продукции, которого бы не было у искомого производителя.
    1.
    SELECT
    DISTINCT
    maker
    2.
    FROM
    Product Pr1 3.
    WHERE
    NOT
    EXISTS
    4.
    (
    SELECT
    type
    5.
    FROM
    Product
    6.
    WHERE
    type
    NOT
    IN
    7.
    (
    SELECT
    type
    8.
    FROM
    Product Pr2 9.
    WHERE
    Pr1.maker = Pr2.maker

    10.
    )
    11.
    )
    ;
    Кроме первого варианта с группировкой все остальные решения используют коррелирующие подзапросы для определения множества типов моделей производителя из основного запроса.
    Следует также отметить, что решение с группировкой не подойдет для случая, когда требуется выполнить деление не на все множество имеющихся типов, а на некоторое их подмножество. Например, если требуется найти производителей, у которых множество типов включает в себя (или совпадает) множество типов, определяемое некоторыми критериями. Другие же приемы можно адаптировать для решения подобной задачи.
    Использование ключевых слов SOME (ANY) и
    ALL с предикатами сравнения
    1. <выражение> <оператор сравнения> SOME | ANY
    (
    <подзапрос>
    )
    SOME и ANY являются синонимами, то есть может использоваться любое из них. Результатом подзапроса является один столбец величин. Если хотя бы для одного значения V, получаемого из подзапроса, результат операции "<значение
    выражения>
    <
    оператор
    сравнения
    >
    V" равняется TRUE, то предикат ANY также равняется TRUE.
    1. <выражение> <оператор сравнения>
    ALL
    (
    <подзапрос>
    )
    Исполняется так же, как и ANY, однако значение предиката ALL будет истинным, если для всех значений V, получаемых из подзапроса, предикат "<значение выражения> <оператор сравнения> V" дает TRUE.
    Пример 5.8.1.
    Найти поставщиков компьютеров, моделей которых нет в
    продаже (то есть модели этих поставщиков отсутствуют в
    таблице PC)
    1.
    SELECT
    DISTINCT
    maker
    2.
    FROM
    Product
    3.
    WHERE
    type =
    'pc'
    AND

    4.
    NOT
    model = ANY
    (
    SELECT
    model
    5.
    FROM
    PC
    6.
    )
    ;
    Оказалось, что только у поставщика Е есть модели, отсутствующие в продаже:
    Maker
    E
    Рассмотрим подробно этот пример. Предикат
    1. model = ANY
    (
    SELECT
    model
    2.
    FROM
    PC
    3.
    )
    ; вернет значение TRUE, если модель, определяемая полем model основного запроса, найдется в списке моделей таблицы РС (возвращаемом подзапросом).
    Поскольку предикат используется в запросе с отрицанием NOT, то значение TRUE будет получено, если модели не окажется в списке. Этот предикат проверяется для каждой записи основного запроса, которыми являются все модели ПК (предикат type = 'pc') из таблицы Product.
    Результирующий набор состоит из одного столбца — имени производителя.
    Чтобы один производитель не выводился несколько раз (что может случиться, если он производит несколько моделей, отсутствующих в таблице РС), используется служебное слово DISTINCT, исключающее дубликаты.
    Пример 5.8.2.
    Найти модели и цены портативных компьютеров, стоимость
    которых превышает стоимость любого ПК
    1.
    SELECT
    DISTINCT
    model, price
    2.
    FROM
    Laptop
    3.
    WHERE
    price >
    ALL
    (
    SELECT
    price
    4.
    FROM
    PC
    5.
    )
    ;

    model
    Price
    1298
    1050
    1750
    1200
    1752
    1150
    Приведем формальные правила оценки истинности предикатов, использующих параметры ANY|SOME и ALL.

    Если определен параметр ALL или SOME и все результаты сравнения значения выражения и каждого значения, полученного из подзапроса, являются TRUE, истинностное значение равно TRUE.

    Если результат выполнения подзапроса не содержит строк и определен параметр ALL, результат равен TRUE. Если же определен параметр
    SOME, результат равен FALSE.

    Если определен параметр ALL и результат сравнения значения выражения хотя бы с одним значением, полученным из подзапроса, является FALSE, истинностное значение равно FALSE.

    Если определен параметр SOME и хотя бы один результат сравнения значения выражения и значения, полученного из подзапроса, является
    TRUE, истинностное значение равно TRUE.

    Если определен параметр SOME и каждое сравнение значения выражения и значений, полученных из подзапроса, равно FALSE, истинностное значение тоже равно FALSE.

    В любом другом случае результат будет равен UNKNOWN.
    Еще раз о
    подзапросах
    Заметим, что в общем случае запрос возвращает множество значений.
    Поэтому использование подзапроса в предложении WHERE без предикатов EXISTS, IN, ALL и ANY, которые дают булево значение, может привести к ошибке времени выполнения запроса.
    Пример 5.8.3

    Найти модели и цены ПК, стоимость которых превышает
    минимальную стоимость портативных компьютеров:
    1.
    SELECT
    DISTINCT
    model, price
    2.
    FROM
    PC
    3.
    WHERE
    price >
    (
    SELECT
    MIN
    (
    price
    )
    4.
    FROM
    Laptop
    5.
    )
    ;
    Этот запрос вполне корректен, так как скалярное значение price сравнивается с подзапросом, который возвращает единственное значение. В результате получим четыре модели ПК:
    model
    price
    1121
    850
    1233
    950
    1233
    970
    1233
    980
    Однако, если в ответ на вопрос «найти модели и цены ПК, стоимость которых совпадает со стоимостью портативных компьютеров» написать следующий запрос
    1.
    SELECT
    DISTINCT
    model, price
    2.
    FROM
    PC
    3.
    WHERE
    price =
    (
    SELECT
    price
    4.
    FROM
    Laptop
    5.
    )
    ; то при выполнении последнего мы можем получить такое сообщение об ошибке:
    Subquery returned more than 1 value. This is not permitted when the subquery
    follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
    («Подзапрос вернул более одного значения. Это не допускается в тех случаях, когда подзапрос следует после =, !=, <, <=, >, >= или когда подзапрос используется в качестве выражения».)

    Эта ошибка будет возникать при сравнении скалярного значения с подзапросом, который возвращает более одного значения.
    Подзапросы, в свою очередь, также могут содержать вложенные запросы.
    С другой стороны, подзапрос, возвращающий множество строк и содержащий несколько столбцов, вполне естественно может использоваться в предложении FROM. Это, например, позволяет ограничить набор столбцов и/или строк при выполнении операции соединения таблиц.
    Пример 5.8.4
    Вывести производителя, тип, модель и частоту процессора для
    Портативных компьютеров, частота процессора которых
    превышает 600 МГц.
    Этот запрос может быть сформулирован, например, следующим образом:
    1.
    SELECT
    prod.maker, lap.*
    2.
    FROM
    (
    SELECT
    'laptop'
    AS
    type, model, speed
    3.
    FROM
    laptop
    4.
    WHERE
    speed >
    600 5.
    )
    AS
    lap
    INNER
    JOIN
    6.
    (
    SELECT
    maker, model
    7.
    FROM
    product
    8.
    )
    AS
    prod
    ON
    lap.model = prod.model;
    В результате получим:
    maker
    type
    model
    speed
    B
    laptop
    1750 750
    A
    laptop
    1752 750
    Наконец, подзапросы могут присутствовать в предложении SELECT. Это иногда позволяет весьма компактно сформулировать запрос.
    Пример 5.8.5
    Найти разницу между средними значениями цены портативных
    компьютеров и ПК, то есть насколько в среднем портативный
    компьютер стоит дороже, чем ПК.

    Здесь вообще можно обойтись одним предложением SELECT в основном запросе:
    1.
    SELECT
    (
    SELECT
    AVG
    (
    price
    )
    2.
    FROM
    Laptop
    3.
    )
    -
    4.
    (
    SELECT
    AVG
    (
    price
    )
    5.
    FROM
    PC
    6.
    )
    AS
    dif_price;
    В результате получим
    dif_price
    328.3333
    Преобразование
    типов и оператор
    CAST
    В реализациях языка
    SQL
    может быть выполнено неявное преобразование типов. Так, например, в
    SQL Server и Sybase ASE.Transact-
    SQL при сравнении или комбинировании значений типов smallint и int, данные типа smallint неявно преобразуются к типу int.
    Подробно о явном и неявном преобразовании типов в SQL Server можно прочитать в BOL.
    Пример 5.9.1.
    Вывести среднюю цену портативных
    компьютеров с предваряющим текстом
    «средняя цена = ».
    Попытка выполнить запрос
    1.
    SELECT
    'Средняя цена = '
    +
    AVG
    (
    price
    )
    2.
    FROM
    Laptop; приведет к сообщению об ошибке:

    Implicit conversion from data type varchar to money is not allowed. Use the
    CONVERT_:_1._SELECTCONVERT(NUMERIC(6,2),AVG(launched*1.0))2._FROM_Ships;_Функция_CONVERT'>CONVERT function to run this query.
    («Не допускается неявное преобразование типа varchar к типу money.
    Используйте для выполнения этого запроса функцию CONVERT».)
    Это сообщение означает, что система не может выполнить неявное преобразование типа varchar к типу money. В подобных ситуациях может помочь явное преобразование типов. При этом, как указано в сообщении об ошибке, можно воспользоваться функцией CONVERT. Однако эта функция не стандартизована, поэтому в целях переносимости рекомендуется использовать стандартное выражение CAST. С него и начнем.
    Итак, если переписать наш запрос в виде
    1.
    SELECT
    'Средняя цена = '
    +
    CAST
    (
    AVG
    (
    price
    )
    AS
    CHAR
    (
    15
    ))
    2.
    FROM
    Laptop; в результате получим то, что требовалось:
    1. Средняя цена =
    1003.33
    Мы использовали выражение явного преобразования типов CAST для приведения среднего значения цены к строковому представлению.
    Синтаксис выражения CAST очень простой
    1.
    CAST
    (
    <выражение>
    AS
    <тип данных>
    )
    Внимание:
    Следует иметь в виду, во-первых, что не любые преобразования типов возможны (стандарт содержит таблицу допустимых преобразований типов данных). Во-вторых, результат функции CAST для значения выражения, равного NULL, тоже будет NULL.
    Рассмотрим еще один пример.
    Пример 5.9.2
    Определить средний год спуска на воду кораблей из таблицы Ships.
    Запрос:

    1.
    SELECT
    AVG
    (
    launched
    )
    2.
    FROM
    Ships; даст результат 1926. В принципе все правильно, так как мы получили в результате то, что просили — год. Однако среднее арифметическое будет составлять примерно 1926,9091. Тут следует напомнить, что агрегатные функции (за исключением функции COUNT, которая всегда возвращает целое число) наследуют тип данных обрабатываемых значений. Поскольку поле launched — целочисленное, мы и получили среднее значение с отброшенной дробной частью (заметьте — не округленное).
    А если нас интересует результат с заданной точностью, скажем, до двух десятичных знаков? Применение выражения CAST к среднему значению ничего не даст по указанной выше причине. Действительно,
    1.
    SELECT
    CAST
    (
    AVG
    (
    launched
    )
    AS
    NUMERIC
    (
    6
    ,
    2
    ))
    2.
    FROM
    Ships; вернет значение 1926.00. Следовательно, CAST нужно применить к аргументу агрегатной функции:
    1.
    SELECT
    AVG
    (
    CAST
    (
    launched
    AS
    NUMERIC
    (
    6
    ,
    2
    )))
    2.
    FROM
    Ships;
    Результат — 1926.90909. Опять не то. Причина состоит в том, что при вычислении среднего значения было выполнено неявное преобразование типа.
    Сделаем еще один шаг:
    1.
    SELECT
    CAST
    (
    AVG
    (
    CAST
    (
    launched
    AS
    NUMERIC
    (
    6
    ,
    2
    )))
    AS
    NUMERIC
    (
    6
    ,
    2
    ))
    2.
    FROM
    Ships;
    В результате получим то, что нужно — 1926.91. Однако это решение выглядит очень громоздко. Заставим неявное преобразование типа поработать на нас:
    1.
    SELECT
    CAST
    (
    AVG
    (
    launched*
    1.0
    )
    AS
    NUMERIC
    (
    6
    ,
    2
    ))

    2.
    FROM
    Ships;
    Теперь мы использовали неявное преобразование целочисленного аргумента к точному числовому типу (EXACT NUMERIC), умножив его на вещественную единицу, после чего применили явное приведения типа результата агрегатной функции.
    Аналогичные преобразования типа можно выполнить с помощью функции
    SQL
    Server CONVERT:
    1.
    SELECT
    CONVERT
    (
    NUMERIC
    (
    6
    ,
    2
    )
    ,
    AVG
    (
    launched*
    1.0
    ))
    2.
    FROM
    Ships;
    Функция CONVERT имеет следующий синтаксис:
    1.
    CONVERT
    (
    <тип_данных
    [(
    <длина>
    )]
    >,
    <выражение>
    [
    ,
    <стиль>
    ])
    Основное отличие функции CONVERT от функции CAST состоит в том, что первая позволяет форматировать данные (например, темпоральные данные типа datetime) при преобразовании их к символьному типу и указывать формат при обратном преобразовании. Разные целочисленные значения необязательного аргумента стиль соответствуют различным типам форматов.
    Рассмотрим следующий пример
    1.
    SELECT
    CONVERT
    (
    char
    (
    25
    )
    ,
    CONVERT
    (
    datetime,
    '20030722'
    ))
    ;
    Здесь мы преобразуем строковое представление даты к типу datetime, после чего выполняем обратное преобразование, чтобы продемонстрировать результат форматирования. Поскольку значение аргумента стиль не задано используется значение по умолчанию (0 или 100). В результате получим:
    Jul 22 2003 12:00AM

    Ниже приведены некоторые другие значения аргумента стиль и результат, полученный на приведенном выше примере. Заметим, что увеличение значения стиль на 100 приводит к четырехзначному отображению года.
    1
    07/22/03
    11
    03/07/22
    3
    22/07/03
    121
    2003-07-22 00:00:00.000
    Перечень всех возможных значений аргумента стиль можно посмотреть в
    BOL.
    Есть одна особенность использования оператора CAST в SQL Server, связанная с преобразованием числа к его строковому представлению. Что произойдет, если число символов в числе превышает размер строки?
    Например,
    1.
    SELECT
    CAST
    (
    1234.6
    AS
    VARCHAR
    (
    5
    ))
    ;
    Следует ожидать, что мы получим сообщение об ошибке. Правильно, вот это сообщение:
    Arithmetic overflow error converting numeric to data type varchar.
    («Ошибка арифметического переполнения при преобразовании числа к типу данных VARCHAR».)
    Естественно, что мы будем ожидать того же сообщения и при выполнении следующего оператора:
    1.
    SELECT
    CAST
    (
    123456
    AS
    VARCHAR
    (
    5
    ))
    ;
    Но нет. В результате мы получим символ «*» вместо сообщения об ошибке.
    Мы не беремся судить, с чем это связано, однако, однажды мы столкнулись с проблемой диагностики ошибки в коде, в котором впоследствии выполнялось обратное преобразование к числовому типу.
    В нашем простейшем примере это будет выглядеть так:

    1.
    SELECT
    CAST
    (
    CAST
    (
    123456
    AS
    VARCHAR
    (
    5
    ))
    AS
    INT
    )
    ;
    Вот тут-то мы и получаем ошибку:
    Syntax error converting the varchar value '*' to a column of data type int.
    («Ошибка синтаксиса при преобразовании значения «*» к типу данных
    INT».)
    Примечание:
    Функция
    SQL
    Server и Sybase ASE.Transact-SQL CONVERT ведет себя
    аналогичным образом.
    Преобразование типа money
    Денежный тип данных не является стандартным. В SQL Server имеется два денежных типа:
    money: диапазон значений от
    –922,337,203,685,477.5808 до
    922,337,203,685,477.5807
    smallmoney: диапазон значений от -214 748,3648 до 214 748,3647
    Точность обоих типов одна десятитысячная.
    Константу типа money можно задать с помощью префикса $, или же использовать преобразование типов, например:
    1.
    SELECT
    1.2
    num, $
    1.2
    mn1,
    CAST
    (
    1.2
    AS
    MONEY
    )
    mn2;
    num
    mn1
    mn2
    1.2
    1,20 1,20
    Обратите внимание на запятую в качестве разделителя "рублей" и "копеек" - не точка!
    Преобразование к целому типу для чисел и денег выполняется по разному: в первом случае дробная часть отбрасывается, во втором происходит округление.
    1.
    SELECT
    CAST
    (
    1.75
    AS
    INT
    )
    int_num,
    CAST
    (
    $
    1.75
    AS
    INT
    )
    int_mon;

    int_num
    int_mon
    1
    2
    Деньги таки, их просто так терять нельзя!
    Оператор
    CASE
    Пусть требуется вывести список всех моделей ПК с
    указанием их цены. При этом если модель
    отсутствует в продаже (ее нет в таблице РС), то
    вместо цены вывести текст «Нет в наличии».
    Список всех моделей ПК с ценами можно получить с помощью запроса:
    1.
    SELECT
    DISTINCT
    Product.model, price
    2.
    FROM
    Product
    LEFT
    JOIN
    3. PC
    ON
    Product.model = PC.model
    4.
    WHERE
    product.type =
    'pc'
    ;
    В результирующем наборе отсутствующая цена будет заменена NULL- значением:
    1   ...   17   18   19   20   21   22   23   24   ...   47


    написать администратору сайта