Изменения и удаление данных в SQL. Использование встроенных функций. Пункт 1 Создаём новую базу данных с названием Test
![]()
|
Пункт 1: Создаём новую базу данных с названием Test. За шаблон новой БД возьмём нашу udb_Test, то есть создадим 2 файла для данных по 3 Mb (в разных файловых группах) и 1 файл для журнала весом 1 Mb. ![]() Затем скопируем в неё таблицы Titles и Sales при помощи SELECT … INTO. SELECT * INTO Test.[dbo].titles FROM [udb_Test].[dbo].titles SELECT * INTO Test.[dbo].Sales FROM [udb_Test].[dbo].Sales Чтобы проверить корректность выполнения команды построим запросы, которые выведут все столбцы новых таблиц. SELECT * FROM Test.[dbo].titles SELECT * FROM Test.[dbo].Sales ![]() ![]() Все данные совпадают Чтобы проверить наличие первичных и внешних ключей у новых таблиц получим скрипт создания этих таблиц для его изучения. USE [Test] GO /****** Object: Table [dbo].[Sales] Script Date: 01.12.2022 20:14:26 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[Sales]( [stor_id] [char](4) NOT NULL, [ord_num] [varchar](20) NOT NULL, [ord_date] [datetime] NOT NULL, [qty] [smallint] NOT NULL, [payterms] [varchar](12) NOT NULL, [title_id] [varchar](6) NOT NULL ) ON [PRIMARY] GO USE [Test] GO /****** Object: Table [dbo].[titles] Script Date: 01.12.2022 20:14:08 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[titles]( [title_id] [varchar](6) NOT NULL, [title] [varchar](80) NOT NULL, [type] [char](12) NOT NULL, [pub_id] [char](4) NULL, [price] [money] NULL, [advance] [money] NULL, [royalty] [int] NULL, [ytd_sales] [int] NULL, [notes] [varchar](200) NULL, [pubdate] [datetime] NOT NULL ) ON [PRIMARY] GO Как мы можем видеть, в новых таблицах нет ни первичных, ни внешних ключей. Добавим их вручную по аналогии с исходной базой данных. ALTER TABLE Test.[dbo].Sales ADD PRIMARY KEY CLUSTERED ([stor_id],[ord_num],[title_id]) ALTER TABLE Test.[dbo].titles ADD PRIMARY KEY CLUSTERED ([title_id]) ALTER TABLE Test.[dbo].Sales ADD CONSTRAINT svaz FOREIGN KEY(title_id) REFERENCES Test.[dbo].titles(title_id) ![]() Проверяем наличие первичных и внешних ключей при помощи диаграммы базы данных. ![]() Пункт 2: При помощи запроса SELECT title FROM titles INNER JOIN Sales ON Sales.title_id = titles.title_id выведем все названия книг, у которых есть продажи Повторы?? ![]() Попытаемся удалить всю информацию о книге, с названием «The Busy Executive's Database Guide» следующим запросом: DELETE FROM titles WHERE title = 'The Busy Executive''s Database Guide' В результате мы получим ошибку «Конфликт инструкции DELETE с ограничением REFERENCE "svaz". Конфликт произошел в базе данных "Test", таблица "dbo.Sales", column 'title_id'», а запрос на удаление не будет выполнен. ![]() Данная ошибка появляется по причине того, что столбец title_id таблицы titles является внешним ключом для таблицы Sales. Из-за этой связи мы не можем удалить книгу из таблицы titles. Каким образом устанавливается ссылочная целостность данных таблиц? Её поддерживает поле title_id, являющееся первичным ключом для таблицы titles и внешним для Sales. Запросом последовательно удалим сначала все записи о продаже книги в таблице Sales, и только затем удалим запись о самой книге из таблицы tittles. Таким образом, мы не нарушим ссылочную целостность, потому что в SQL Server выполнение команд идёт по очереди. DECLARE @id varchar(30) SELECT @id = title_id FROM titles WHERE title = 'The Busy Executive''s Database Guide' DELETE FROM Sales WHERE title_id = @id DELETE FROM titles WHERE title = 'The Busy Executive''s Database Guide' ![]() Пункт 3: Чтобы установите каскадный способ поддержания ссылочной целостности данных в таблицах Titles и Sales используем конструкцию ON DELETE CASCADE при создании внешнего ключа. Для замены внешнего ключа удалим старый внешний ключ «svaz» и создадим новый «svazi» с конструкцией ON DELETE CASCADE. Удаление внешнего ключа «svaz»: ALTER TABLE Test.[dbo].Sales DROP CONSTRAINT svaz ![]() Добавление внешнего ключа «svazi»: ALTER TABLE Test.[dbo].Sales ADD CONSTRAINT svazi FOREIGN KEY (title_id) REFERENCES Test.[dbo].titles(title_id) ON DELETE CASCADE ![]() Для проверки корректности работы каскадного способа попытаемся удалить всю информацию о книге «But Is It User Friendly?» только из таблицы titles. DELETE FROM titles WHERE title = 'But Is It User Friendly?' ![]() Как мы видим, запрос выполнен успешно. Если проверить таблицу Sales, то будет видно, что из неё также удалены все связанные записи о продажах этой книги. Внешний ключ с каскадным удалением означает, что если запись в родительской таблице будет удалена, то соответствующие записи в дочерней таблице также будут удалены автоматически. Удалим каскадный способ поддержания ссылочной целостности. Для этого аналогично тому, как мы добавляли данный способ, удаляем данную связь и создаём новую, без каскадного способа поддержания ссылочной целостности. ALTER TABLE Test.[dbo].Sales DROP CONSTRAINT svazi ![]() ALTER TABLE Test.[dbo].Sales ADD CONSTRAINT svaz FOREIGN KEY (title_id) REFERENCES Test.[dbo].titles(title_id) ![]() Пункт 4: Напишите и выполните отладку команды для уменьшения цен у книг, изданных ранее заданного года (N) на Х%. Значения Х и N задайте через переменные: DECLARE @N date??, @X real; SELECT @N = '1991/06/15', @X = 25; SELECT (price - (price * (@X / 100))) AS 'Новая цена' FROM titles WHERE pubdate < @N; ![]() Постройте запрос, возвращающий текущее количество поставок книг (связанных строк в таблице Sales) в следующем виде: ![]() SELECT titles.title AS 'Название книги', CONCAT_WS(' ', 'Книга поставлялась', count(*), CASE count(*) WHEN 1 THEN 'раз' WHEN 2 THEN 'раза' WHEN 3 THEN 'раза' WHEN 4 THEN 'раза' WHEN 5 THEN 'раз' А как 6 и более раз?? ELSE ' ' END) AS 'Количество поставок' FROM sales, titles WHERE titles.title_id in (SELECT titles.title_id WHERE sales.title_id = titles.title_id) GROUP BY sales.title_id, titles.title SELECT title AS 'Название книги', CONCAT_WS(' ', 'Книга вообще не поставлялась в магазины', ' ') AS 'Количество поставок' FROM titles WHERE NOT EXISTS (select title_id from sales where sales.title_id = titles.title_id) Напишите и выполните отладку команды, которая по заданному в переменной названию книги увеличивает на один месяц дату поставки (sales.ord_date) экземпляров этой книги для её будущих (от текущей даты) поставок: DECLARE @title varchar(30); SELECT @title = 'The Gourmet Microwave'; SELECT dateadd(month, +1, ord_date) AS 'Дата' FROM sales, titles, titleauthor WHERE ord_date > getdate() AND sales.title_id in (select title_id from titleauthor where sales.title_id = titleauthor.title_id AND titleauthor.title_id in (select title_id from titles where titleauthor.title_id = titles.title_id AND title = @title)) Пункт 5: В переменных записаны старый и новый ключ книги. Напишите явную транзакцию, гарантирующую целостность базы при замене Title_id у этой книги: DECLARE @Old varchar(6), @New varchar(6); SELECT @Old = 'FR2748', @New = 'HG7845'; ALTER TABLE sales NOCHECK CONSTRAINT ALL; UPDATE titles SET title_id = @New WHERE title_id = @Old; UPDATE sales SET title_id = @New WHERE title_id = @Old; ALTER TABLE sales CHECK CONSTRAINT ALL; ![]() Пункт 6: Индивидуальное задание Вариант № 3 Номера студенческих билетов оканчиваются на 11, поэтому мы берём остаток от деления 11 на 8, то есть 3. По индивидуальному заданию была введена книга автора Иоанны Хмелевской «Стечение обстоятельств» с title_id = PC2947, поэтому далее вся работа будет происходить с данными только об этой книге. 1. Замену даты публикации книги, введенной по индивидуальному заданию, на 30 мая 2007г., если при этом не известен установленный формат даты, который нельзя изменить. ![]() ![]() Для изменения даты публикации используем запрос: UPDATE titles SET pubdate ='2007-05-30T00:00:00' WHERE title_id = 'PC2947' Проверим внесение изменений. ![]() ![]() 2. Удаление из таблицы Sales строки с наибольшей датой продажи книги, введенной в ЛР №3. ![]() declare @MaxDate datetime; SELECT @MaxDate = MAX(ord_date) FROM sales WHERE title_id = 'PC2947'; DELETE FROM sales WHERE title_id = 'PC2947' AND ord_date = @MaxDate ![]() 3. Заменяющей значение поля City для автора Bennet Abraham на значение поля City для автора Иоанна Хмелевская. ![]() declare @city varchar(30); SELECT @city = city FROM authors WHERE au_lname = 'Иоанна' AND au_fname = 'Хмелевская'; UPDATE authors SET city = @city WHERE au_lname = 'Bennet' AND au_fname = 'Abraham'; ![]() Контрольные вопросы 1. Сколько команд потребуется выполнить для изменения в БД первичного ключа в таблице titles в отсутствие каскадных операций? 4 команды 2. Как определить установленный в соединении формат представления даты (dateformat)? Можно при помощи командыSELECTgetdate()AS'Дата' вывести текущие дату и время и посмотреть установленный формат соединения. См. SELECT*FROMsys.dm_exec_sessions--+++ SELECT@@SPID--+++ ![]() 3. Напишите программу, которая из таблицы Sales записи с прошедшей датой поставки (ord_date) переносит?? в таблицу Sales_OLD, имеющую аналогичную структуру. SELECT * INTO [udb_Test].[dbo].sales_OLD FROM [udb_Test].[dbo].sales WHERE ord_date < getdate() ![]() 4. Напишите команду, которая заменяет значение поля City для автора фамилия и имя которого заданы в переменных @LN1 и @FN1, Если он переехал в город, где живет автор, фамилия и имя которого заданы в переменных @LN2 и @FN2. DECLARE @LN1 varchar(30), @FN1 varchar(30), @LN2 varchar(30), @FN2 varchar(30), @city varchar(20) SET @LN1 = 'Сергей' SET @FN1 = 'Каратыгин' SET @LN2 = 'White' SET @FN2 = 'Johnson' UPDATE authors SET city = (select city from authors where au_lname = @LN2 AND au_fname = @FN2) WHERE au_lname = @LN1 AND au_fname = @FN1 DECLARE @N VARCHAR(30), @count int SET @N = 'Sushi, Anyone?' SELECT @count = count(au_id) from titleauthor, titles WHERE title = @N AND titles.title_id = titleauthor.title_id UPDATE titleauthor SET royaltyper = 100 / @count WHERE titleauthor.title_id in (select title_id from titles where title = @N) Нет тестов?? 6. Напишите скрипт полного удаления из базы книги с названием, заданным в переменной @T, при этом авторы книги не удаляются. Если такой книги нет или она не одна, то удаление не выполняется. DECLARE @T VARCHAR(30), @flag varchar(3); SELECT @T = 'But Is It User Friendly?'; SET @flag = CASE WHEN (SELECT count(*) FROM titles WHERE title = @T) = 1 THEN 'OK' ELSE '' END; IF @flag = 'OK' BEGIN DELETE FROM titleauthor WHERE title_id in (select title_id from titles WHERE title = @T) DELETE FROM sales WHERE title_id in (select title_id from titles WHERE title = @T) DELETE FROM titles WHERE title = @T END 7. Создайте программу, которая в таблице titles заменяет значение поля ytd_sales – количество проданных экземпляров издания равным сумме значений поля qty – количество экземпляров книги по всем поставкам каждой книги. SELECT title_id, sum(qty) AS 'ytd_new' INTO #Table FROM sales GROUP BY title_id UPDATE titles SET ytd_sales = ytd_new FROM titles JOIN #Table on titles.title_id = #Table.title_id |