Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
SQL (от Сани Сафронова).doc
Скачиваний:
71
Добавлен:
03.06.2015
Размер:
969.22 Кб
Скачать

2. Подзапрос в предложении select

SELECT (SELECT maker

FROM Product

WHERE Product.model = Pr1.model) maker,

Pr1.model, Pr1.type

FROM product Pr1 JOIN product Pr2

ON Pr1.type = Pr2.type AND Pr1.model >= Pr2.model

GROUP BY Pr1.type, Pr1.model

HAVING COUNT (*) <= 3

ORDER BY type,model

Использование подзапроса в предложении SELECT допускается, если он возвращает всего одно значение для каждой строки основного запроса. Это условие у нас выполняется, т.к. мы выбираем производителя модели, которая передается из основного запроса и является уникальной (первичный ключ в таблице Product).

Решение на основе ранжирующих функций

Ранжирующие функции - ROW_NUMBER, RANK, DENSE_RANKиNTILEпоявились в составеSQL Server, начиная с версии 2005. Их появление в языке SQL было вызвано потребностью выполнять упорядоченные вычисления. Собственно, наше упражнение как раз и относится к этому классу задач. И теперь у нас есть возможность оценить данное приобретение. :

Для решения нашей задачи воспользуемся функцией RANK. Эта функция позволяет разбить все строки, возвращаемые запросом, на группы и вычислить ранг каждой строки в группе в соответствии заданной сортировкой. Поскольку мы будем сортировать по уникальному номеру модели, то ранг фактически будет совпадать с номером строки в группе. Итак, решение

SELECT maker, model, type FROM

(

SELECT maker, model, type, RANK() OVER(PARTITION BY type ORDER BY model) num

FROM Product

) X

WHERE num <= 3

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

Экономно, не так ли. Однако давайте разберем более детально конструкцию

RANK() OVER(PARTITION BY type ORDER BY model)

Предложение PARTITION BY typeформирует группы; в одну группу у нас попадают строки, имеющий один и тот же тип продукции (одно и то же значение в столбце type).

Предложение ORDER BY modelзадает сортировку строк в группе (по возрастанию номера модели).

Наконец, RANK()присваивает ранг каждой строке в группе на основе заданной сортировки, т.е. первая строка в группе получает ранг 1, следующая, если она имеет отличный номер модели, ранг 2 и т.д. Как я уже сказал, поскольку номер модели уникальный, то каждая строка в группе будет иметь отличный ранг. В противном случае, строки с одинаковым номером модели имели бы одинаковый ранг.

Подробное описание функций ранжирования выходит за рамки данной статьи, но, возможно, я напишу нечто подобное для Учебника по SQL.

Dzone.com

Как удалить дубликаты строк из таблицы?

    Моисеенко С.И. (13-06-2009)

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

Пусть имеется следующая таблица T:

name

John

Smith

John

Smith

Smith

Tom

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

Распространенным решением данной проблемы является создание вспомогательной таблицы требуемой структуры, в которую копируются уникальные строки из таблицы T с последующим удалением таблицы T и переименованием вспомогательной таблицы. Ниже приводится код на языке T-SQL, реализующий данный алгоритм.

CREATE TABLE Ttemp(name VARCHAR(50) NOT NULL PRIMARY KEY);

GO

INSERT INTO Ttemp

SELECT DISTINCT * FROM T;

GO

DROP TABLE T;

GO

EXEC sp_rename 'Ttemp', 'T';

GO

SELECT * FROM T;

В результате получим то, что и требовалось:

name

John

Smith

Tom

При этом ограничение первичного ключа будет препятствовать появлению дубликатов впоследствии.

А можно ли обойтись без создания новой таблицы? Можно. Например, с помощью такого алгоритма: - добавить новый столбец типа счетчик (IDENTITY), который перенумерует все имеющиеся строки в таблице; - из каждой группы строк с одинаковым значением в столбце nameудалить все строки за исключением строки с максимальным номером (или минимальным - это все равно, т.к. мы имеем дело с дубликатами); - удалить вспомогательный столбец; - наложить ограничение.

Вот пример реализации такого подхода:

ALTER TABLE T

ADD id INT IDENTITY(1,1);

GO

DELETE FROM T

WHERE id < (SELECT MAX(id)

FROM T AS T1

WHERE T.name = T1.name

);

GO

ALTER TABLE T

DROP COLUMN id;

GO

ALTER TABLE T

ALTER COLUMN name VARCHAR(50) NOT NULL;

GO

ALTER TABLE T

ADD CONSTRAINT T_PK PRIMARY KEY(name);

GO

А если без создания дополнительного столбца? Опять ответ утвердительный, но тут нам потребуются новые возможности языка, специфицированные в стандарте ANSI SQL-99. Идея состоит в том, чтобы создавать не постоянный столбец в таблице, который потом потребуется удалять, а виртуальный (вычисляемый). Этот столбец мы создадим с помощьюоконных функций, присвоив ранг каждой строке внутри окна, определяемого равенством значений в столбцеname. Наконец, мы удалим все строки с рангом выше 1.

Давайте подробно рассмотрим построение запроса на удаление дубликатов этим методом.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]