- •Оглавление Извлечение данных. Оператор select
- •Оператор select
- •Предикаты (часть I)
- •Предикаты сравнения
- •Предикат between
- •Предикат in
- •Переименование столбцов и вычисления в результирующем наборе
- •Предикаты (часть 2) Предикат like
- •Использование значения null в условиях поиска Предикат is [not] null
- •Получение итоговых значений
- •Предложение group by
- •Предложение having
- •Использование в запросе нескольких источников записей
- •Явные операции соединения
- •Традиционные операции над множествами и оператор select
- •Декартово произведение
- •Объединение
- •Пересечение и разность
- •Предикат exists
- •Использование ключевых слов some | any и all с предикатами сравнения
- •Еще о подзапросах
- •Преобразование типов
- •Оператор case
- •Функции Transact-sql для обработки даты/времени
- •Функция dateadd
- •Функция datediff
- •Функция datepart
- •Функция datename
- •Функции работы со строками в ms sql server 2005
- •Функция substring
- •Функция reverse
- •Функция replace
- •Функции ltrim и rtrim
- •Функции lower и upper
- •Функция unicode
- •Функция nchar
- •Операторы модификации данных
- •Оператор insert
- •Вставка строк в таблицу, содержащую автоинкрементируемое поле
- •Оператор update
- •Оператор delete
- •Приложение 1. Описание учебных баз данных
- •1. Компьютерная фирма
- •2. Фирма вторсырья
- •3. Корабли
- •4. Аэрофлот
- •5. Окраска
- •Приложение 2. Список упражнений (select)
- •Как объединить данные из двух столбцов в один без использования union и join?
- •1. Union all
- •2. Full join
- •3. Unpivot
- •Комментарии
- •Как добавить новый столбец в таблицу между существующими столбцами?
- •Как вывести по n строк из каждой группы?
- •"Классическое" решение
- •1. Соединение
- •2. Подзапрос в предложении select
- •Решение на основе ранжирующих функций
- •Как удалить дубликаты строк из таблицы?
- •1. Нумерация строк
- •2. Ранжирование строк внутри групп дубликатов
- •3. Удаление дубликатов из виртуальной таблицы
- •Как удалить дубликаты строк при наличии первичного ключа?
- •Id name
- •Id_pk color
- •Id name color
- •Обновление таблицы t_details
- •Id_pk name color dup min_id
- •Id_pk color
- •Id name
- •Id_pk color
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.
Давайте подробно рассмотрим построение запроса на удаление дубликатов этим методом.