Загрузка данных
--13.1 Напишите хранимую процедуру для вывода информации о сервере, о базе данных, о текущем пользователе, о текущем времени, и вызовите ее.
CREATE PROC Task1
AS
BEGIN
SELECT
@@Servername AS Сервер
,@@Version AS [Версия СУБД]
,Db_Name() AS [База данных]
,User AS [Пользователь базы данных]
,System_User AS [Системный пользователь]
,GETDATE() AS [Текущее время];
END;
GO
EXECUTE Task1;
--13.2 Напишите хранимую процедуру, которая выводит данные всех стран.
CREATE PROC Task2
AS
BEGIN
SELECT Название, Столица, Площадь, Население, Континент
FROM Countries;
END;
GO
EXECUTE Task2;
--13.3 Напишите хранимую процедуру, которая выводит список стран, кроме заданной части света, и вызовите ее.
CREATE PROC Task3
@Kont AS VARCHAR(50)
AS
BEGIN
SELECT Название, Столица, Площадь, Население, Континент
FROM Countries
WHERE Континент != @Kont;
END;
GO
EXECUTE Task3 'Азия';
--13.4 Напишите хранимую процедуру, которая выводит список стран, население которых находится в заданном интервале, и вызовите ее.
CREATE PROC Task4
@MinPop AS INT,
@MaxPop AS INT
AS
BEGIN
SELECT Название, Столица, Площадь, Население, Континент
FROM Countries
WHERE Население BETWEEN @MinPop AND @MaxPop;
END;
GO
EXECUTE Task4 10000000, 50000000;
--13.5 Напишите хранимую процедуру, которая возвращает количество стран, у которых в названии отсутствует заданная буква, и вызовите ее.
CREATE PROC Task5
@Буква AS CHAR(1),
@Количество AS INT OUTPUT
AS
BEGIN
SELECT @Количество = COUNT(*)
FROM Countries
WHERE CHARINDEX(@Буква, Название) = 0;
END;
GO
DECLARE @K INT;
DECLARE @Б CHAR(1) = 'а';
EXECUTE Task5 @Б, @K OUTPUT;
SELECT @K AS [Количество стран без буквы];
--13.6 Напишите хранимую процедуру для вывода пяти стран с наибольшим населением в заданной части света, и вызовите ее. Если часть света не указана, выбрать Африку.
CREATE PROC Task6
@Kont AS VARCHAR(50) = 'Африка'
AS
BEGIN
SELECT TOP 5 Название, Столица, Площадь, Население, Континент
FROM Countries
WHERE Континент = @Kont
ORDER BY Население DESC;
END;
GO
EXECUTE Task6 DEFAULT;
--13.7 Напишите хранимую процедуру, которая создает таблицу «Страны_С», и заполняет ее странами, названия которых начинаются с первой буквой вашей фамилии.
CREATE PROC Task7
AS
BEGIN
SELECT Название, Столица, Площадь, Население, Континент
INTO Страны_С
FROM Countries
WHERE LEFT(Название, 1) = 'С';
END;
GO
EXECUTE Task7;
--13.8 Напишите хранимую процедуру, которая удаляет таблицу, которую вы создали в предыдущем задании и возвращает количество удаленных строк.
CREATE PROC Task8
AS
BEGIN
DECLARE @K INT;
SELECT @K = COUNT(*)
FROM Страны_С;
DROP TABLE Страны_С;
RETURN @K;
END;
GO
DECLARE @Count INT;
EXECUTE @Count = Task8;
SELECT @Count AS [Количество строк в удаленной таблице];
--13.9 Напишите хранимую процедуру, принимающую число и возвращающую количество цифр в нем через параметр OUTPUT.
CREATE PROC Task9
@Num INT,
@DigitCount INT OUTPUT
AS
BEGIN
IF @Num = 0
SET @DigitCount = 1;
ELSE
BEGIN
SET @DigitCount = 0;
DECLARE @Temp INT = ABS(@Num);
WHILE @Temp > 0
BEGIN
SET @DigitCount = @DigitCount + 1;
SET @Temp = @Temp / 10;
END
END
END;
GO
DECLARE @Cnt INT;
EXECUTE Task9 12345, @Cnt OUTPUT;
SELECT @Cnt AS [Количество цифр];
--13.10 Напишите хранимую процедуру AddRightDigit, добавляющую к целому положительному числу К справа цифру D (D- входной параметр целого типа, лежащий в диапазоне [0..9], К - параметр целого типа, являющийся одновременно входным и выходным).
CREATE PROC AddRightDigit
@D INT,
@K INT OUTPUT
AS
BEGIN
SET @K = @K * 10 + @D;
END;
GO
DECLARE @Val INT = 123;
EXECUTE AddRightDigit 5, @Val OUTPUT;
SELECT @Val AS [Новое число];
--13.11 Напишите хранимую процедуру InvDigit, меняющую порядок следования цифр целого положительного числа К на обратный (К параметр целого типа, являющийся одновременно входным и выходным).
CREATE PROC InvDigit
@K INT OUTPUT
AS
BEGIN
DECLARE @Res INT = 0;
DECLARE @Temp INT = @K;
WHILE @Temp > 0
BEGIN
SET @Res = @Res * 10 + (@Temp % 10);
SET @Temp = @Temp / 10;
END
SET @K = @Res;
END;
GO
DECLARE @Val INT = 1234;
EXECUTE InvDigit @Val OUTPUT;
SELECT @Val AS [Инвертированное число];
--13.12 Напишите хранимую процедуру Swap, меняющую содержимое переменных Х и Y (Х и Y вещественные параметры, являющиеся одновременно входными и выходными).
CREATE PROC Swap
@X FLOAT OUTPUT,
@Y FLOAT OUTPUT
AS
BEGIN
DECLARE @Temp FLOAT = @X;
SET @X = @Y;
SET @Y = @Temp;
END;
GO
DECLARE @Val1 FLOAT = 5.5, @Val2 FLOAT = 10.2;
EXECUTE Swap @Val1 OUTPUT, @Val2 OUTPUT;
SELECT @Val1 AS X, @Val2 AS Y;
--13.13 Напишите хранимую процедуру SortInc, меняющую содержимое переменных А, В, С, таким образом, чтобы их значения оказались упорядоченными по возрастанию (А, В, С вещественные параметры, являющиеся одновременно входными и выходными).
CREATE PROC SortInc
@A FLOAT OUTPUT,
@B FLOAT OUTPUT,
@C FLOAT OUTPUT
AS
BEGIN
DECLARE @Temp FLOAT;
IF @A > @B BEGIN SET @Temp = @A; SET @A = @B; SET @B = @Temp; END
IF @A > @C BEGIN SET @Temp = @A; SET @A = @C; SET @C = @Temp; END
IF @B > @C BEGIN SET @Temp = @B; SET @B = @C; SET @C = @Temp; END
END;
GO
DECLARE @V1 FLOAT = 9.5, @V2 FLOAT = 2.1, @V3 FLOAT = 5.4;
EXECUTE SortInc @V1 OUTPUT, @V2 OUTPUT, @V3 OUTPUT;
SELECT @V1 AS A, @V2 AS B, @V3 AS C;
--13.14 Напишите хранимую процедуру DigitCountSum, находящую количество С цифр целого положительного числа К, а также их сумму S (К входной, С, S выходные параметры целого типа).
CREATE PROC DigitCountSum
@K INT,
@C INT OUTPUT,
@S INT OUTPUT
AS
BEGIN
SET @C = 0;
SET @S = 0;
DECLARE @Temp INT = ABS(@K);
IF @Temp = 0
BEGIN
SET @C = 1;
SET @S = 0;
END
ELSE
BEGIN
WHILE @Temp > 0
BEGIN
SET @S = @S + (@Temp % 10);
SET @C = @C + 1;
SET @Temp = @Temp / 10;
END
END
END;
GO
DECLARE @CountDigits INT, @SumDigits INT;
EXECUTE DigitCountSum 485, @CountDigits OUTPUT, @SumDigits OUTPUT;
SELECT @CountDigits AS [Количество цифр], @SumDigits AS [Сумма цифр];
--13.15 Напишите код, который удаляет все хранимые процедуры, вами созданные.
DROP PROC IF EXISTS Task1;
DROP PROC IF EXISTS Task2;
DROP PROC IF EXISTS Task3;
DROP PROC IF EXISTS Task4;
DROP PROC IF EXISTS Task5;
DROP PROC IF EXISTS Task6;
DROP PROC IF EXISTS Task7;
DROP PROC IF EXISTS Task8;
DROP PROC IF EXISTS Task9;
DROP PROC IF EXISTS AddRightDigit;
DROP PROC IF EXISTS InvDigit;
DROP PROC IF EXISTS Swap;
DROP PROC IF EXISTS SortInc;
DROP PROC IF EXISTS DigitCountSum;
GO
--14.1 Напишите триггер на изменение записи в таблице «Ученики». Данный триггер, в случае изменения данных, должен вывести «Запись изменена».
CREATE TRIGGER Task1 ON Ученики
AFTER UPDATE
AS
BEGIN
PRINT 'Запись изменена';
END;
GO
--14.2 Напишите триггер на добавление и удаление записи из таблицы «Ученики». Данный триггер, в случае успешного добавления или удаления данных, должен вывести «Количество строк изменено».
CREATE TRIGGER Task2 ON Ученики
AFTER INSERT, DELETE
AS
BEGIN
PRINT 'Количество строк изменено';
END;
GO
--14.3 Напишите триггер на добавление, изменение и удаление данных в таблице «Ученики». Данный триггер должен вывести «{Текущий пользователь изменил таблицу. Время: {текущее время}».
CREATE TRIGGER Task3 ON Ученики
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
DECLARE @Msg VARCHAR(200);
SET @Msg = SYSTEM_USER + ' изменил таблицу. Время: ' + CONVERT(VARCHAR, GETDATE(), 120);
PRINT @Msg;
END;
GO
--14.4 Напишите триггер на изменение записи в таблице «Ученики». Данный триггер, при попытке изменения данных, должен вывести «Нельзя редактировать данные».
CREATE TRIGGER Task4 ON Ученики
INSTEAD OF UPDATE
AS
BEGIN
PRINT 'Нельзя редактировать данные';
END;
GO
--14.5 Создать таблицу «Ученики_Сергеев», которая будет содержать фамилии удаленных учеников и даты их удаления. Написать триггер, который будет фиксировать в таблице «Ученики_Сергеев» данные учеников при удалении из таблицы «Ученики», в том случае, если у них остались однофамильцы в таблице «Ученики».
CREATE TABLE Ученики_Сергеев
(
Фамилия VARCHAR(50) NOT NULL,
Удалено DATETIME NOT NULL
);
GO
CREATE TRIGGER Task5 ON Ученики
AFTER DELETE
AS
BEGIN
INSERT INTO Ученики_Сергеев (Фамилия, Удалено)
SELECT d.Фамилия, GETDATE()
FROM DELETED d
WHERE EXISTS (
SELECT 1 FROM Ученики u WHERE u.Фамилия = d.Фамилия
);
END;
GO
--14.6 Напишите команды для приостановления и запуска триггера из предыдущей задачи.
DISABLE TRIGGER Task5 ON Ученики;
ENABLE TRIGGER Task5 ON Ученики;
GO
--14.7 Напишите команды для удаления всех созданных вами триггеров.
DROP TRIGGER IF EXISTS Task1;
DROP TRIGGER IF EXISTS Task2;
DROP TRIGGER IF EXISTS Task3;
DROP TRIGGER IF EXISTS Task4;
DROP TRIGGER IF EXISTS Task5;
GO
--15.1 Создайте представление, содержащее список африканских стран, население которых больше 10 млн. чел., а площадь больше 500 тыс. кв. км, и используйте его.
CREATE VIEW Task1_View
AS
SELECT
Название,
Столица,
Площадь,
Население,
Континент
FROM Countries
WHERE Континент = 'Африка'
AND Население > 10000000
AND Площадь > 500000;
GO
SELECT * FROM Task1_View;
GO
--15.2 Создайте представление, содержащее список континентов, среднюю площадь стран, которые находятся на нем, среднюю плотность населения, и используйте его.
CREATE VIEW Task2_View
AS
SELECT
Континент,
AVG(Площадь) AS [Средняя площадь],
AVG(CAST(Население AS FLOAT) / Площадь) AS [Средняя плотность]
FROM Countries
GROUP BY Континент;
GO
SELECT * FROM Task2_View;
GO
--15.3 Создайте представление, содержащее фамилии преподавателей, их должность, звание, степень, место работы, количество их экзаменов, и используйте его.
CREATE VIEW Task3_View
AS
SELECT
С.Фамилия,
С.Должность,
П.Звание,
П.Степень,
К.Название AS [Место работы],
COUNT(Э.Код) AS [Количество экзаменов]
FROM Сотрудник С
INNER JOIN Преподаватель П ON С.Таб_номер = П.Таб_номер
INNER JOIN Кафедра К ON С.Шифр = К.Шифр
LEFT JOIN Экзамен Э ON С.Таб_номер = Э.Таб_номер
GROUP BY С.Фамилия, С.Должность, П.Звание, П.Степень, К.Название;
GO
SELECT * FROM Task3_View;
GO
--15.4 Создайте табличную переменную, содержащую три столбца («Номер месяца», «Название месяца», «Количество дней»), заполните ее для текущего года, и используйте ее.
DECLARE @Task4_Table TABLE
(
[Номер месяца] INT,
[Название месяца] VARCHAR(50),
[Количество дней] INT
);
DECLARE @Month INT = 1;
WHILE @Month <= 12
BEGIN
DECLARE @Date DATE = DATEFROMPARTS(YEAR(GETDATE()), @Month, 1);
INSERT INTO @Task4_Table ([Номер месяца], [Название месяца], [Количество дней])
VALUES (
@Month,
DATENAME(MONTH, @Date),
DAY(EOMONTH(@Date))
);
SET @Month = @Month + 1;
END
SELECT * FROM @Task4_Table;
GO
--15.5 Создайте табличную переменную, содержащую список стран, площадь которых в 100 раз меньше, чем средняя площадь стран на континенте, где они находятся, и используйте ее.
DECLARE @Task5_Table TABLE
(
Название VARCHAR(50),
Столица VARCHAR(50),
Площадь FLOAT,
Население BIGINT,
Континент VARCHAR(50)
);
INSERT INTO @Task5_Table
SELECT А.Название, А.Столица, А.Площадь, А.Население, А.Континент
FROM Countries А
WHERE А.Площадь * 100 < (
SELECT AVG(Б.Площадь)
FROM Countries Б
WHERE Б.Континент = А.Континент
);
SELECT * FROM @Task5_Table;
GO
--15.6 Создайте локальную временную таблицу, имеющую три столбца («Номер недели», «Количество экзаменов», «Количество студентов»), заполните и используйте ее.
SELECT
DATEPART(WEEK, Дата) AS [Номер недели],
COUNT(Код) AS [Количество экзаменов],
COUNT(DISTINCT Рег_номер) AS [Количество студентов]
INTO #Task6_Temp
FROM Экзамен
GROUP BY DATEPART(WEEK, Дата);
SELECT * FROM #Task6_Temp;
DROP TABLE #Task6_Temp;
GO
--15.7 Создайте глобальную временную таблицу, содержащую название континентов, наибольшую и наименьшую площадь стран на них, заполните и используйте ее.
CREATE TABLE ##Task7_Global
(
Континент VARCHAR(50),
[Наибольшая площадь] FLOAT,
[Наименьшая площадь] FLOAT
);
INSERT INTO ##Task7_Global (Континент, [Наибольшая площадь], [Наименьшая площадь])
SELECT
Континент,
MAX(Площадь),
MIN(Площадь)
FROM Countries
GROUP BY Континент;
SELECT * FROM ##Task7_Global;
DROP TABLE ##Task7_Global;
GO
--15.8 С помощью обобщенных табличных выражений напишите запрос для вывода списка сотрудников, чьи зарплаты меньше, чем средняя зарплата по факультету, их зарплаты и название факультета.
WITH FacultyAvgSalary AS (
SELECT
Ф.Аббревиатура AS ФакультетШифр,
Ф.Название AS ФакультетНазвание,
AVG(С.Зарплата) AS [Средняя зарплата по факультету]
FROM Сотрудник С
INNER JOIN Кафедра К ON С.Шифр = К.Шифр
INNER JOIN Факультет Ф ON К.Факультет = Ф.Аббревиатура
GROUP BY Ф.Аббревиатура, Ф.Название
)
SELECT
С.Фамилия,
С.Зарплата,
F.ФакультетНазвание AS [Факультет]
FROM Сотрудник С
INNER JOIN Кафедра К ON С.Шифр = К.Шифр
INNER JOIN FacultyAvgSalary F ON К.Факультет = F.ФакультетШифр
WHERE С.Зарплата < F.[Средняя зарплата по факультету];
GO
--15.9 Напишите команды для удаления всех созданных вами представлений.
DROP VIEW IF EXISTS Task1_View;
DROP VIEW IF EXISTS Task2_View;
DROP VIEW IF EXISTS Task3_View;
GO