
- •ProblemForExamSqlQuery17.Sql - Test
- •ProblemForExamSqlQuery17.Sql - Solution
- •ProblemForExamSqlQuery16.Sql - Test
- •ProblemForExamSqlQuery16.Sql - Solution
- •ProblemForExamSqlQuery19.Sql - Test
- •ProblemForExamSqlQuery19.Sql – Solution
- •ProblemForExamSqlQuery25.Sql – Solution
- •Для создания резервной копии базы данных воспользоваться инструкцией backup database, имеющей следующий формат:
- •Имена баз данных экземпляра sql Server можно извлечь из системного представления sys.Databases.
Базы данных. Задачи на модули SQL
Вариант 01
Создать хранимую процедуру без параметров, в которой для экземпляра SQL Server создаются резервные копии всех пользовательских баз данных. Имя файла резервной копии должно состоять из имени базы данных и даты создания резервной копии, разделенных символом нижнего подчеркивания. Дата создания резервной копии должна быть представлена в формате YYYYDDMM. Созданную хранимую процедуру протестировать.
Рекомендации.
Для создания резервной копии базы данных воспользоваться инструкцией BACKUP DATABASE, имеющей следующий формат:
BACKUP DATABASE имя_базы_данных TO DISK = полная_спецификация_файла_резервной_копии
Имена баз данных экземпляра SQL Server можно извлечь из системного представления sys.databases.
-------------------------------
Написать сценарий на T-SQL, в котором для экземпляра SQL Server создаются резервные копии всех пользовательских баз данных. Имя файла резервной копии должно состоять из имени базы данных и даты создания резервной копии, разделенных символом нижнего подчеркивания. Дата создания резервной копии должна быть представлена в формате YYYYDDMM. Созданный сценарий протестировать.
DECLARE @name VARCHAR(50) – имя базы данных
DECLARE @path VARCHAR(256) – путь к backup-файлу
DECLARE @fileName VARCHAR(256) – полная спецификация файла
DECLARE @fileDate VARCHAR(20) – часть имени backup-файла, содержащая дату его создания
SET @path = 'D:\Backup\'
SELECT @fileDate = CONVERT(VARCHAR(20),GETDATE(),112)
DECLARE db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases –- sys.databases
WHERE name NOT IN ('master','model','msdb','tempdb')
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @name
WHILE @@FETCH_STATUS = 0
BEGIN
SET @fileName = @path + @name + '_' + @fileDate + '.BAK'
BACKUP DATABASE @name TO DISK = @fileName
FETCH NEXT FROM db_cursor INTO @name
END
CLOSE db_cursor
DEALLOCATE db_cursor
Создать и протестировать хранимую процедуру T-SQL, в которой для экземпляра SQL Server создаются резервные копии всех пользовательских баз данных. Имя файла резервной копии должно состоять из имени базы данных и даты создания резервной копии, разделенных символом нижнего подчеркивания. Дата создания резервной копии должна быть представлена в формате YYYYDDMM.
Рекомендации
Для создания резервной копии базы данных воспользоваться инструкцией BACKUP DATABASE, имеющей следующий формат:
BACKUP DATABASE имя_базы_данных TO DISK = полная_спецификация_файла_резервной_копии
Имена баз данных экземпляра SQL Server можно извлечь из системного представления sys.databases.
CREATE PROCEDURE usp_01 @path VARCHAR(256)
AS
BEGIN
DECLARE @name VARCHAR(50) -- имя базы данных
DECLARE @fileName VARCHAR(256) -- полная спецификация файла
DECLARE @fileDate VARCHAR(20) -- часть имени backup-файла, содержащая дату его создания
SELECT @fileDate = CONVERT(VARCHAR(20),GETDATE(),112)
DECLARE db_cursor CURSOR FOR
SELECT name
FROM sys.databases
WHERE name NOT IN ('master','model','msdb','tempdb')
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @name
WHILE @@FETCH_STATUS = 0
BEGIN
SET @fileName = @path + @name + '_' + @fileDate + '.BAK'
BACKUP DATABASE @name TO DISK = @fileName
FETCH NEXT FROM db_cursor INTO @name
END
CLOSE db_cursor
DEALLOCATE db_cursor
END
GO
Условия тестирования
EXEC usp_01 @path = 'D:\BACKUP\'
GO
Вариант 02
Создать хранимую процедуру, которая, не уничтожая базу данных, уничтожает все те таблицы текущей базы данных в схеме 'dbo', имена которых начинаются с фразы 'TableName'. Созданную хранимую процедуру протестировать.
Рекомендации.
Для уничтожения таблицы воспользоваться инструкцией DROP TABLE.
Информацию о таблицах базы данных можно извлечь из системного представления sys.objects.
----------------------------
Создать и протестировать хранимую процедуру на T-SQL, которая, не уничтожая текущую базу данных, уничтожает все таблицы в схеме 'dbo', имена которых начинаются с префикса, указываемого параметром процедуры.
CREATE PROCEDURE usp_02 @param VARCHAR(150)
AS
BEGIN
DECLARE @tname VARCHAR(150)
DECLARE @strsql VARCHAR(300)
SELECT @tname = (SELECT TOP 1 [name] FROM sys.objects WHERE [type] = 'U' and [name] like @param+'%' ORDER BY [name])
WHILE @tname IS NOT NULL
BEGIN
SELECT @strsql = 'DROP TABLE [dbo].[' + RTRIM(@tname) + ']';
EXEC (@strsql);
PRINT 'Dropped Table : ' + @tname;
SELECT @tname = (SELECT TOP 1 [name] FROM sys.objects WHERE [type] = 'U' AND [name] LIKE @param+'%' AND [name] > @tname ORDER BY [name]);
END;
END;
GO
Условия тестирования
CREATE TABLE TableNameXXX (c1 int);
GO
CREATE TABLE TableNameYYY (c1 float);
GO
CREATE TABLE TableNameZZZ (c1 char(2));
GO
EXEC usp_02 @param='TableName';
GO
Результаты тестирования
Dropped Table : TableNameXXX
Dropped Table : TableNameYYY
Dropped Table : TableNameZZZ
-----------------
Напишите сценарий, который, не уничтожая базу данных, уничтожает все те таблицы базы данных, имена которых начинаются с фразы 'TableName'. Созданный сценарий протестировать.
USE demodb
GO
DECLARE @tname VARCHAR(150)
DECLARE @strsql VARCHAR(300)
SELECT @tname = (SELECT TOP 1 [name] FROM sys.objects WHERE [type] = 'U' and [name] like N'TableName%' ORDER BY [name])
WHILE @tname IS NOT NULL
BEGIN
SELECT @strsql = 'DROP TABLE [dbo].[' + RTRIM(@tname) + ']'
EXEC (@strsql)
PRINT 'Dropped Table : ' + @tname
SELECT @tname = (SELECT TOP 1 [name] FROM sys.objects WHERE [type] = 'U' AND [name] like N'TableName%' AND [name] > @tname ORDER BY [name])
GO
Условия тестирования
USE demodb
GO
CREATE TABLE TableNameXXX (c1 int)
GO
CREATE TABLE TableNameYYY (c1 float)
GO
CREATE TABLE TableNameZZZ (c1 char(2))
GO
Результаты тестирования
Dropped Table : TableNameXXX
Dropped Table : TableNameYYY
Dropped Table : TableNameZZZ
Вариант 03
Создать хранимую процедуру с входным параметром, которая выводит имена и описания типа объектов (только хранимых процедур и скалярных функций), в тексте которых на языке SQL встречается строка, задаваемая параметром процедуры. Созданную хранимую процедуру протестировать.
Рекомендации.
Информацию об объектах базы данных можно извлечь из системного представления sys.objects.
Информацию о модулях базы данных можно извлечь из системного представления sys.sql_modules.
-------------------
Написать хранимую процедуру с входным параметром, которая выводит имена и описания типа объектов (хранимых процедур и скалярных функций), в тексте которых на языке SQL встречается строка, задаваемая параметром процедуры. Созданную процедуру протестировать.
USE demodb
GO
IF OBJECT_ID('dbo.search_procedure', 'P') IS NOT NULL
DROP PROCEDURE dbo.search_procedure
GO
-- Создание хранимой процедуры
CREATE PROCEDURE dbo.search_procedure @search_text nvarchar(100)
AS
BEGIN
DECLARE @sql_string nvarchar(1000)
SET @sql_string =
'SELECT DISTINCT o.name AS [Имя объекта], o.type_desc AS [Описание типа объекта]
FROM sys.sql_modules m INNER JOIN sys.objects o ON m.object_id=o.object_id
WHERE m.definition LIKE ''%'+@search_text+'%'' AND (o.type=''P'' OR o.type=''FN'')'
EXEC ( @sql_string )
END
GO
-- Тестирование хранимой процедуры
EXEC dbo.search_procedure @search_text = N'XML'
Вариант 04
Создать хранимую процедуру с двумя входными параметрами – имя базы данных и имя таблицы, которая выводит сведения об индексах указанной таблицы в указанной базе данных. Созданную хранимую процедуру протестировать.
Рекомендации.
Сведения об индексах указанной таблицы в указанной базе данных можно получить с помощью динамической административной функции sys.dm_db_index_physical_stats, принимающей пять параметров:
Идентификатор базы данных - можно получить с помощью функции метаданных DB_ID.
Идентификатор таблицы - можно получить с помощью функции метаданных OBJECT_ID.
Для прочих параметров можно указать значения NULL.
Если имя базы данных задано неверно, напечатать сообщение 'Invalid database'.
Если имя таблицы задано неверно, напечатать сообщение 'Invalid table'.
USE demodb;
GO
-- ********************************************************************************
-- Создаем хранимую процедуру получения сведений об индексах
-- ********************************************************************************
IF OBJECT_ID(N'dbo.GetInfoAboutIndex', 'P') IS NOT NULL
DROP PROCEDURE dbo.GetInfoAboutIndex;
GO
CREATE PROCEDURE dbo.GetInfoAboutIndex @dbname nvarchar(50), @tblname nvarchar(50)
AS
BEGIN
DECLARE @db_id int;
DECLARE @object_id int;
SET @db_id = DB_ID(@dbname);
IF @db_id IS NULL
BEGIN;
PRINT N'Invalid database';
RETURN;
END;
SET @object_id = OBJECT_ID(@dbname+'.'+@tblname, 'U');
IF @object_id IS NULL
BEGIN;
PRINT N'Invalid object';
RETURN;
END;
SELECT * FROM sys.dm_db_index_physical_stats(@db_id, @object_id, NULL, NULL, NULL);
END;
GO
-- ********************************************************************************
-- Проверяем хранимую процедуру на четырех примерах
-- ********************************************************************************
USE demodb;
GO
EXEC GetInfoAboutIndex @dbname=N'AdventureWorks', @tblname=N'Person.Address'
EXEC GetInfoAboutIndex @dbname=N'Northwind', @tblname=N'dbo.Orders'
EXEC GetInfoAboutIndex @dbname=N'Northwint', @tblname=N'dbo.Orders' -- Invalid database
EXEC GetInfoAboutIndex @dbname=N'Northwind', @tblname=N'Orders' -- Invalid object
GO
------------------
Отредактировать (вариант 16)
IF OBJECT_ID ( 'dbo.Metadata', 'P' ) IS NOT NULL
DROP PROCEDURE dbo.Metadata
GO
CREATE PROCEDURE dbo.Metadata
@nametable varchar(10)
AS
if(OBJECT_ID(@nametable)is null)
print 'Invalid table!'
else
begin
SELECT sm.object_id AS TableID, OBJECT_NAME(sm.object_id) AS TableName
FROM sys.dm_db_index_physical_stats(DB_ID() ,OBJECT_ID(@nametable), null, null, null) as sm
end;
GO
EXEC dbo.Metadata 'dbo.H'
GO
Вариант 05
Создать хранимую процедуру с входным параметром – имя таблицы, которая удаляет дубликаты записей из указанной таблицы в текущей базе данных. Созданную хранимую процедуру протестировать.
Рекомендации.
Если имя таблицы задано неверно, напечатать сообщение 'Invalid table'.
---------------------
USE master
GO
IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'demodb') CREATE DATABASE demodb
GO
USE demodb
GO
IF OBJECT_ID(N'dbo.Employee', 'U') IS NOT NULL DROP TABLE dbo.Employee
GO
CREATE TABLE dbo.Employee
(
Id int NOT NULL,
Name nvarchar(20) NOT NULL,
Salary decimal NOT NULL
);
GO
INSERT INTO dbo.Employee (Id, Name, Salary)
VALUES (1, N'Ram', 1000), (1, N'Ram', 1000), (2, N'Joe', 2000), (2, N'Joe', 1000),
(3, N'Mary', 1000), (4, N'Julie', 5000), (2, N'Joe', 1000), (1, N'Ram', 1000)
GO
/*
Хранимая процедура удаления дубликатов (второго или следующих экземпляров) записей из таблицы Employee
*/
CREATE PROCEDURE DelAllDuplicateRecords
AS
BEGIN
DECLARE @id int, @name varchar (20), @cnt int, @salary numeric
DECLARE GetAllDuplicateRecords CURSOR LOCAL STATIC FOR
SELECT COUNT (*), Id, Name, Salary
FROM dbo.Employee (NOLOCK)
GROUP BY Id, Name, Salary
HAVING COUNT(*)>1
OPEN GetAllDuplicateRecords
FETCH NEXT FROM GetAllDuplicateRecords INTO @cnt, @id, @name, @salary
WHILE @@FETCH_STATUS = 0
BEGIN
SET @cnt = @cnt-1
SET ROWCOUNT @cnt
DELETE FROM Employee WHERE Id=@id and Name=@name and Salary=@salary
SET ROWCOUNT 0
FETCH NEXT FROM GetAllDuplicateRecords INTO @cnt, @id, @name, @salary
END
CLOSE GetAllDuplicateRecords
DEALLOCATE GetAllDuplicateRecords
END
GO
-- ************************************************************
-- Тестирование хранимой процедуры
-- ************************************************************
SELECT Id, Name, Salary FROM dbo.Employee ORDER BY Id
GO
EXEC DelAllDuplicateRecords
GO
SELECT Id, Name, Salary FROM dbo.Employee ORDER BY Id
GO
Результаты тестирования
1 Ram 1000
1 Ram 1000
1 Ram 1000
2 Joe 1000
2 Joe 2000
2 Joe 1000
3 Mary 1000
4 Julie 5000
1 Ram 1000
2 Joe 1000
2 Joe 2000
3 Mary 1000
4 Julie 5000
---------------------------------
ProblemForExam08
1> USE demodb
2> GO
Changed database context to 'demodb'.
1> IF OBJECT_ID(N'dbo.Employee', 'U') IS NOT NULL
2> DROP TABLE dbo.Employee
3> GO
1> CREATE TABLE dbo.Employee
2> (
3> Id int NOT NULL,
4> Name nvarchar(20) NOT NULL,
5> Salary decimal NOT NULL
6> );
7> GO
1> INSERT INTO dbo.Employee (Id, Name, Salary)
2> VALUES
3> (1, N'Ram', 1000),
4> (1, N'Ram', 1000),
5> (2, N'Joe', 2000),
6> (2, N'Joe', 1000),
7> (3, N'Mary', 1000),
8> (4, N'Julie', 5000),
9> (2, N'Joe', 1000),
10> (1, N'Ram', 1000)
11> GO
(8 rows affected)
1> SELECT Id, Name, Salary FROM dbo.Employee
2> GO
Id Name Salary
----------- -------------------- --------------------
1 Ram 1000
1 Ram 1000
2 Joe 2000
2 Joe 1000
3 Mary 1000
4 Julie 5000
2 Joe 1000
1 Ram 1000
(8 rows affected)
1> -- ************************************************************
2> -- Сценарий удаления дубликатов (второго или следующих экземпляров)
3> -- записей из таблицы Employee
4> -- ************************************************************
5> DECLARE @id int, @name varchar (20), @cnt int, @salary numeric
6> DECLARE GetAllDuplicateRecords CURSOR LOCAL STATIC FOR
7> SELECT COUNT (*), Id, Name, Salary
8> FROM dbo.Employee (NOLOCK)
9> GROUP BY Id, Name, Salary
10> HAVING COUNT(*)>1
11> OPEN GetAllDuplicateRecords
12> FETCH NEXT FROM GetAllDuplicateRecords INTO @cnt, @id, @name, @salary
13> WHILE @@FETCH_STATUS = 0
14> BEGIN
15> SET @cnt = @cnt-1
16> SET ROWCOUNT @cnt
17> DELETE FROM Employee WHERE Id=@id and Name=@name and Salary=@salary
18> SET ROWCOUNT 0
19> -- DELETE TOP (@cnt)FROM Employee WHERE Id=@id and Name=@name and Salary
=@salary
20> FETCH NEXT FROM GetAllDuplicateRecords INTO @cnt, @id, @name, @salary
21> END
22> CLOSE GetAllDuplicateRecords
23> DEALLOCATE GetAllDuplicateRecords
24> -- ************************************************************
25> GO
(2 rows affected)
1> SELECT Id, Name, Salary FROM dbo.Employee ORDER BY Id
2> GO
Id Name Salary
----------- -------------------- --------------------
1 Ram 1000
2 Joe 1000
2 Joe 2000
3 Mary 1000
4 Julie 5000
(5 rows affected)
USE demodb
GO
IF OBJECT_ID(N'dbo.Employee', 'U') IS NOT NULL
DROP TABLE dbo.Employee
GO
CREATE TABLE dbo.Employee
(
Id int NOT NULL,
Name nvarchar(20) NOT NULL,
Salary decimal NOT NULL
);
GO
INSERT INTO dbo.Employee (Id, Name, Salary)
VALUES
(1, N'Ram', 1000),
(1, N'Ram', 1000),
(2, N'Joe', 2000),
(2, N'Joe', 1000),
(3, N'Mary', 1000),
(4, N'Julie', 5000),
(2, N'Joe', 1000),
(1, N'Ram', 1000)
GO
SELECT Id, Name, Salary FROM dbo.Employee
GO
-- ************************************************************
-- Сценарий удаления дубликатов (второго или следующих экземпляров)
-- записей из таблицы Employee –
-- ************************************************************
DECLARE @id int, @name varchar (20), @cnt int, @salary numeric
DECLARE GetAllDuplicateRecords CURSOR LOCAL STATIC FOR
SELECT COUNT (*), Id, Name, Salary
FROM dbo.Employee (NOLOCK)
GROUP BY Id, Name, Salary
HAVING COUNT(*)>1
OPEN GetAllDuplicateRecords
FETCH NEXT FROM GetAllDuplicateRecords INTO @cnt, @id, @name, @salary
WHILE @@FETCH_STATUS = 0
BEGIN
SET @cnt = @cnt-1
SET ROWCOUNT @cnt
DELETE FROM Employee WHERE Id=@id and Name=@name and Salary=@salary
SET ROWCOUNT 0
-- DELETE TOP (@cnt)FROM Employee WHERE Id=@id and Name=@name and Salary=@salary
FETCH NEXT FROM GetAllDuplicateRecords INTO @cnt, @id, @name, @salary
END
CLOSE GetAllDuplicateRecords
DEALLOCATE GetAllDuplicateRecords
-- ************************************************************
GO
SELECT Id, Name, Salary FROM dbo.Employee ORDER BY Id
GO
Вариант 06
Создать хранимую процедуру без параметров, которая перестраивает все индексы всех таблиц в схеме 'dbo' в текущей базе данных. Созданную хранимую процедуру протестировать.
Рекомендации.
Информацию о таблицах базы данных можно извлечь из системного представления sys.objects.
Для перестроения индексов для таблицы в указанной базе данных воспользоваться командой DBCC DBREINDEX.
Использовать значение коэффициента заполнения для индекса, указанное при создании индекса.
--------------------
/*
REBUILD_INDEX
Написать хранимую процедуру без параметров, которая перестраивает все индексы всех таблиц в схеме dbo в произвольной базе данных, например, Northwind. Для перестроения индексов для таблицы в указанной базе данных воспользолваться командой DBCC DBREINDEX. Использовать значение коэффициента заполнения для индекса, указанное при создании индекса.
*/
USE Northwind
GO
ALTER PROCEDURE REBUILD_INDEX
AS
BEGIN
DECLARE @tablename varchar(255), @tablename_header varchar(600), @sql varchar(600)
DECLARE tnames_cursor CURSOR FOR
SELECT 'tablename'=o.name
FROM sys.objects o WHERE o.type = 'U' AND o.principal_id IS NULL
OPEN tnames_cursor
FETCH NEXT FROM tnames_cursor INTO @tablename
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
BEGIN
SELECT @tablename_header = '*** Updating '+rtrim(upper(@tablename))+'('+convert(varchar, getdate(), 20) + ') ***'
PRINT @tablename_header
SELECT @sql = 'DBCC DBREINDEX("dbo.'+@tablename+'", '''',0)'
EXEC ( @sql )
END
FETCH NEXT FROM tnames_cursor INTO @tablename
END
PRINT '*** DBREINDEX have been updated for all tables (' + convert(varchar,getdate(),20) + ') ***'
CLOSE tnames_cursor
DEALLOCATE tnames_cursor
END
GO
-- Тестирование хранимой процедуры
USE Northwind
GO
EXEC REBUILD_INDEX
GO
--------------
(Рома)
CREATE PROC dbo.reindexing
AS
BEGIN
SELECT * FROM A
SELECT * FROM B
SELECT * FROM P
--IF OBJECT_ID (N'dbo.A.PK_A2') IS NULL
-- CREATE NONCLUSTERED INDEX PK_A2
--ON A
-- (Ano DESC, Aname ASC, Adate);
IF OBJECT_ID (N'dbo.A.PK_B2') IS NULL
CREATE NONCLUSTERED INDEX PK_B2
ON B
(Bno DESC, Bname ASC, Bpart);
IF OBJECT_ID (N'dbo.A.PK_P2') IS NULL
CREATE NONCLUSTERED INDEX PK_P2
ON P
(Pno DESC, Scope ASC, OwnerS);
DBCC DBREINDEX ("A",PK_A2, 100);
DBCC DBREINDEX ("B",PK_B2, 50);
DBCC DBREINDEX ("P",PK_P2, 90);
SELECT * FROM A
SELECT * FROM B
SELECT * FROM P
END;
GO
EXEC dbo.reindexing
GO
Вариант 07
Создать хранимую процедуру без параметров, которая в текущей базе данных обновляет все статистики для таблиц в схеме 'dbo'. Созданную хранимую процедуру протестировать.
Рекомендации.
Информацию о таблицах базы данных можно извлечь из системного представления sys.objects.
Чтобы обновить статистику оптимизации запросов для таблицы в указанной базе данных, необходимо воспользоваться инструкцией UPDATE STATISTICS, которая в простейшем случае имеет следующий формат:
UPDATE STATISTICS имя_схемы.имя_таблицы
----------------------
(Юра)
ALTER PROCEDURE dbo.UpdateStatistics AS
BEGIN
UPDATE STATISTICS dbo.attendance;
UPDATE STATISTICS dbo.students;
UPDATE STATISTICS dbo.subjects;
UPDATE STATISTICS dbo.rooms;
END;
GO
EXEC dbo.UpdateStatistics;
GO
---------------------
/*
Написать хранимую процедуру без параметров, которая в произвольной базе данных, например, Northwind, обновляет все статистики для таблиц в схеме dbo.
*/
USE Northwind
GO
ALTER PROCEDURE UPDATE_STATISTICS
AS
BEGIN
DECLARE @tablename varchar(255), @tablename_header varchar(600), @sql varchar(600)
DECLARE tnames_cursor CURSOR FOR
SELECT 'tablename'=o.name
FROM sys.objects o
WHERE o.type = 'U' AND o.principal_id IS NULL
OPEN tnames_cursor
FETCH NEXT FROM tnames_cursor INTO @tablename
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
BEGIN
SELECT @tablename_header = '*** Updating '+rtrim(upper(@tablename))+'('+convert(varchar, getdate(), 20) + ') ***'
PRINT @tablename_header
SELECT @sql = 'UPDATE STATISTICS '+'dbo.'+@tablename
EXEC ( @sql )
END
FETCH NEXT FROM tnames_cursor INTO @tablename
END
PRINT '*** Statistics has been updated for all tables ('+convert(varchar,getdate(),20) + ') ***'
CLOSE tnames_cursor
DEALLOCATE tnames_cursor
END
GO
EXEC UPDATE_STATISTICS
GO
Вариант 08
Создать хранимую процедуру без параметров, которая осуществляет поиск потенциально опасных ключевых слов в хранимых процедурах в текущей базе данных. В данном случае таким ключевым словом является 'EXEC'. Хранимая процедура выводит инструкцию 'EXEC', которая выполняет командную строку — строку символов или один из следующих модулей: хранимую процедуру или скалярную пользовательскую функцию. Созданную хранимую процедуру протестировать.
Рекомендации.
Информацию об объектах базы данных можно извлечь из системного представления sys.objects.
Информацию о модулях базы данных можно извлечь из системного представления sys.sql_modules.
Для работы со строками воспользоваться следующими функциями:
CHARINDEX ( expression1 ,expression2 [ , start_location ] )
Выполняет поиск выражения expression1 в выражении expression2 и в случае обнаружения возвращает его начальную позицию. Поиск начинается с аргумента start_location.
SUBSTRING ( value_expression , start_expression , length_expression )
Возвращает фрагмент символьного, двоичного, текстового или графического выражения.
DATALENGTH ( expression )
Возвращает число байтов, использованных для представления выражения.
---------------------
/*
Сценарий поиска потенциально опасных ключевых слов в хранимых процедурах. В данном случае таким ключевым словом является 'EXEC'.
Сценарий печатает инструкцию 'EXEC', которая выполняет командную строку — строку символов или один из следующих модулей: хранимую процедуру или скалярную пользовательскую функцию.
*/
USE Northwind
GO
DECLARE @i int, @j int, @current_proc varchar(255),@current_text varchar(8000)
DECLARE _Cursor CURSOR FOR
SELECT o.name, m.definition
FROM sys.objects o INNER JOIN sys.sql_modules m ON o.object_id = m.object_id
WHERE o.type='P' AND m.definition IS NOT NULL
OPEN _Cursor
FETCH NEXT FROM _Cursor INTO @current_proc, @current_text
WHILE @@FETCH_STATUS = 0
BEGIN
SET @i=0
lblAgain: SET @i=CHARINDEX('EXEC', @current_text, @i)
SET @j=CHARINDEX(CHAR(13), @current_text, @i)-@i
IF @j<0
SET @j=DATALENGTH(@current_text)-@i+1
IF @i>0
BEGIN
PRINT @current_proc
PRINT ' '+SUBSTRING(@current_text, @i, @j)
SET @i=@i+1
GOTO lblAgain
END
FETCH NEXT FROM _Cursor INTO @current_proc, @current_text
END
CLOSE _Cursor
DEALLOCATE _Cursor
GO
-------------------------
(Никита Горшков)
USE Lab_01
GO
CREATE PROCEDURE MetadataWorker
AS
DECLARE @exec_string varchar(40)
DECLARE [CURSOR] CURSOR
GLOBAL
FOR
SELECT SUBSTRING(sm.definition, CHARINDEX('EXEC',sm.definition, 0), 60)
FROM sys.sql_modules AS sm
JOIN sys.objects AS o ON sm.object_id = o.object_id
WHERE CHARINDEX('EXEC',sm.definition) <> 0 AND OBJECT_NAME(sm.object_id) <> 'MetadataWorker' AND o.type = 'P' AND SUBSTRING(sm.definition, CHARINDEX('EXEC',sm.definition, 0), 40)<>'';
OPEN [Cursor];
FETCH NEXT FROM [CURSOR] INTO @exec_string;
PRINT CONVERT(varchar, @exec_string);
CLOSE [Cursor];
DEALLOCATE [Cursor];
GO
EXEC MetadataWorker
GO
DROP procedure dbo.MetadataWorker
Вариант 09
Создать хранимую процедуру с выходным параметром, которая уничтожает все SQL DDL триггеры (триггеры типа 'TR') в текущей базе данных. Выходной параметр возвращает количество уничтоженных триггеров. Созданную хранимую процедуру протестировать.
Рекомендации.
Для уничтожения триггера воспользоваться инструкцией DROP TRIGGER.
Системное представление sys.triggers содержит по одной строке для каждого объекта, являющегося триггером типа TR или TA. Имена триггеров DML существуют в пределах схемы и, следовательно, видимы в представлении sys.objects. Область существования имен триггеров DDL определяется родительской сущностью, поэтому эти имена видимы только в этом представлении. Столбцы parent_class и name однозначно идентифицируют триггер в базе данных.
USE dbFAS
GO
CREATE TRIGGER [asd]
ON DATABASE
FOR CREATE_TABLE
AS
PRINT 'You must disable Trigger "ddl" to drop trigger!';
--ROLLBACK;
GO
USE dbFAS
GO
IF OBJECT_ID ( N'drop_all_triggers' ) IS NOT NULL
DROP PROCEDURE drop_all_triggers
GO
CREATE PROCEDURE drop_all_triggers
AS
--DECLARE - При помощи этой инструкции можно объявлять переменные
--курсоров для использования в других инструкциях
DECLARE @sql NVARCHAR(MAX) = '';
DECLARE @name sysname;
DECLARE LILU CURSOR
FOR
SELECT name FROM sys.triggers;
OPEN LILU;
FETCH NEXT FROM LILU INTO @name;
WHILE (@@FETCH_STATUS=0)
BEGIN
SELECT @sql = 'DROP TRIGGER ' + @name + ' ON DATABASE; ';
EXEC (@SQL);
FETCH NEXT FROM LILU INTO @name;
END;
CLOSE LILU;
DEALLOCATE LILU;
EXEC drop_all_triggers;
CREATE TABLE t(id int)
----------------------------
ProblemForExamSqlQuery17.Sql - Test
-- ********************************************************************************
-- Создаем демонстрационную базу данных с тремя DML-триггерами двумя DDL-триггерами
-- ********************************************************************************
USE master
GO
IF DB_ID (N'sample_db') IS NOT NULL DROP DATABASE sample_db
GO
CREATE DATABASE sample_db
GO
USE sample_db
GO
IF OBJECT_ID('dbo.sample_table', 'U') IS NOT NULL DROP TABLE dbo.sample_table
GO
CREATE TABLE dbo.sample_table
(
c1 int NOT NULL IDENTITY(1,1),
c2 char(10) NULL,
c3 datetime NULL
CONSTRAINT PK_sample_table PRIMARY KEY (c1)
)
GO
INSERT INTO dbo.sample_table (c2, c3)
VALUES ('qwe', GETDATE()), ('asd', GETDATE()), ('zxc', GETDATE())
GO
IF OBJECT_ID('dbo.insert_trigger', 'TR') IS NOT NULL DROP TRIGGER dbo.insert_trigger
GO
CREATE TRIGGER dbo.insert_trigger ON dbo.sample_table AFTER INSERT
AS
PRINT 'INSERT TRIGGER'
GO
IF OBJECT_ID('dbo.update_trigger','TR') IS NOT NULL DROP TRIGGER dbo.update_trigger
GO
CREATE TRIGGER dbo.update_trigger ON dbo.sample_table AFTER UPDATE
AS
PRINT 'UPDATE TRIGGER'
GO
IF OBJECT_ID('dbo.delete_trigger','TR') IS NOT NULL DROP TRIGGER dbo.delete_trigger
GO
CREATE TRIGGER dbo.delete_trigger ON dbo.sample_table AFTER DELETE
AS
PRINT 'DELETE TRIGGER'
GO
IF EXISTS (SELECT * FROM sys.triggers WHERE parent_class = 0 AND name = 'trigger_table')
DROP TRIGGER trigger_table ON DATABASE
GO
CREATE TRIGGER trigger_table ON DATABASE FOR DROP_TABLE, ALTER_TABLE
AS
PRINT 'You must disable "trigger_table" to drop or alter tables!'
ROLLBACK;
GO
IF EXISTS (SELECT * FROM sys.triggers WHERE parent_class = 0 AND name = 'trigger_index')
DROP TRIGGER trigger_index ON DATABASE
GO
CREATE TRIGGER trigger_index ON DATABASE FOR DROP_INDEX, ALTER_INDEX
AS
PRINT 'You must disable "trigger_index" to drop or alter indexes!'
ROLLBACK;
GO
ProblemForExamSqlQuery17.Sql - Solution
-- ********************************************************************************
-- Создаем хранимую процедуру удаления всех SQL DML триггеров
-- ********************************************************************************
IF OBJECT_ID('dbo.drop_all_SQL_DDL_triggers', 'P') IS NOT NULL
DROP PROCEDURE dbo.drop_all_SQL_DDL_triggers
GO
CREATE PROCEDURE drop_all_SQL_DDL_triggers @cnt int OUTPUT
AS
BEGIN
DECLARE @trigger_name nvarchar(255), @SqlString nvarchar(1000)
SET @cnt = 0
IF NOT EXISTS (SELECT * FROM sys.triggers WHERE parent_class = 0)
RETURN
DECLARE trigger_list CURSOR FORWARD_ONLY STATIC FOR
SELECT name FROM sys.triggers WHERE parent_class = 0
OPEN trigger_list
FETCH NEXT FROM trigger_list into @trigger_name
WHILE @@FETCH_STATUS = 0
BEGIN
SET @cnt = @cnt+1
SET @SqlString = N'DROP TRIGGER '+@trigger_name+N' ON DATABASE';
EXEC (@SqlString)
FETCH NEXT FROM trigger_list into @trigger_name
END
CLOSE trigger_list
DEALLOCATE trigger_list
END
GO
-- ********************************************************************************
-- Проверяем хранимую процедуру удаления всех SQL DDL триггеров
-- ********************************************************************************
SELECT * FROM sys.triggers
GO
DECLARE @cnt int
EXEC drop_all_SQL_DDL_triggers @cnt OUTPUT
SELECT @cnt
EXEC drop_all_SQL_DDL_triggers @cnt OUTPUT
SELECT @cnt
GO
SELECT * FROM sys.triggers
GO
Вариант 10
Создать хранимую процедуру с выходным параметром, которая уничтожает все SQL DML триггеры (триггеры типа 'TR') в текущей базе данных. Выходной параметр возвращает количество уничтоженных триггеров. Созданную хранимую процедуру протестировать.
Рекомендации.
Для уничтожения триггера воспользоваться инструкцией DROP TRIGGER.
Системное представление sys.triggers содержит по одной строке для каждого объекта, являющегося триггером типа TR или TA. Имена триггеров DML существуют в пределах схемы и, следовательно, видимы в представлении sys.objects. Область существования имен триггеров DDL определяется родительской сущностью, поэтому эти имена видимы только в этом представлении. Столбцы parent_class и name однозначно идентифицируют триггер в базе данных.
----------------
(Антон)
CREATE PROC dbo.DropDMLTrigger @count INT OUTPUT
AS
DECLARE @t1 varchar(1000)
DECLARE @sqlstr varchar(4000)
DECLARE st SCROLL CURSOR FOR
SELECT s1 = ob.name FROM sys.objects AS ob WHERE OBJECTPROPERTY(ob.object_id, N'IsTrigger') = 1 AND ob.type = 'TR'
OPEN st
FETCH NEXT FROM st INTO @t1
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @sqlstr = 'DROP TRIGGER ' + @t1
EXEC (@sqlstr)
SET @count = @count + 1
FETCH NEXT FROM st INTO @t1
END
CLOSE st
DEALLOCATE st
GO
DECLARE @num INT = 0
EXEC dbo.DropDMLTrigger @num OUTPUT
SELECT @num
GO
--------------------