Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
BD_Otvety_na_zadachi_SQL_1.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
82.86 Кб
Скачать

Базы данных. Задачи на модули SQL

Вариант 01

Создать хранимую процедуру без параметров, в которой для экземпляра SQL Server создаются резервные копии всех пользовательских баз данных. Имя файла резервной копии должно состоять из имени базы данных и даты создания резервной копии, разделенных символом нижнего подчеркивания. Дата создания резервной копии должна быть представлена в формате YYYYDDMM. Созданную хранимую процедуру протестировать.

Рекомендации.

  1. Для создания резервной копии базы данных воспользоваться инструкцией BACKUP DATABASE, имеющей следующий формат:

BACKUP DATABASE имя_базы_данных TO DISK = полная_спецификация_файла_резервной_копии

  1. Имена баз данных экземпляра 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'. Созданную хранимую процедуру протестировать.

Рекомендации.

  1. Для уничтожения таблицы воспользоваться инструкцией DROP TABLE.

  2. Информацию о таблицах базы данных можно извлечь из системного представления 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 встречается строка, задаваемая параметром процедуры. Созданную хранимую процедуру протестировать.

Рекомендации.

  1. Информацию об объектах базы данных можно извлечь из системного представления sys.objects.

  2. Информацию о модулях базы данных можно извлечь из системного представления 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

Создать хранимую процедуру с двумя входными параметрами – имя базы данных и имя таблицы, которая выводит сведения об индексах указанной таблицы в указанной базе данных. Созданную хранимую процедуру протестировать.

Рекомендации.

  1. Сведения об индексах указанной таблицы в указанной базе данных можно получить с помощью динамической административной функции sys.dm_db_index_physical_stats, принимающей пять параметров:

    1. Идентификатор базы данных - можно получить с помощью функции метаданных DB_ID.

    2. Идентификатор таблицы - можно получить с помощью функции метаданных OBJECT_ID.

    3. Для прочих параметров можно указать значения NULL.

  2. Если имя базы данных задано неверно, напечатать сообщение 'Invalid database'.

  3. Если имя таблицы задано неверно, напечатать сообщение '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

Создать хранимую процедуру с входным параметром – имя таблицы, которая удаляет дубликаты записей из указанной таблицы в текущей базе данных. Созданную хранимую процедуру протестировать.

Рекомендации.

  1. Если имя таблицы задано неверно, напечатать сообщение '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' в текущей базе данных. Созданную хранимую процедуру протестировать.

Рекомендации.

  1. Информацию о таблицах базы данных можно извлечь из системного представления sys.objects.

  2. Для перестроения индексов для таблицы в указанной базе данных воспользоваться командой DBCC DBREINDEX.

  3. Использовать значение коэффициента заполнения для индекса, указанное при создании индекса.

--------------------

/*

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'. Созданную хранимую процедуру протестировать.

Рекомендации.

  1. Информацию о таблицах базы данных можно извлечь из системного представления sys.objects.

  2. Чтобы обновить статистику оптимизации запросов для таблицы в указанной базе данных, необходимо воспользоваться инструкцией 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', которая выполняет командную строку — строку символов или один из следующих модулей: хранимую процедуру или скалярную пользовательскую функцию. Созданную хранимую процедуру протестировать.

Рекомендации.

  1. Информацию об объектах базы данных можно извлечь из системного представления sys.objects.

  2. Информацию о модулях базы данных можно извлечь из системного представления sys.sql_modules.

  3. Для работы со строками воспользоваться следующими функциями:

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') в текущей базе данных. Выходной параметр возвращает количество уничтоженных триггеров. Созданную хранимую процедуру протестировать.

Рекомендации.

  1. Для уничтожения триггера воспользоваться инструкцией DROP TRIGGER.

  2. Системное представление 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') в текущей базе данных. Выходной параметр возвращает количество уничтоженных триггеров. Созданную хранимую процедуру протестировать.

Рекомендации.

  1. Для уничтожения триггера воспользоваться инструкцией DROP TRIGGER.

  2. Системное представление 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

--------------------

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