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

  • COALESCE

  • Операторы модификации данных Язык манипуляции данными (DML — Data Manipulation Language) помимо оператора SELECT

  • CREATE TABLE

  • INSERT

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


    Скачать 7.88 Mb.
    НазваниеУчебник по sql если вы хотите узнать, что такое sql этот сайт для вас
    Анкорлекция
    Дата21.12.2022
    Размер7.88 Mb.
    Формат файлаpdf
    Имя файлаMoiseenko_SQL.pdf
    ТипУчебник
    #857633
    страница22 из 47
    1   ...   18   19   20   21   22   23   24   25   ...   47
    Model
    price
    1121
    850
    1232
    350
    1232
    400
    1232
    600
    1233
    600
    1233
    950

    1233
    980
    1260
    350
    2111
    NULL
    2112
    NULL
    Чтобы заменить NULL-значения нужным текстом, можно воспользоваться оператором CASE:
    1.
    SELECT
    DISTINCT
    product.model,
    2.
    CASE
    3.
    WHEN
    price
    IS
    NULL
    4.
    THEN
    'Нет в наличии'
    5.
    ELSE
    CAST
    (
    price
    AS
    CHAR
    (
    20
    ))
    6.
    END
    price
    7.
    FROM
    Product
    LEFT
    JOIN
    8. PC
    ON
    Product.model = PC.model
    9.
    WHERE
    product.type =
    'pc'
    ;
    Оператор CASE в зависимости от указанных условий возвращает одно из множества возможных значений. В нашем примере условием является проверка на NULL. Если это условие выполняется, то возвращается текст
    «Нет в наличии», в противном случае (ELSE) возвращается значение цены.
    Здесь есть один принципиальный момент. Поскольку результатом оператора SELECT всегда является таблица, то все значения любого столбца должны иметь один и тот же тип данных (с учетом неявного приведения типов). Поэтому мы не можем наряду с ценой (числовой тип) выводить символьную константу. Вот почему к полю price применяется преобразование типов, чтобы привести его значения к символьному представлению. В результате получим:
    model
    price
    1121
    850
    1232
    350
    1232
    400

    1232
    600
    1233
    600
    1233
    950
    1233
    980
    1260
    350
    2111
    Нет в наличии
    2112
    Нет в наличии
    Оператор CASE может быть использован в одной из двух синтаксических форм записи:
    1-я форма:
    1.
    CASE
    <проверяемое выражение>
    2.
    WHEN
    <сравниваемое выражение
    1
    >
    3.
    THEN
    <возвращаемое значение
    1
    >
    4. …
    5.
    WHEN
    <сравниваемое выражение N>
    6.
    THEN
    <возвращаемое значение N>
    7.
    [
    ELSE
    <возвращаемое значение>
    ]
    8.
    END
    2-я форма:
    1.
    CASE
    2.
    WHEN
    <предикат
    1
    >
    3.
    THEN
    <возвращаемое значение
    1
    >
    4. …
    5.
    WHEN
    <предикат N>
    6.
    THEN
    <возвращаемое значение N>
    7.
    [
    ELSE
    <возвращаемое значение>
    ]
    8.
    END
    Все предложения WHEN должны иметь одинаковую синтаксическую форму, то есть нельзя смешивать первую и вторую формы. При использовании первой синтаксической формы условие WHEN удовлетворяется, как только значение проверяемого выражения станет равным значению выражения,
    указанного в предложении WHEN.
    При использовании второй синтаксической формы условие WHEN удовлетворяется, как только предикат принимает значение TRUE.
    При удовлетворении условия оператор CASE возвращает значение, указанное в соответствующем предложении THEN. Если ни одно из условий WHEN не выполнилось, то будет использовано значение, указанное в предложении ELSE. При отсутствии ELSE, будет возвращено NULL-значение. Если удовлетворены несколько условий, то будет возвращено значение предложения THEN первого из них, так как остальные просто не будут проверяться.
    В приведенном выше примере была применена вторая форма оператора CASE.
    Заметим, что для проверки на NULL стандарт предлагает более короткую форму — оператор COALESCE. Он имеет произвольное число параметров и возвращает значение первого из них, отличного от NULL. Для двух параметров оператор COALESCE(A,
    B) эквивалентен следующему оператору CASE:
    1.
    CASE
    2.
    WHEN
    A
    IS
    NOT
    NULL
    3.
    THEN
    A
    4.
    ELSE
    B
    5.
    END
    Решение рассмотренного выше примера при использовании оператора COALESCE можно переписать следующим образом:
    1.
    SELECT
    DISTINCT
    Product.model,
    2. COALESCE
    (
    CAST
    (
    price
    AS
    CHAR
    (
    20
    ))
    ,
    'Нет в наличии'
    )
    price
    3.
    FROM
    Product
    LEFT
    JOIN
    4. PC
    ON
    Product.model = PC.model
    5.
    WHERE
    Product.type =
    'pc'
    ;
    Применение первой синтаксической формы оператора CASE можно продемонстрировать на следующем примере.
    Пример 5.10.1
    Вывести все имеющиеся модели ПК с указанием цены. Отметить
    самые дорогие и самые дешевые модели.
    1.
    SELECT
    DISTINCT
    model, price,

    2.
    CASE
    price
    3.
    WHEN
    (
    SELECT
    MAX
    (
    price
    )
    4.
    FROM
    PC
    5.
    )
    6.
    THEN
    'Самый дорогой'
    7.
    WHEN
    (
    SELECT
    MIN
    (
    price
    )
    8.
    FROM
    PC
    9.
    )
    10.
    THEN
    'Самый дешевый'
    11.
    ELSE
    'Средняя цена'
    12.
    END
    comment
    13.
    FROM
    PC
    14.
    WHERE
    price
    IS
    NOT
    NULL
    15.
    ORDER
    BY
    price;
    В результате выполнения запроса получим:
    model
    price
    comment
    1232
    350.0
    Самый дешевый
    1260
    350.0
    Самый дешевый
    1232
    400.0
    Средняя цена
    1232
    600.0
    Средняя цена
    1233
    600.0
    Средняя цена
    1121
    850.0
    Средняя цена
    1233
    950.0
    Средняя цена
    1233
    980.0
    Самый дорогой
    Оператор CASE может быть использован не только в предложении SELECT.
    Здесь вы можете найти другие примеры его использования.

    Рассмотрим еще несколько примеров.
    Посчитать количество рейсов из Ростова в Москву, и количество
    рейсов, выполняемых в остальные города.
    Здесь мы можем воспользоваться вычисляемым столбцом, по значениям которого будем выполнять группировку:
    1.
    SELECT
    flag,
    COUNT
    (
    *
    )
    qty
    FROM
    2.
    (
    SELECT
    CASE
    WHEN
    town_to =
    'Moscow'
    THEN
    'Moscow'
    ELSE
    'Other'
    END
    flag
    3.
    FROM
    Trip
    4.
    WHERE
    town_from=
    'Rostov'
    5.
    )
    X
    6.
    GROUP
    BY
    flag;
    flag
    qty
    Moscow 4
    Other
    2
    Посчитать общее количество рейсов из Ростова и количество
    рейсов, пунктом назначения которых не является Москва.
    В этой задаче тоже требуется выполнить агрегацию по двум выборкам, при этом одна из выборок является подмножеством второй. Поэтому здесь напрямую не подойдёт вычисляемый столбец, по которому можно выполнить группировку. Это годилось для решения предыдущей задачи, когда множество делилось на собственные непересекающиеся подмножества, по каждому из которых требовалось выполнить агрегацию.
    Для решения данной задачи мы можем посчитать количество по всему множеству и использовать подзапрос для подсчета значений в подмножестве
    (второе обращение к таблице) или использовать CASE в сочетании с агрегатной функцией, чтобы избежать повторного чтения таблицы. Давайте посмотрим, как оценит оптимизатор эти варианты.
    Использование подзапроса
    1.
    SELECT
    COUNT
    (
    *
    )
    total,
    2.
    (
    SELECT
    COUNT
    (
    *
    )
    FROM
    Trip

    3.
    WHERE
    town_from=
    'Rostov'
    AND
    town_to <>
    'Moscow'
    )
    non_moscow
    4.
    FROM
    Trip
    5.
    WHERE
    town_from=
    'Rostov'
    ;
    Использование CASE с агрегатной функцией
    1.
    SELECT
    COUNT
    (
    *
    )
    total_qty,
    2.
    SUM
    (
    CASE
    WHEN
    town_to <>
    'Moscow'
    THEN
    1
    ELSE
    0
    END
    )
    non_moscow
    3.
    FROM
    Trip
    4.
    WHERE
    town_from=
    'Rostov'
    ;
    Результат, естественно, будет одинаков:
    total
    non_moscow
    6
    2 а вот стоимость второго запроса, как и ожидалось, оказалась вдвое ниже.
    Вы можете сравнить реальное время выполнения, если сгенерируете достаточный объём данных.
    Второй вариант можно записать более компактно, если использовать функцию NULLIF - сокращенный вариант частного случая использования
    CASE:
    1.
    SELECT
    COUNT
    (
    *
    )
    total_qty,
    2.
    COUNT
    (
    NULLIF
    (
    town_to,
    'Moscow'
    ))
    non_moscow
    3.
    FROM
    Trip
    4.
    WHERE
    town_from=
    'Rostov'
    ;
    Функция NULLIF возвращает NULL, если её аргументы равны, или первый аргумент в противном случае.
    В решении используется тот факт, что агрегатные функции не учитывают
    NULL-значения, которые появляются в аргументе функции COUNT тогда, когда город прибытия равен 'Moscow'.
    Начиная с версии 2012, в
    SQL
    Server появилась функция IIF, хорошо известная тем, кто использует VBA. Эта функция является альтернативой выражению CASE в MS Access и имеет следующий синтаксис:

    1. IIF
    (
    <условие>,
    <выражение, если условие истинно>,
    <выражение, если условие не истинно>
    )
    Функция возвращает результат вычисления выражения из второго аргумента, если условие есть TRUE; в противном случае возвращается результат вычисления выражения из третьего аргумента. Таким образом, функция
    1.
    IIF
    (
    condition, expression_1, expression_2
    )
    эквивалентна следующему выражению CASE:
    1.
    CASE
    WHEN
    condition
    THEN
    expression_1
    ELSE
    expression_2
    END
    С помощью функции IIF мы можем переписать решение первой задачи следующим образом:
    1.
    SELECT
    DISTINCT
    product.model,
    2. IIF
    (
    price
    IS
    NULL
    , N
    'Нет в наличии'
    ,
    CAST
    (
    price
    AS
    CHAR
    (
    20
    )))
    price
    3.
    FROM
    Product
    LEFT
    JOIN
    4. PC
    ON
    Product.model = PC.model
    5.
    WHERE
    product.type =
    'PC'
    ;
    В том случае, если вариантов ветвления больше двух, можно использовать вложенные функции IIF. Например, для решения задачи 5.10.1
    можно использовать такой запрос:
    1.
    SELECT
    DISTINCT
    model, price,
    2.
    IIF
    (
    price=
    (
    SELECT
    MAX
    (
    price
    )
    FROM
    PC
    )
    ,N
    'Самый дорогой'
    ,
    3. IIF
    (
    price=
    (
    SELECT
    MIN
    (
    price
    )
    FROM
    PC
    )
    , N
    'Самый дешевый'
    ,N
    'Средняя цена'
    ))
    comment
    4.
    FROM
    PC
    5.
    ORDER
    BY
    price;
    Если так и дальше пойдет, то скоро в
    T-SQL
    появится оператор SWITCH.
    Операторы
    модификации данных
    Язык манипуляции данными (DML —
    Data Manipulation Language) помимо
    оператора SELECT, осуществляющего извлечение информации из базы данных, включает операторы, изменяющие состояние данных. Этими операторами являются:
    оператор
    функция
    INSERT
    Добавление записей
    (строк) в таблицу БД
    UPDATE
    Обновление данных в столбце таблицы БД
    DELETE
    Удаление записей из таблицы БД
    Вы можете попрактиковаться в написании этих операторов на странице с
    упражнениями по DML
    на сайте
    SQL-EX.RU
    Оператор
    INSERT
    Оператор INSERT вставляет новые записи в таблицу. При этом значения столбцов могут представлять собой литеральные константы, либо являться результатом выполнения подзапроса. В первом случае для вставки каждой строки используется отдельный оператор INSERT; во втором случае будет вставлено столько строк, сколько возвращается подзапросом.
    Синтаксис оператора следующий:

    1.
    INSERT
    INTO
    <имя таблицы>
    [(
    <имя столбца>,...
    )]
    2.
    {
    VALUES
    (
    <значение столбца>,…
    )}
    3. | <выражение запроса>
    4. |
    {
    DEFAULT
    VALUES
    }
    Как видно из представленного синтаксиса, список столбцов не является обязательным (об этом говорят квадратные скобки в описании синтаксиса). В том случае, если он отсутствует, список вставляемых значений должен быть полный, то есть обеспечивать значения для всех столбцов таблицы. При этом порядок значений должен соответствовать порядку, заданному оператором CREATE TABLE для таблицы, в которую вставляются строки.
    Кроме того, эти значения должны относиться к тому же типу данных, что и столбцы, в которые они вносятся. В качестве примера рассмотрим вставку строки в таблицу Product, созданную следующим оператором CREATE
    TABLE:
    1.
    CREATE
    TABLE
    product
    2.
    (
    3. maker char
    (
    1
    )
    NOT
    NULL
    ,
    4. model varchar
    (
    4
    )
    NOT
    NULL
    ,
    5. type varchar
    (
    7
    )
    NOT
    NULL
    6.
    )
    ;
    Пусть требуется добавить в эту таблицу модель ПК 1157 производителя B.
    Это можно сделать следующим оператором:
    1.
    INSERT
    INTO
    Product
    2.
    VALUES
    (
    'B'
    ,
    1157
    ,
    'PC'
    )
    ;
    Если задать список столбцов, то можно изменить «естественный» порядок их следования:
    1.
    INSERT
    INTO
    Product
    (
    type, model, maker
    )
    2.
    VALUES
    (
    'PC'
    ,
    1157
    ,
    'B'
    )
    ;
    Казалось бы, это совершенно излишняя возможность, которая делает конструкцию только более громоздкой. Однако она становится выигрышной, если столбцы имеют значения по умолчанию. Рассмотрим следующую структуру таблицы:
    1.
    CREATE
    TABLE
    product_D
    2.
    (
    3. maker char
    (
    1
    )
    NULL
    ,
    4. model varchar
    (
    4
    )
    NULL
    ,
    5. type varchar
    (
    7
    )
    NOT
    NULL
    DEFAULT
    'PC'
    6.
    )
    ;

    Отметим, что здесь значения всех столбцов имеют значения по умолчанию
    (первые два — NULL, а последний столбец — type — PC). Теперь мы могли бы написать:
    1.
    INSERT
    INTO
    Product_D
    (
    model, maker
    )
    2.
    VALUES
    (
    1157
    ,
    'B'
    )
    ;
    В этом случае отсутствующее значение при вставке строки будет заменено значением по умолчанию — PC. Заметим, что если для столбца в операторе CREATE TABLE не указано значение по умолчанию и не указано ограничение NOT NULL, запрещающее использование NULL в данном столбце таблицы, то подразумевается значение по умолчанию NULL.
    Возникает вопрос: а можно ли не указывать список столбцов и, тем не менее, воспользоваться значениями по умолчанию? Ответ положительный. Для этого нужно вместо явного указания значения использовать зарезервированное слово DEFAULT:
    1.
    INSERT
    INTO
    Product_D
    2.
    VALUES
    (
    'B'
    ,
    1158
    ,
    DEFAULT
    )
    ;
    Поскольку все столбцы имеют значения по умолчанию, для вставки строки со значениями по умолчанию можно было бы написать:
    1.
    INSERT
    INTO
    Product_D
    2.
    VALUES
    (
    DEFAULT
    ,
    DEFAULT
    ,
    DEFAULT
    )
    ;
    Однако для этого случая предназначена специальная конструкция DEFAULT
    VALUES (см. синтаксис оператора), с помощью которой вышеприведенный оператор можно переписать в виде
    1.
    INSERT
    INTO
    Product_D
    DEFAULT
    VALUES
    ;
    Заметим, что при вставке строки в таблицу проверяются все ограничения, наложенные на данную таблицу. Это могут быть ограничения первичного ключа или уникального индекса, проверочные ограничения типа CHECK, ограничения ссылочной целостности. В случае нарушения какого-либо ограничения вставка строки будет отклонена. Рассмотрим теперь случай использования подзапроса. Пусть нам требуется вставить в таблицу Product_D все строки из таблицы Product, относящиеся к моделям персональных компьютеров (type = ‘PC’). Поскольку необходимые нам значения уже имеются в некоторой таблице, то формирование вставляемых строк вручную, во-первых, является неэффективным, а, во-вторых, может допускать ошибки ввода. Использование подзапроса решает эти проблемы:

    1.
    INSERT
    INTO
    Product_D
    2.
    SELECT
    *
    3.
    FROM
    Product
    4.
    WHERE
    type =
    'PC'
    ;
    Использование в подзапросе символа «*» является в данном случае оправданным, так как порядок следования столбцов является одинаковым для обеих таблиц. Если бы это было не так, следовало бы применить список столбцов либо в операторе INSERT, либо в подзапросе, либо в обоих местах, который приводил бы в соответствие порядок следования столбцов:
    1.
    INSERT
    INTO
    Product_D
    (
    maker, model, type
    )
    2.
    SELECT
    *
    3.
    FROM
    Product
    4.
    WHERE
    type =
    'PC'
    ; или
    1.
    INSERT
    INTO
    Product_D
    2.
    SELECT
    maker, model, type
    3.
    FROM
    Product
    4.
    WHERE
    type =
    'PC'
    ; или
    1.
    INSERT
    INTO
    Product_D
    (
    maker, model, type
    )
    2.
    SELECT
    maker, model, type
    3.
    FROM
    Product
    4.
    WHERE
    type =
    'PC'
    ;
    Здесь, также как и ранее, можно указывать не все столбцы, если требуется использовать имеющиеся значения по умолчанию, например:
    1.
    INSERT
    INTO
    Product_D
    (
    maker, model
    )
    2.
    SELECT
    maker, model
    3.
    FROM
    Product
    4.
    WHERE
    type =
    'PC'
    ;

    В данном случае в столбец type таблицы Product_D будет подставлено значение по умолчанию PC для всех вставляемых строк.
    Отметим, что при использовании подзапроса, содержащего предикат, будут вставлены только те строки, для которых значение предиката равно TRUE (не UNKNOWN!). Другими словами, если бы столбец type в таблице Product допускал бы NULL-значение, и это значение присутствовало бы в ряде строк, то эти строки не были бы вставлены в таблицу Product_D.
    Преодолеть ограничение на вставку одной строки в операторе INSERT при использовании конструктора строки в предложении VALUES позволяет искусственный прием использования подзапроса, формирующего строку с предложением UNION ALL. Так если нам требуется вставить несколько строк при помощи одного оператора INSERT, можно написать:
    1.
    INSERT
    INTO
    Product_D
    2.
    SELECT
    'B'
    AS
    maker,
    1158
    AS
    model,
    'PC'
    AS
    type
    3.
    UNION
    ALL
    4.
    SELECT
    'C'
    ,
    2190
    ,
    'Laptop'
    5.
    UNION
    ALL
    6.
    SELECT
    'D'
    ,
    3219
    ,
    'Printer'
    ;
    Использование
    1   ...   18   19   20   21   22   23   24   25   ...   47


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