powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Помогите написать запрос для обезличивания данных.
14 сообщений из 14, страница 1 из 1
Помогите написать запрос для обезличивания данных.
    #40081154
Фотография Badger
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добрый день.

Поставили задачу в MS SQL Server 2014 и обезличить все фамилии и паспортные данные в базе данных во всех таблицах. Структуры и описания базы нет, все таблицы с кучей полей (по 100 и более) с миллионами записей.
Код: sql
1.
select count(*) from INFORMATION_SCHEMA.TABLES

выдала -> 4619
Код: sql
1.
SELECT OBJECT_NAME(id) table_name, rows FROM sysindexes WHERE indid IN (0,1) and rows > 100000000 order by rows desc 

выдала -> 1748 строк

Помогите придумать SQL код, чтобы моя обезличка, не заняла весь период моего испытательного строка, - в лучшем случае.
...
Рейтинг: 0 / 0
Помогите написать запрос для обезличивания данных.
    #40081163
uaggster
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ну... попробуйте поискать во всех char, nchar, varchar, nvarchar, text, ntext, xml - имена (нужно искать "Александр" и "Татьяна"), номера паспортов (что-нибудь типа '[0-9][0-9][ ][0-9][0-9]' как серия), номера телефонов (11 цифр), и т.д.
Выбрать все подозрительные поля, посмотреть, что в них глазами...
...
Рейтинг: 0 / 0
Помогите написать запрос для обезличивания данных.
    #40081164
Фотография a_voronin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Лучше воспользуйтесь HASHBYTES md5 строка -> MD5 -> строка (если влезет)

https://docs.microsoft.com/ru-ru/sql/t-sql/functions/hashbytes-transact-sql?view=sql-server-ver15
...
Рейтинг: 0 / 0
Помогите написать запрос для обезличивания данных.
    #40081175
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a_voronin
Лучше воспользуйтесь HASHBYTES md5 строка -> MD5 -> строка (если влезет)

https://docs.microsoft.com/ru-ru/sql/t-sql/functions/hashbytes-transact-sql?view=sql-server-ver15


Радикально-черный цвет средство.

Код: sql
1.
Drop database ИмяРек;
...
Рейтинг: 0 / 0
Помогите написать запрос для обезличивания данных.
    #40081188
godsql
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
a_voronin
Лучше воспользуйтесь HASHBYTES md5 строка -> MD5 -> строка (если влезет)

https://docs.microsoft.com/ru-ru/sql/t-sql/functions/hashbytes-transact-sql?view=sql-server-ver15

Какое это имеет отношение к обезличиванию?
...
Рейтинг: 0 / 0
Помогите написать запрос для обезличивания данных.
    #40081190
Фотография Badger
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uaggster, Таблицу пользователей и отдельную таблицу с паспортными данными я нашел, уже проще. А дальше нужно пробежать с этими данными по все таблицам. Это уже сложнее
...
Рейтинг: 0 / 0
Помогите написать запрос для обезличивания данных.
    #40081195
godsql
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Badger,

попробуйте пойти от противного. Эта же база используется для какого-то/каких-то приложения/ний?
Соответственно, люди знают, где вводят эти персональные данные.
Соответственно, эти места локализовать и просмотреть таблицы, которые используются.
А дальше уже начинать корректную замену реальных данных на данные из словаря для обезличивания.

В одно лицо это как раз и займет испытательный срок :)
Правда, тут есть разброс от "недели" до "пары-тройки месяцев".
Все зависит от схемы базы
...
Рейтинг: 0 / 0
Помогите написать запрос для обезличивания данных.
    #40081203
Фотография a_voronin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Badger
uaggster, Таблицу пользователей и отдельную таблицу с паспортными данными я нашел, уже проще. А дальше нужно пробежать с этими данными по все таблицам. Это уже сложнее



Есть такая функция

Код: sql
1.
  EXEC sp_MSforeachtable 'SELECT ''?'' TableName, Count(1) NumRecords FROM ?'
...
Рейтинг: 0 / 0
Помогите написать запрос для обезличивания данных.
    #40081210
Фотография Badger
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a_voronin, Oooo! Какая пушка. Сейчас будем ее испытывать. Спасибо

Код: sql
1.
sp_msForEachTable



Sp_msforeachtable – это недокументированная функция, которая «проходит» по всем таблицам в БД и выполняет запрос, подставляя вместо ‘?’ имя текущей таблицы. Так же существует похожая функция sp_msforeachdb, работающая на уровне баз данных.

Известно несколько проблем с этой недокументированной функцией, например, использование спецсимволов в именах объектов. Т.е. если имя таблицы или базы данных содержит знак ‘-‘, хранимая процедура, листинг которой ниже, завершится с ошибкой.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
CREATE TABLE #rowcount
    ( Tablename VARCHAR(128) ,
      Rowcnt INT ); 

EXEC sp_MSforeachtable 'insert into #rowcount select ''?'', count(*) from ?' 

SELECT  *
FROM    #rowcount
ORDER BY Tablename ,
        Rowcnt; 

DROP TABLE #rowcount;
...
Рейтинг: 0 / 0
Помогите написать запрос для обезличивания данных.
    #40081245
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Badger
uaggster, Таблицу пользователей и отдельную таблицу с паспортными данными я нашел, уже проще. А дальше нужно пробежать с этими данными по все таблицам. Это уже сложнее


Этот стажер не прошел стажировку.
Можно расходиться.
...
Рейтинг: 0 / 0
Помогите написать запрос для обезличивания данных.
    #40081260
Посетитель
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aleks222,

мож у них серия+номер паспорта в качестве внешнего ключа используются)))
...
Рейтинг: 0 / 0
Помогите написать запрос для обезличивания данных.
    #40081312
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дурная задача вроде затачивания якоря. Запросите список таблиц, в которых хранятся персональные данные. Они могут находиться и в несвязанных таблицах и вообще, где угодно.
...
Рейтинг: 0 / 0
Помогите написать запрос для обезличивания данных.
    #40084845
Фотография Badger
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Чтобы не терять процедуру, которая оказалась никому ненужной, я решил ее опубликовать и порадовать флеймеров
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_depersonalization]') AND type in (N'P', N'PC'))	DROP PROCEDURE [dbo].[sp_depersonalization]
GO

CREATE PROCEDURE dbo.sp_depersonalization
(
	@user_name		varchar (255)	= NULL
)
as
begin
/*----------------------------------------------------------------------
--
--    Процедура :	dbo.sp_depersonalization
--						
--   Аргументы :	user_name	- Строка для команды EXEC, которая выдаст одну колонку - список данных (Фамилия Имя --Отчество пользователей по слову в строек) которых нужно обезличить
--					table_name  - таблица или набор таблиц через пробел которые нужно обезличить, если оставить NULL скрипт будет искать по всем таблицам базы.
--
--     Описание :	Формирует список (таблица + поле + персональные данные Replace на другие персональные данные) для их обезличивания. Разрабатывалось для Microsoft SQL Server 2014 
--
-- Используется :	для ручного запуска 
--
--  Возвращает :	список UPDATE(ов) для формироваться подмены данных по всей базе (в разумных пределах иначе процедура будет работать оооочень долго)
--						
--     История :    	07.07.2021 - badger
--
--Пример вызова:    
--
					declare @exec_pole	nvarchar (4000)

					SET @user_name = 
							'select distinct       /* Фамилии  */  s_U_FamilyName	from table_user tu with(nolock) where IIF (Rtrim (s_U_FamilyName)	= '''', NULL, s_U_FamilyName)	IS NOT NULL and Len (s_U_FamilyName)> 1	and ASCII (tu.s_U_FamilyName)	> 191
							union select distinct  /* Имена    */  s_U_FirstName	from table_user tu with(nolock) where IIF (Rtrim (s_U_FirstName)	= '''', NULL, s_U_FirstName)	IS NOT NULL and Len (s_U_FirstName)	> 1	and ASCII (tu.s_U_FirstName)	> 191
							union select distinct  /* Отчества */  s_U_LastName	from table_user tu with(nolock) where IIF (Rtrim (s_U_LastName)		= '''', NULL, s_U_LastName)		IS NOT NULL and Len (s_U_LastName)	> 1	and ASCII (tu.s_U_LastName)		> 191'


					EXEC dbo.sp_depersonalization  @user_name, "select 'Иванов' union select 'обезличен' 
--
--
-------------------------------------------------------------------------'*/

	declare @start			datetime
	declare @id_identity	int
	declare @row_count		int
	declare @pole_1			nvarchar (4000)	
	declare @exec_pole		nvarchar (4000)
	set @start = getdate()

	/* эта часть необязательная, но если хочется запускать из скрипта, то это нужно */
	if object_id('tempdb..#table_1', 'u') is not null drop table #table_1
	if object_id('tempdb..#table_2', 'u') is not null drop table #table_2
	if object_id('tempdb..#table_3', 'u') is not null drop table #table_3
	if object_id('tempdb..#table_4', 'u') is not null drop table #table_4
	if object_id('tempdb..#table_5', 'u') is not null drop table #table_5
	if object_id('tempdb..##table_6','u') is not null drop table ##table_6
	if object_id('tempdb..##table_7','u') is not null drop table ##table_7
	if object_id('tempdb..#table_8', 'u') is not null drop table #table_8

	/* таблица для создания списка фамилий, имен, отчеств */
	create table #table_1 (	id_identity	int identity,	name_1 VARCHAR(128) primary key,	name_2 VARCHAR(128) NULL) 

	/* таблица для создания подменяемого списка клиентов */
	create table #table_2 (	id_identity	int identity,	name_1 VARCHAR(128) NULL,			name_2 VARCHAR(128) NULL) 

	/* таблица для всех полей базы данных */
	create table #table_3 
	(				
					id_identity					int					identity,	
					TABLE_SCHEMA				varchar	(255)		NULL,
					table_name					varchar	(255)		NULL,
					COLUMN_NAME					varchar	(255)		NULL,
					DATA_TYPE					varchar	(255)		NULL,
					CHARACTER_MAXIMUM_LENGTH	int				NULL
	)

	/* таблица сбора всех данных по всем таблицам полям и подменяемым данным */
	create table #table_4 
	( 
					id_identity					int					identity, 
					pole_1						nvarchar (4000)		null
	) 


	/* таблица сбора всех данных по всем таблицам полям и подменяемым данным */
	create table #table_5 
	( 
					id_identity					int					identity, 
					pole_1						nvarchar (4000)		null
	) 

	create table ##table_6
	(				
					id_identity					int					identity,	
					TABLE_SCHEMA				varchar	(255)		NULL,
					table_name					varchar	(255)		NULL,
					COLUMN_NAME					varchar	(255)		NULL,
					name_1						varchar	(255)		NULL,
					name_2						varchar	(255)		NULL,
					DATA_TYPE					varchar	(255)		NULL,
					DATA_SIZE					varchar	(255)		NULL
	)

	create table ##table_7
	(				
					id_identity					int					identity,	
					TABLE_SCHEMA				varchar	(255)		NULL,
					table_name					varchar	(255)		NULL,
					COLUMN_NAME					varchar	(255)		NULL,
					name_1						varchar	(255)		NULL,
					name_2						varchar	(255)		NULL,
					DATA_TYPE					varchar	(255)		NULL,
					DATA_SIZE					varchar	(255)		NULL
	)

	create table #table_8
	( 
					id_identity					int					identity, 
					pole_1						nvarchar (4000)		null
	) 

	/* делаем тоже самое, что  на три строки выше, только из входящих параметров */
	SET @exec_pole = 'insert into  #table_1 (name_1) '
	SET @exec_pole = @exec_pole + @user_name

	EXEC SP_EXECUTESQL @exec_pole


	/* самый простой способ сделать второй список пользователей в другой последовательности */
	insert into  #table_2 (name_2)
	select name_1 from #table_1 order by substring (name_1, 2,3) desc, id_identity desc

	/* проставляем второй столбец пользователей */
	UPDATE t1 SET name_2 = t2.name_2 FROM #table_1 t1, #table_2 t2 WHERE t2.id_identity = t1.id_identity and NOT t1.name_1 = t2.name_2

	/* проходимся еще раз, так как может остаться одно пустое поле */
	UPDATE t1 SET name_2 = t2.name_2 FROM #table_1 t1, #table_2 t2 WHERE t1.name_2 IS NULL	 and NOT t1.name_1 = t2.name_2

	/* получаем список всех таблиц и их полей в которых гипотетически могут встречаться Фамилия, Имя, Отчество */
	insert into #table_3
	(
			TABLE_SCHEMA,
			table_name,
			COLUMN_NAME,
			DATA_TYPE,
			CHARACTER_MAXIMUM_LENGTH
	)
	select 
			it.TABLE_SCHEMA,  
			it.table_name, 
			ic.COLUMN_NAME, 
			ic.DATA_TYPE, 
			ic.CHARACTER_MAXIMUM_LENGTH
	from 
			INFORMATION_SCHEMA.COLUMNS ic,
			INFORMATION_SCHEMA.TABLES it
	where	
			ic.TABLE_NAME	= it.TABLE_NAME and
			ic.CHARACTER_MAXIMUM_LENGTH IS NOT NULL 
	order by 
			it.table_name,
			ic.DATA_TYPE 

	/* типы полей, где могут быть персональные данные */
--	SELECT DISTINCT DATA_TYPE FROM #table_3 

	/* Собираем строку формата:	
	схема_таблицы		пример:	dbo
	таблица				пример:	t_User
	колонка				пример:	s_U_LastName
	подменяемое_имя		пример:	Харитон
	на_что_меняем		пример:	Иванович
	тип_данных			пример:	varchar
	размер				пример:	40	*/


	/* теперь  список всех таблиц и всех их полей, перемножаем на всех пользователей, которых мы планируем поменять в XML полях */
	/*****************************************************/
	/* кусочек связанный с XML полями */
	insert into #table_4 ( pole_1) 
	select 
			'INSERT INTO ##table_6 ( TABLE_SCHEMA, table_name, COLUMN_NAME, name_1, name_2, DATA_TYPE ) 
			SELECT ''' + 
			t3.TABLE_SCHEMA + ''', ''' + 
			t3.table_name	+ ''', ''' + 
			t3.COLUMN_NAME	+ ''', ''' + 
			t1.name_1		+ ''', ''' + 
			t1.name_2		+ ''', ''' + 
			t3.DATA_TYPE    + '''  
			FROM ' + t3.TABLE_SCHEMA + '.' + t3.table_name + ' with(nolock) WHERE '  
			+ t3.COLUMN_NAME + '.exist(N''//*[contains(., ' + '"' + t1.name_1 + '"'+ ')]'') = 1 having Count (*) > 0'
	from 
			#table_3 t3,
			#table_1 t1
	where 
			t3.CHARACTER_MAXIMUM_LENGTH < 0 
			and t3.DATA_TYPE	= 'xml'	
			and t3.table_name   = 'table_name' /* здесь можно проставить список таблиц с XML полями по которым нужно сделать обезличку. Если это поле закомментировать, то процедура будет пытаться обезличить всю базу XML полей, но думаю ресурсов tempdb для этого не хватит */

	/* теперь список всех таблиц и всех их полей, перемножаем на всех пользователей, которых мы планируем поменять в ТЕКСТОВЫХ полях */
	insert into #table_5 ( pole_1) 
	select 
			'INSERT INTO ##table_7 ( TABLE_SCHEMA, table_name, COLUMN_NAME, name_1, name_2, DATA_TYPE, DATA_SIZE) 
			SELECT DISTINCT ''' + 
			t3.TABLE_SCHEMA		+ ''', ''' + 
			t3.table_name		+ ''', ''' + 
			t3.COLUMN_NAME		+ ''', ''' + 
			t1.name_1			+ ''', ''' + 
			t1.name_2			+ ''', ''' + 
			t3.DATA_TYPE		+ ''', ''' + 
			Convert (varchar (100), t3.CHARACTER_MAXIMUM_LENGTH) + 
			''' FROM ' + t3.TABLE_SCHEMA + '.' + t3.table_name + ' with(nolock)  
			WHERE '  + 'PATINDEX(''%' + t1.name_1 + '%'', ' + t3.COLUMN_NAME + ' ) > 0 and ' + t3.COLUMN_NAME + ' IS NOT NULL'
	from 
			#table_3 t3,
			#table_1 t1
	where 
			t3.CHARACTER_MAXIMUM_LENGTH > 0 
			and t3.DATA_TYPE  in ( 'text', 'ntext', 'nvarchar', 'varchar', 'char', 'nchar')
			and t3.table_name  = 'table_name' /* здесь можно проставить список таблиц с ТЕКСТОВЫМИ полями по которым нужно сделать обезличку. Если это поле закомментировать, то процедура будет пытаться обезличить всю базу, но думаю ресурсов tempdb для этого не хватит */

	/* получаем количество колонок по всем таблицам умноженные на количество заменяемых имен */
	select	@row_count		= Count (*) from #table_4
--	set		@row_count		= 1000 /* если нужно поставить ограничения для отладки */
	set		@id_identity	= 1
	set		@pole_1			= ''

	/* Цикл для формирования строк формата:	
	схема_таблицы		пример:	dbo
	таблица				пример:	t_User
	колонка				пример:	s_U_LastName
	подменяемое_имя		пример:	Харитон
	на_что_меняем		пример:	Иванович
	тип_данных			пример:	varchar
	размер				пример:	40	*/

	while	@id_identity <= @row_count
	begin

		if Len (@pole_1) = 0 
		begin
			select @pole_1 = pole_1  from	#table_4 where	id_identity = @id_identity
		end
		else
		begin
			select
					@pole_1 = @pole_1 + Substring (pole_1, CharIndex ('SELECT', pole_1), Len (pole_1))
			  from
					#table_4
			 where
					id_identity = @id_identity
		end

		/* объединяем запросы в максимальную строку через UNION чтобы реже вызывать процедуру SP_EXECUTESQL */
		if datalength (@pole_1) < 3400 and @id_identity < @row_count
		begin
			SELECT @pole_1 = @pole_1 + Char (13) + Char (10) +  ' UNION ' + Char (13) + Char (10) 
		end
		else
		begin
			/* исполняемый запрос о наличие персональных данных в этом поле */
			if datalength (@pole_1) > 3900 
			begin
				select datalength (@pole_1), @pole_1
			end 

			EXEC SP_EXECUTESQL @pole_1
			set @pole_1 = ''
		end

		set @id_identity = @id_identity + 1

	end

	/* получаем количество колонок по всем таблицам умноженные на количество заменяемых имен */
	select	@row_count		= Count (*) from #table_5
--	set		@row_count		= 1000 /* если нужно поставить ограничения для отладки */
	set		@id_identity	= 1
	set		@pole_1			= ''

	/* Цикл для формирования строк формата:	
	схема_таблицы		пример:	dbo
	таблица				пример:	t_User
	колонка				пример:	s_U_LastName
	подменяемое_имя		пример:	Харитон
	на_что_меняем		пример:	Иванович
	тип_данных			пример:	varchar
	размер				пример:	40	*/
	while	@id_identity <= @row_count
	begin

		if Len (@pole_1) = 0 
		begin
			select @pole_1 = pole_1  from	#table_5 where	id_identity = @id_identity
		end
		else
		begin
			select
					@pole_1 = @pole_1 + Substring (pole_1, CharIndex ('SELECT', pole_1), Len (pole_1))
			  from
					#table_5
			 where
					id_identity = @id_identity
		end

		/* объединяем запросы в максимальную строку через UNION чтобы реже вызывать процедуру SP_EXECUTESQL */
		if datalength (@pole_1) < 3400 and @id_identity < @row_count
		begin
			SELECT @pole_1 = @pole_1 + Char (13) + Char (10) +  ' UNION ' + Char (13) + Char (10) 
		end
		else
		begin
			/* исполняемый запрос о наличие персональных данных в этом поле */
--			select @pole_1 
			EXEC SP_EXECUTESQL @pole_1
			set @pole_1 = ''
		end
		
		set @id_identity = @id_identity + 1

	end

	/* список XML таблиц и их полей и все их данные, которые мы заменяем для обезлички */
	insert into #table_8 ( pole_1) 
	select 
			'UPDATE ' + TABLE_SCHEMA  + '.' + table_name  + 
			  ' SET ' +  column_name + ' = Convert ( xml,  replace ( Convert (varchar (max), ' + COLUMN_NAME + '), ''' + name_1 + ''', ''' + name_2 + ''' )) 
			  WHERE ' + column_name + '.exist(N''//*[contains(., ' + '"' + name_1 + '"'+ ')]'') = 1'
	  from 
			##table_6

																
	/* список ТЕКСТОВЫХ таблиц и их полей и все их данные, которые мы заменяем для обезлички */
	insert into #table_8 ( pole_1) 
	select 
			'UPDATE ' + TABLE_SCHEMA  + '.' + table_name  + 
			  ' SET ' +  column_name + ' = replace ( ' + COLUMN_NAME + ', ''' + name_1 + ''', ''' + name_2 + ''' ) 
			  WHERE '  + 'PATINDEX(''%' + name_1 + '%'', ' + COLUMN_NAME + ' ) > 0 and ' + COLUMN_NAME + ' IS NOT NULL'
	  from 
			##table_7

	/* начальные установки */
	select	@row_count		= Count (*) from #table_8
--	set		@row_count		= 100 /* если нужно поставить ограничения для отладки */
	set		@id_identity	= 1
	set		@pole_1			= ''

	/* Цикл финального обезличивания таблиц лежит здесь */
	while	@id_identity <= @row_count
	begin
		select @pole_1 = pole_1  from	#table_8 where	id_identity = @id_identity

		/* запуск обезличивания */	
--		select @pole_1  /* для отладки по каждой строке */
--		EXEC SP_EXECUTESQL @pole_1
		
		set @id_identity = @id_identity + 1
	end 

	/* список UPDATE(ов) для тестирования */ 
	/* реальное обновление данных в строке 'EXEC SP_EXECUTESQL @pole_1' - на шесть сточек выше, сейчас закомментировано */
	select top 100 pole_1  from	#table_8 

	select @row_count as 'количество записей в #table_8', datediff(ss, @start, getdate()) as 'время заполнения #table_8 в секундах' 

	drop table #table_1
	drop table #table_2
	drop table #table_3
	drop table #table_4
	drop table #table_5
	drop table ##table_6
	drop table ##table_7
	drop table #table_8
end 



Модератор: Используйте тег "spoiler" для таких портянок
...
Рейтинг: 0 / 0
Помогите написать запрос для обезличивания данных.
    #40120582
Фотография Badger
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Чтобы не потерять код, нужно им делиться. :)
Последняя версия тут.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
513.
514.
515.
516.
517.
518.
519.
520.
521.
522.
523.
524.
525.
526.
527.
528.
529.
530.
531.
532.
533.
534.
535.
536.
537.
538.
539.
540.
541.
542.
543.
544.
545.
546.
547.
548.
549.
550.
551.
552.
553.
554.
555.
556.
557.
558.
559.
560.
561.
562.
563.
564.
565.
566.
567.
568.
569.
570.
571.
572.
573.
574.
575.
576.
577.
578.
579.
580.
581.
582.
583.
584.
585.
586.
587.
588.
589.
590.
591.
592.
593.
594.
595.
596.
597.
598.
599.
600.
601.
602.
603.
604.
605.
606.
607.
608.
609.
610.
611.
612.
613.
614.
615.
616.
617.
618.
619.
620.
621.
622.
623.
624.
625.
626.
627.
628.
629.
630.
631.
632.
633.
634.
635.
636.
637.
638.
639.
640.
641.
642.
643.
644.
645.
646.
647.
648.
649.
650.
651.
652.
653.
654.
655.
656.
657.
658.
659.
660.
661.
662.
663.
664.
665.
666.
667.
668.
669.
670.
671.
672.
673.
674.
675.
676.
677.
678.
679.
680.
681.
682.
683.
684.
685.
686.
687.
688.
689.
690.
691.
692.
693.
694.
695.
696.
697.
698.
699.
700.
701.
702.
703.
704.
705.
706.
707.
708.
709.
710.
711.
712.
713.
714.
715.
716.
717.
718.
719.
720.
721.
722.
723.
724.
725.
726.
727.
728.
729.
730.
731.
732.
733.
734.
735.
736.
737.
738.
739.
740.
741.
742.
743.
744.
745.
746.
747.
748.
749.
750.
751.
752.
753.
754.
755.
756.
757.
758.
759.
760.
761.
762.
763.
764.
765.
766.
767.
768.
769.
770.
771.
772.
773.
774.
775.
776.
777.
778.
779.
780.
781.
782.
783.
784.
785.
786.
787.
788.
789.
790.
791.
792.
793.
794.
795.
796.
797.
798.
799.
800.
801.
802.
803.
804.
805.
806.
807.
808.
809.
810.
811.
812.
813.
814.
815.
816.
817.
818.
819.
820.
821.
822.
823.
824.
825.
826.
827.
828.
829.
830.
831.
832.
833.
834.
835.
836.
837.
838.
839.
840.
841.
842.
843.
844.
845.
846.
847.
848.
849.
850.
851.
852.
853.
854.
855.
856.
857.
858.
859.
860.
861.
862.
863.
864.
865.
866.
867.
868.
869.
870.
871.
872.
873.
874.
875.
876.
877.
878.
879.
880.
881.
882.
883.
884.
885.
886.
887.
888.
889.
890.
891.
892.
893.
894.
895.
896.
897.
898.
899.
900.
901.
902.
903.
904.
905.
906.
907.
908.
909.
910.
911.
912.
913.
914.
915.
916.
917.
918.
919.
920.
921.
922.
923.
924.
925.
926.
927.
928.
929.
930.
931.
932.
933.
934.
935.
936.
937.
938.
939.
940.
941.
942.
943.
944.
945.
946.
947.
948.
949.
950.
951.
952.
953.
954.
955.
956.
957.
958.
959.
960.
961.
962.
963.
964.
965.
966.
967.
968.
969.
970.
971.
972.
973.
974.
975.
976.
977.
978.
979.
980.
981.
982.
983.
984.
985.
986.
987.
988.
989.
990.
991.
992.
993.
994.
995.
996.
997.
998.
999.
1000.
1001.
1002.
1003.
1004.
1005.
1006.
1007.
1008.
1009.
1010.
1011.
1012.
1013.
1014.
1015.
1016.
1017.
1018.
1019.
1020.
1021.
1022.
1023.
1024.
1025.
1026.
1027.
1028.
1029.
1030.
1031.
1032.
1033.
1034.
1035.
1036.
1037.
1038.
1039.
1040.
1041.
1042.
1043.
1044.
1045.
1046.
1047.
1048.
1049.
1050.
1051.
1052.
1053.
1054.
1055.
1056.
1057.
1058.
1059.
1060.
1061.
1062.
1063.
1064.
1065.
1066.
1067.
1068.
1069.
1070.
1071.
1072.
1073.
1074.
1075.
1076.
1077.
1078.
1079.
1080.
1081.
1082.
1083.
1084.
1085.
1086.
1087.
1088.
1089.
1090.
1091.
1092.
1093.
1094.
1095.
1096.
1097.
1098.
1099.
1100.
1101.
1102.
1103.
1104.
1105.
1106.
1107.
1108.
1109.
1110.
1111.
1112.
1113.
1114.
1115.
1116.
1117.
1118.
1119.
1120.
1121.
1122.
1123.
1124.
1125.
1126.
1127.
1128.
1129.
1130.
1131.
1132.
1133.
1134.
1135.
1136.
1137.
1138.
1139.
1140.
1141.
1142.
1143.
1144.
1145.
1146.
1147.
1148.
1149.
1150.
1151.
1152.
1153.
1154.
1155.
1156.
1157.
1158.
1159.
1160.
1161.
1162.
1163.
1164.
1165.
1166.
1167.
1168.
1169.
1170.
1171.
1172.
1173.
1174.
1175.
1176.
1177.
1178.
1179.
1180.
1181.
1182.
1183.
1184.
1185.
1186.
1187.
1188.
1189.
1190.
1191.
1192.
1193.
1194.
1195.
1196.
1197.
1198.
1199.
1200.
1201.
1202.
1203.
1204.
1205.
1206.
1207.
1208.
1209.
1210.
1211.
1212.
1213.
1214.
1215.
1216.
1217.
1218.
1219.
1220.
1221.
1222.
1223.
1224.
1225.
1226.
1227.
1228.
1229.
1230.
1231.
1232.
1233.
1234.
1235.
1236.
1237.
1238.
1239.
1240.
1241.
1242.
1243.
1244.
1245.
1246.
1247.
1248.
1249.
1250.
1251.
1252.
1253.
1254.
1255.
1256.
1257.
1258.
1259.
1260.
1261.
1262.
1263.
1264.
1265.
1266.
1267.
1268.
1269.
1270.
1271.
1272.
1273.
1274.
1275.
1276.
1277.
1278.
1279.
1280.
1281.
1282.
1283.
1284.
1285.
1286.
1287.
1288.
1289.
1290.
1291.
1292.
1293.
1294.
1295.
1296.
1297.
1298.
1299.
1300.
1301.
1302.
1303.
1304.
1305.
1306.
1307.
1308.
1309.
1310.
1311.
1312.
1313.
1314.
1315.
1316.
1317.
1318.
1319.
1320.
1321.
1322.
1323.
1324.
1325.
1326.
1327.
1328.
1329.
1330.
1331.
1332.
1333.
1334.
1335.
1336.
1337.
1338.
1339.
1340.
1341.
1342.
1343.
1344.
1345.
1346.
1347.
1348.
1349.
1350.
1351.
1352.
1353.
1354.
1355.
1356.
1357.
1358.
1359.
1360.
1361.
1362.
1363.
1364.
1365.
1366.
1367.
1368.
1369.
1370.
1371.
1372.
1373.
1374.
1375.
1376.
1377.
1378.
1379.
1380.
1381.
1382.
1383.
1384.
1385.
1386.
1387.
1388.
1389.
1390.
1391.
1392.
1393.
1394.
1395.
1396.
1397.
1398.
1399.
1400.
1401.
1402.
1403.
1404.
1405.
1406.
1407.
1408.
1409.
1410.
1411.
1412.
1413.
1414.
1415.
1416.
1417.
1418.
1419.
1420.
1421.
1422.
1423.
1424.
1425.
1426.
1427.
1428.
1429.
1430.
1431.
1432.
1433.
1434.
1435.
1436.
1437.
1438.
1439.
1440.
1441.
1442.
1443.
1444.
1445.
1446.
1447.
1448.
1449.
1450.
1451.
1452.
1453.
1454.
1455.
1456.
1457.
1458.
1459.
1460.
1461.
1462.
1463.
1464.
1465.
1466.
1467.
1468.
1469.
1470.
1471.
1472.
1473.
1474.
1475.
1476.
1477.
1478.
1479.
1480.
1481.
1482.
1483.
1484.
1485.
1486.
1487.
1488.
1489.
1490.
1491.
1492.
1493.
1494.
1495.
1496.
1497.
1498.
1499.
1500.
1501.
1502.
1503.
1504.
1505.
1506.
1507.
1508.
1509.
1510.
1511.
1512.
1513.
1514.
1515.
1516.
1517.
1518.
1519.
1520.
1521.
1522.
1523.
1524.
1525.
1526.
1527.
1528.
1529.
1530.
1531.
1532.
1533.
1534.
1535.
1536.
1537.
1538.
1539.
1540.
1541.
1542.
1543.
1544.
1545.
1546.
1547.
1548.
1549.
1550.
1551.
1552.
1553.
1554.
1555.
1556.
1557.
1558.
1559.
1560.
1561.
1562.
1563.
1564.
1565.
1566.
1567.
1568.
1569.
1570.
1571.
1572.
1573.
1574.
1575.
1576.
1577.
1578.
1579.
1580.
1581.
1582.
1583.
1584.
1585.
1586.
1587.
1588.
1589.
1590.
1591.
1592.
1593.
1594.
1595.
1596.
1597.
1598.
1599.
1600.
1601.
1602.
1603.
1604.
1605.
1606.
1607.
1608.
1609.
1610.
1611.
1612.
1613.
1614.
1615.
1616.
1617.
1618.
1619.
1620.
1621.
1622.
1623.
1624.
1625.
1626.
1627.
1628.
1629.
1630.
1631.
1632.
1633.
1634.
1635.
1636.
1637.
1638.
1639.
1640.
1641.
1642.
1643.
1644.
1645.
1646.
1647.
1648.
1649.
1650.
1651.
1652.
1653.
1654.
1655.
1656.
1657.
1658.
1659.
1660.
1661.
1662.
1663.
1664.
1665.
1666.
1667.
1668.
1669.
1670.
1671.
1672.
1673.
1674.
1675.
1676.
1677.
1678.
1679.
1680.
1681.
1682.
1683.
1684.
1685.
1686.
1687.
1688.
1689.
1690.
1691.
1692.
1693.
1694.
1695.
1696.
1697.
1698.
1699.
1700.
1701.
1702.
1703.
1704.
1705.
1706.
1707.
1708.
1709.
1710.
1711.
1712.
1713.
1714.
1715.
1716.
1717.
1718.
1719.
1720.
1721.
1722.
1723.
1724.
1725.
1726.
1727.
1728.
1729.
1730.
1731.
1732.
1733.
1734.
1735.
1736.
1737.
1738.
1739.
1740.
1741.
1742.
1743.
1744.
1745.
1746.
1747.
1748.
1749.
1750.
1751.
1752.
1753.
1754.
1755.
1756.
1757.
1758.
1759.
1760.
1761.
1762.
1763.
1764.
1765.
1766.
1767.
1768.
1769.
1770.
1771.
1772.
1773.
1774.
1775.
1776.
1777.
1778.
1779.
1780.
CREATE PROCEDURE [sp_depersonalization]
as
begin
/*----------------------------------------------------------------------
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_depersonalization]') AND type in (N'P', N'PC'))	DROP PROCEDURE [dbo].[sp_depersonalization]
GO
--
--    Процедура :	dbo.sp_depersonalization
--						
--   Аргументы :	нет
--
--     Описание :	Формирует список (таблица + поле + персональные данные Replace на другие персональные данные) для их обезличивания. Разрабатывалось для Microsoft SQL Server 2014 
--
-- Используется :	для ручного запуска 
--
--  Возвращает :	список UPDATE(ов) для формироваться подмены данных по всей базе (в разумных пределах иначе процедура будет работать очень долго)
--						
--      История :   07.07.2021 - Андрей Львович Антонов, создал
--
-- Пример вызова:   можно запускать несколько экземпляров процедуры для более быстрой проработки данных  
--					EXEC dbo.sp_depersonalization  
--					в данной примере данные берутся из таблицы t_user 
--					из трех полей 
--					t_user.s_U_FamilyName
--					t_user.s_U_FirstName
--					t_user.s_U_LastName
--					эти поля являются Ф.И.О, которые будут перемешаны. Но по логике лучше обрабатывать отдельно сначала Фамилии потом Имена и отдельно Отчества

Анализ (промежуточных) результатов:
					select top 100 * from w_getdate  (nolock) order by date_time desc		/* трассировка по времени */
					select top 100 * from w_getdate  (nolock) where num > 1 order by sec desc				/* максимальное временя  */
					select Count (*) from w_depersonalization_table_8  (nolock) /* сколько найдено таблица + поле которые имеют персональные данные */
					select Count (*) from w_depersonalization_pole_1   (nolock) /* сколько всего проверено запросов */
					select Count (*) from w_depersonalization_pole_2   (nolock) /* проверено */ 
					select Count (*) from w_depersonalization_pole_3   (nolock) /* проверено */ 
					select Count (*) from w_depersonalization_table_12  (nolock) /* нужно проверить */ 
					select * from w_depersonalization_table_12 where pole_5 not in (select pole_5 from w_depersonalization_table_12 where occupied > 2 )
					select pole_1, Count (*) from w_depersonalization_pole_3   (nolock) GROUP BY pole_1 HAVING Count (pole_1) > 1 /* проверка на наличие запросов которые попали дважды (должно быть пусто) */
					select pole_1, Count (*) from w_depersonalization_pole_1   (nolock) GROUP BY pole_1 HAVING Count (pole_1) > 1 /* проверка на наличие запросов которые попали дважды (должно быть пусто) */

					select object_name(id) table_name, rows from sysindexes   (nolock) where indid in (0,1) and rows > 100000000 /* таблицы где записей более 100 миллионов */

					/* статистика обработки записей по часам для второго этапа */
					select top 1000 datediff(dd, '19000101', diff) [Дни], datepart(hh, diff) [Часы], Count (*) [Обработано] from (select (SELECT Max (date_time) FROM w_getdate (nolock) where num = 28) - date_time as diff from w_getdate (nolock) where num = 28) r group by datediff(dd, '19000101', diff), datepart(hh, diff) order by [Дни] asc, [Часы] asc

					/* статистика обработки записей по минутам для второго этапа */
					select datediff(dd, '19000101', diff) [Дни], datepart(hh, diff) [Часы], datepart(mi, diff) [Минуты],  Count (*) [Обработано] from (select  (SELECT Max (date_time) FROM w_getdate (nolock)  where num = 28) - date_time diff from w_getdate (nolock)  where num = 28) r group by datediff(dd, '19000101', diff), datepart(hh, diff), datepart(mi, diff)  order by [Дни] desc, [Часы] desc, [Минуты] desc

					/* статистика обработки записей по дням */
					select datediff(dd, '19000101', diff) [Дни], Count (*) [Обработано] from (select  (SELECT Max (date_time) FROM w_getdate (nolock) where num = 28) - date_time diff from w_getdate (nolock) where num = 28) r group by datediff(dd, '19000101', diff)   order by [Дни] desc 

					/* поиск по всем процедурам */
					 select distinct  so.xtype, so.name from syscomments sc (nolock) inner join sysobjects so (nolock) on sc.id = so.id where sc.text like '%текст для поиска%' order by so.xtype, so.name
					
					/* Заполненность tempdb */
					select convert(numeric(10,2),round(sum(data_pages)*8/1024.,2)) as user_object_reserved_MB
					from tempdb.sys.allocation_units a
					inner join tempdb.sys.partitions b on a.container_id = b.partition_id
					inner join tempdb.sys.objects c on b.object_id = c.object_id
					go

-------------------------------------------------------------------------*/


		declare @pole_1						nvarchar (4000)		/* Поиск полей для обезличивания */
		declare @pole_2						nvarchar (1000)		/* Создание индекса */
		declare @pole_3						nvarchar (1000)		/* Удаление индекса */
		declare @pole_4						nvarchar (100)		/* "таблица + поле" - идентификатор индекса */
		declare @pole_5						nvarchar (100)		/* "таблица + поле + имя" - идентификатор запроса */
		declare @pole_6						nvarchar (100)		/* поисковое слово по слогам длиной - @int_num */
		declare @pole_11					nvarchar (4000)	
		declare @pole_22					nvarchar (1000)	
		declare @pole_33					nvarchar (1000)	
		declare @pole_44					nvarchar (100)	
		declare @pole_55					nvarchar (100)	
		declare @exec_pole					nvarchar (4000)
		declare @DATA_TYPE					varchar	(255)
		declare @CHARACTER_MAXIMUM_LENGTH	int
		declare @occupied_01				int
		declare @occupied_02				int = 2
		declare @id_identity				int
		declare @id_identity_old			int
		declare @row_count					int
		declare @occupied_10				int
		declare @occupied_11				int
		declare @occupied_12				int
		declare @occupied_13				int
		declare @occupied_14				int
		declare @occupied_15				int
		declare @occupied_16				int
		declare @row_table_13				int
		declare @RowCount_table_10			int
		declare @RowCount_table_13			int
		declare @user_name					varchar(50)		/* select @user_name = user_name() */
		select  @user_name = user_name()
--	if user_name() = @user_name DELETE FROM w_getdate 

		if object_id('w_getdate', 'u') is null 
		BEGIN
			/* это стационарная таблица в которой накапливаются поля и значения которые были обработаны для varchar полей */
			
			CREATE TABLE w_getdate
			(
						num							int					NULL,
						spid						int					NULL,
						date_time					datetime			NULL,
						sec							int					NULL,
						descr						varchar	(255)		NULL
			)
			CREATE INDEX isx_w_getdate_date_time_spid ON  w_getdate (date_time, spid)

		END

		if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time, sec, descr) SELECT 1, @@spid, GetDate (), IsNull(DATEDIFF(ms, Max (date_time), GetDate ()), 0), 'запуск процедуры' FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid))   WHERE spid = @@spid

		/* скрипт расставляет приоритеты поиска для каждого слова поделив по три символа */
		declare @int_num int
		/* ищем таблицы где есть персональные данные при минимальном количестве запросов */
	/*************************************************************************************************************************************************/
		set @int_num = 4		-- Переменная отвечающая насколько символов в слоге делить Ф.И.О. пользователей, чтобы сократить число запросов, где нужно искать персональные данные.
		-- Можно сделать по 2 -(57 / 303 183), можно по 3 - (276 / 1 468 044),  можно по 4 - (575 / 3 058 425), можно по 5 - (841 / 4 473 279), можно по 6- (880/4 680 720),  
		-- из 1722 персональных имени на нашей базе которые создадут 9 159 318  запросов только по varchar полям, а еще есть  XML которые работают еще медленнее. 
		-- Это дает возможность найти таблицы, где есть персональные данные, но при УМЕНЬШЕНИЕ цифры @int_num чаще попадают таблицы в которых нет персональных данных и так как 
		-- это случайные совпадения, это увеличивает время конечного поиска по всем найденным ТАБЛИЦАМ умножены ПОЛЯ умножены 1722 уникальных имени, которые будет делаться позже.
	/**********************************************************************************************************************************************************/

		if object_id('tempdb..#table_01', N'U')		is not null drop table #table_01
		if object_id('tempdb..#table_02', N'U')		is not null drop table #table_02
		if object_id('tempdb..#table_name_1', N'U') is NOT null drop table #table_name_1
		if object_id('tempdb..#table_11',N'u')		is not null drop table #table_11
		if object_id('tempdb..#table_12',N'u')		is not null drop table #table_12
		if object_id('tempdb..#table_pre_12',N'u')	is not null drop table #table_pre_12
		if object_id('tempdb..#table_pre_13',N'u')	is not null drop table #table_pre_13
		if object_id('tempdb..#table_pre_14',N'u')	is not null drop table #table_pre_14 
		if object_id('tempdb..#table_pre_15',N'u')	is not null drop table #table_pre_15
		if object_id('tempdb..#table_03_VAR',N'u')	is not null drop table #table_03_VAR
--		if object_id('tempdb..##table_10',N'u')		is not null drop table ##table_10

		/* таблица для создания списка фамилий, имен, отчеств */
		create table #table_01 (	id_identity	int identity,	name_1 VARCHAR(128) primary key,	name_2 VARCHAR(128) NULL) 

		/* таблица для создания подменяемого списка клиентов */
		create table #table_02 (	id_identity	int identity,	name_1 VARCHAR(128) NULL,			name_2 VARCHAR(128) NULL) 

		/* список всех таблиц базы и их размер  */
		create table #table_name_1 (	id_identity	int identity,	table_name VARCHAR(128) primary key, rows_1 int null, rows_2 int null) 
		create table #table_pre_12 ( name_1 varchar (10) null, row_1 int null )
		create table #table_pre_13 ( name_1 varchar (10) null )
		/* таблица для всех VARCHAR полей базы данных */
		create table #table_03_VAR 
		(				
						id_identity					int					identity,	
						TABLE_SCHEMA				varchar	(255)		NULL,
						table_name					varchar	(255)		NULL,
						COLUMN_NAME					varchar	(255)		NULL,
						DATA_TYPE					varchar	(255)		NULL,
						CHARACTER_MAXIMUM_LENGTH	int					NULL
		)

		/* таблица куда собираются все используемые сочетания Ф.И.О. по 3 или 4 символа в зависимости от @int_num переменной. */
		/* name_2 только ПЕРВОЕ ИМЯ!!! Таких (похожих) имен может быть много. */
		create table #table_pre_15 
		(	
						name_1		varchar (10)		null, 
						name_2		varchar (128)		null
		)

		/* таблица для создания весов слогов по три четыре или пять символов */
		create table #table_pre_14 (	
						id_identity					int					identity,	
						pole_name					VARCHAR(128)		primary key, 
						row_1						int					null ,
						name_1						varchar (10)		null,
						n_01						varchar (10)		null,
						n_02						varchar (10)		null,
						n_03						varchar (10)		null,
						n_04						varchar (10)		null,
						n_05						varchar (10)		null,
						n_06						varchar (10)		null,
						n_07						varchar (10)		null,
						n_08						varchar (10)		null,
						n_09						varchar (10)		null,
						n_10						varchar (10)		null,
						n_11						varchar (10)		null,
						n_12						varchar (10)		null,
						n_13						varchar (10)		null,
						n_14						varchar (10)		null,
						n_15						varchar (10)		null,
						n_16						varchar (10)		null,
						n_17						varchar (10)		null,
						n_18						varchar (10)		null,
						n_19						varchar (10)		null,
						n_20						varchar (10)		null 
		)

		create table #table_12
		(				
						id_identity					int					identity,	
						TABLE_SCHEMA				varchar	(255)		NULL,
						table_name					varchar	(255)		NULL,
						COLUMN_NAME					varchar	(255)		NULL,
						name_1						varchar	(255)		NULL,
						name_2						varchar	(255)		NULL,
						DATA_TYPE					varchar	(255)		NULL,
						CHARACTER_MAXIMUM_LENGTH	int					NULL,
						pole_5						nvarchar (100)		NULL /* "таблица + поле + имя" - идентификатор запроса */
		)

		if object_id('tempdb..##table_8',N'u')		is null 
		BEGIN
			create table ##table_8
			(				
							id_identity					int					identity,	
							TABLE_SCHEMA				varchar	(255)		NULL,
							table_name					varchar	(255)		NULL,
							COLUMN_NAME					varchar	(255)		NULL,
							name_1						varchar	(255)		NULL,
							name_2						varchar	(255)		NULL,
							DATA_TYPE					varchar	(255)		NULL,
							DATA_SIZE					varchar	(255)		NULL,
							pole_5						nvarchar (100)		NULL /* "таблица + поле + имя" - идентификатор запроса */
			)
		END

		if object_id('tempdb..##table_10',N'u')		is null 
		BEGIN
			create table ##table_10
			(				
							id_identity					int					identity,	
							TABLE_SCHEMA				varchar	(255)		NULL,
							table_name					varchar	(255)		NULL,
							COLUMN_NAME					varchar	(255)		NULL,
							name_1						varchar	(255)		NULL,
							name_2						varchar	(255)		NULL,
							DATA_TYPE					varchar	(255)		NULL,
							DATA_SIZE					varchar	(255)		NULL,
							pole_5						nvarchar (100)		NULL /* "таблица + поле + имя" - идентификатор запроса */
			)
		END

		if object_id('w_depersonalization_pole_1', 'u') is null 
		BEGIN
			/* это стационарная таблица в которой накапливаются 'таблицы + поля + значения' которые были обработаны на 2-м этапе */
			CREATE TABLE w_depersonalization_pole_1
			(
						id_identity					int					identity,	
						pole_1						nvarchar (4000)		NULL,
						DATA_TYPE					varchar	(255)		NULL,
						CHARACTER_MAXIMUM_LENGTH	int					NULL
			)
		END

		if object_id('w_depersonalization_pole_3', 'u') is null 
		BEGIN
			/* это стационарная таблица в которой накапливаются 'таблицы + поля + значения' которые были обработаны на 1-м этапе */
			CREATE TABLE w_depersonalization_pole_3
			(
						id_identity					int					identity,	
						pole_1						nvarchar (100)		NULL,
						pole_6						varchar (10)		NULL, /* поисковое слово по слогам длиной - @int_num */
						DATA_TYPE					varchar	(255)		NULL,
						CHARACTER_MAXIMUM_LENGTH	int					NULL
			)

			CREATE INDEX isx_w_depersonalization_pole_3_pole_1 ON  w_depersonalization_pole_3 (pole_1)
		END


		if object_id('w_depersonalization_table_8', 'u') is null 
		BEGIN
			/* это стационарная таблица в которой накапливаются 'таблицы + поля + значения' КОТОРЫЕ НУЖНО ОБЕЗЛИЧИТЬ  */
			CREATE TABLE w_depersonalization_table_8
			(
						id_identity					int					NULL,	
						TABLE_SCHEMA				varchar	(255)		NULL,
						table_name					varchar	(255)		NULL,
						COLUMN_NAME					varchar	(255)		NULL,
						name_1						varchar	(255)		NULL,
						name_2						varchar	(255)		NULL,
						DATA_TYPE					varchar	(255)		NULL,
						DATA_SIZE					varchar	(255)		NULL,
						pole_5						nvarchar (100)		NULL /* "таблица + поле + имя" - идентификатор запроса */
			)
		END

		if object_id('w_depersonalization_table_9', 'u') is null 
		BEGIN
			/* это стационарная таблица в которой накапливаются 'таблицы + поля + значения' КОТОРЫЕ НУЖНО ОБЕЗЛИЧИТЬ  */
			CREATE TABLE w_depersonalization_table_9
			(
						id_identity					int					NULL,	
						TABLE_SCHEMA				varchar	(255)		NULL,
						table_name					varchar	(255)		NULL,
						COLUMN_NAME					varchar	(255)		NULL,
						name_1						varchar	(255)		NULL,
						name_2						varchar	(255)		NULL,
						DATA_TYPE					varchar	(255)		NULL,
						DATA_SIZE					varchar	(255)		NULL
			)
		END

		if object_id('w_depersonalization_table_10', 'u') is null 
		BEGIN
			/* это стационарная таблица в которой накапливаются 'таблицы + поля + значения' КОТОРЫЕ НУЖНО ОБЕЗЛИЧИТЬ  */
			CREATE TABLE w_depersonalization_table_10
			( 
							id_identity					int					identity, 
							pole_1						nvarchar (4000)		null,
							pole_5						nvarchar (100)		NULL, /* "таблица + поле + имя" - идентификатор запроса */
							occupied					int					null  /* 1 - если занята другой процедурой или 2- запись уже отработана */
			) 
		END

		if object_id('w_depersonalization_table_12', 'u') is null 
		BEGIN
			
			/* таблица сбора всех данных по всем таблицам полям и подменяемым данным */
			create table w_depersonalization_table_12
			( 
							id_identity					int					identity, 
							pole_1						nvarchar (4000)		null, /* Поиск полей для обезличивания */
							pole_2						nvarchar (1000)		null, /* Создание индекса */
							pole_3						nvarchar (1000)		null, /* Удаление индекса */
							pole_4						nvarchar (100)		null, /* "таблица + поле" - идентификатор индекса */
							pole_5						nvarchar (100)		null, /* "таблица + поле + имя" - идентификатор запроса */
							pole_6						nvarchar (100)		null, /* поисковое слово по слогам длиной - @int_num */
							DATA_TYPE					varchar  (255)		null, /* тип данных */
							CHARACTER_MAXIMUM_LENGTH	int					null, /* размер поля */
							occupied					int					null  /* 1 - если занята другой процедурой или 2- запись уже отработана */
			) 
			CREATE INDEX isx_w_depersonalization_table_12_occupied ON  w_depersonalization_table_12 (pole_5, occupied)
			
		END

		if object_id('w_depersonalization_table_13', 'u') is null 
		BEGIN
			
			/* таблица сбора всех данных по всем таблицам полям и подменяемым данным INSERT INTO ##table_8 ( TABLE_SCHEMA, table_name, COLUMN_NAME, name_1, name_2, DATA_TYPE, DATA_SIZE, pole_5)   т */
			create table w_depersonalization_table_13
			( 
							id_identity					int					identity, 
							pole_1						nvarchar (4000)		null, /* Поиск полей для обезличивания */
							pole_2						nvarchar (1000)		null, /* Создание индекса */
							pole_3						nvarchar (1000)		null, /* Удаление индекса */
							pole_4						nvarchar (100)		null, /* "таблица + поле" - идентификатор индекса */
							pole_5						nvarchar (100)		null, /* "таблица + поле + имя" - идентификатор запроса */
							pole_6						nvarchar (100)		null, /* поисковое слово по слогам длиной - @int_num */
							DATA_TYPE					varchar  (255)		null, /* тип данных */
							CHARACTER_MAXIMUM_LENGTH	int					null, /* размер поля */
							occupied					int					null  /* 1 - если занята другой процедурой или 2- запись уже отработана */
			) 
			CREATE INDEX isx_w_depersonalization_table_13_occupied ON  w_depersonalization_table_13 (pole_5, occupied)
			

		END

		/*****************************************************************************************************************************************************************************************************************************/
		/* в этой таблице лежат конечные UPDATE базы данных для обезличивания, если они есть, то создавать их ненужно, но обрабатываться будут только записи w_depersonalization_table_10.occupied = 0 остальные считаются в работе  */	
		/*****************************************************************************************************************************************************************************************************************************/
		SELECT @RowCount_table_10 = Count (*) FROM w_depersonalization_table_10 /* (TABLOCK)*/  (NOLOCK)

		/* если конечных UPDATE(ов) нет, то создаем их */
		IF @RowCount_table_10 = 0 
		BEGIN 

					/**********************************/
					/* НАЧАЛО транзакции по TABLOCKX  */
					BEGIN TRAN a1
					/*************************************/

					/* Получаем количество записей которые можно обработать */
					--	        SELECT Count (*) FROM  w_depersonalization_table_12   (NOLOCK)
					--	        SELECT top 100 * FROM  w_depersonalization_table_12   (NOLOCK)
					/* Блокируем таблицу до конца транзакции */
					SELECT @occupied_12 = Count (*) FROM w_depersonalization_table_12 (TABLOCKX) /*WHERE occupied < 2*/  /*  (NOLOCK)*/ 
					--	        SELECT Count (*) FROM w_depersonalization_table_12 WHERE occupied < 2 /* в работе */
					--	        SELECT * FROM w_depersonalization_table_12 WHERE occupied < 2 /* в работе */
		
					/* проверка на начало второго этапа в этой таблице лежат INSERT INTO ##table_8 ( TABLE_SCHEMA, table_name, COLUMN_NAME, name_1, name_2, DATA_TYPE, DATA_SIZE, pole_5)  */
					SELECT @occupied_15 = Count (*) FROM w_depersonalization_table_13 /*(TABLOCKX)*/   (NOLOCK)

					/* проверка на начало второго этапа */
					IF @occupied_15 > 0 
					BEGIN
						/* начался второй этап обработки, поэтому первый этап пропускаем */
						SET @occupied_12 = -1
					END 

					/* Проверка на наличие рабочих записей  */
					IF @occupied_12 = 0  /* блок BEGIN END работает если все записи обработаны */
					BEGIN
			--					if user_name() = @user_name DELETE FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid 
								if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 2, @@spid, GetDate (), IsNull (DATEDIFF(ms, Max (date_time), GetDate ()), 0), 'время начала работы первой процедуры' FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid
								/* удаляем не обработанные записи */
								DELETE FROM w_depersonalization_table_12   /* первый этап   */
								DELETE FROM w_depersonalization_table_13   /* второй этап  */

								/* обработано раньше */
								select	@row_count		= Count (*) from w_depersonalization_pole_3
								if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 3, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @row_count) + ' - обработано записей раньше'  FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

								/* список всех Ф.И.О. для получения слогов длинной  @int_num для предварительного сбора статистики - (в каких таблицах есть персональные данные) */
/*								insert into #table_pre_14 (pole_name)
								select distinct			/* Фамилии  */	s_U_FamilyName		from t_user tu (nolock) where IIF (Rtrim (s_U_FamilyName)	= '''', NULL, s_U_FamilyName)	IS NOT NULL and Len (s_U_FamilyName)> 1	and ASCII (tu.s_U_FamilyName)	> 191 and charindex (' ', s_U_FamilyName ) = 0	and Len (s_U_FamilyName)	> 1
								union select distinct	/* Имена    */  s_U_FirstName		from t_user tu (nolock) where IIF (Rtrim (s_U_FirstName)	= '''', NULL, s_U_FirstName)	IS NOT NULL and Len (s_U_FirstName)	> 1	and ASCII (tu.s_U_FirstName)	> 191 and charindex (' ', s_U_FirstName ) = 0	and Len (s_U_FirstName)		> 1
								union select distinct	/* Отчества */  s_U_LastName		from t_user tu (nolock) where IIF (Rtrim (s_U_LastName)		= '''', NULL, s_U_LastName)		IS NOT NULL and Len (s_U_LastName)	> 1	and ASCII (tu.s_U_LastName)		> 191 and charindex (' ', s_U_LastName ) = 0	and Len (s_U_LastName)		> 1
*/
								--select  from #table_pre_14 where charindex (' ', pole_name ) > 0

								SELECT @row_count = count (*) FROM #table_pre_14
								if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 4, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @row_count) + ' - список всех Ф.И.О.' FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

								/* получаем список всех таблиц базы данных и количество записей в каждой */
								insert into #table_name_1 (table_name, rows_1, rows_2) 	select object_name(id) table_name, rows, 0 from sysindexes where indid in (0,1) /*and rows > 100000000*/ order by table_name desc   /* таблицы где записей более 100 миллионов */

								/* получаем список всех таблиц и их полей в которых гипотетически могут встречаться Фамилия, Имя, Отчество */
								insert into #table_03_VAR
								(
										TABLE_SCHEMA,
										table_name,
										COLUMN_NAME,
										DATA_TYPE,
										CHARACTER_MAXIMUM_LENGTH
								)
								select 
										it.TABLE_SCHEMA,  
										it.table_name, 
										ic.COLUMN_NAME, 
										ic.DATA_TYPE, 
										ic.CHARACTER_MAXIMUM_LENGTH
								from 
										INFORMATION_SCHEMA.COLUMNS ic,
										INFORMATION_SCHEMA.TABLES  it,
										#table_name_1  tn /* убираем таблицы где нет записей */
								where	
										tn.rows_1			> 0							and /* убираем таблицы где нет записей */
										tn.TABLE_NAME		= it.TABLE_NAME				and 
										ic.TABLE_NAME		= it.TABLE_NAME				and
										ic.CHARACTER_MAXIMUM_LENGTH IS NOT NULL			and
										it.TABLE_TYPE		=  'BASE TABLE'				and  /* только таблицы иначе попадут VIEW */
										tn.table_name not like 'w_depersonalization%'	and /* убираем из поиска служебные таблицы этой процедуры */
										tn.table_name not like 'w_getdate%'					/* убираем из поиска служебные таблицы этой процедуры */
								order by 
										it.table_name,
										ic.DATA_TYPE 

								SELECT @row_count = count (*) FROM #table_03_VAR
								if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 5, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @row_count) + ' - список всех таблиц и их полей' FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

								/* разбиваем Ф.И.О. по слогам */
								UPDATE #table_pre_14 
								SET n_01 = SUBSTRING (pole_name, 1 , @int_num ),
									n_02 = SUBSTRING (pole_name, 2 , @int_num ),
									n_03 = SUBSTRING (pole_name, 3 , @int_num ),
									n_04 = SUBSTRING (pole_name, 4 , @int_num ),
									n_05 = SUBSTRING (pole_name, 5 , @int_num ),
									n_06 = SUBSTRING (pole_name, 6 , @int_num ),
									n_07 = SUBSTRING (pole_name, 7 , @int_num ),
									n_08 = SUBSTRING (pole_name, 8 , @int_num ),
									n_09 = SUBSTRING (pole_name, 9 , @int_num ),
									n_10 = SUBSTRING (pole_name, 10 , @int_num ),
									n_11 = SUBSTRING (pole_name, 11 , @int_num ),
									n_12 = SUBSTRING (pole_name, 12 , @int_num ),
									n_13 = SUBSTRING (pole_name, 13 , @int_num ),
									n_14 = SUBSTRING (pole_name, 14 , @int_num ),
									n_15 = SUBSTRING (pole_name, 15 , @int_num ),
									n_16 = SUBSTRING (pole_name, 16 , @int_num ),
									n_17 = SUBSTRING (pole_name, 17 , @int_num ),
									n_18 = SUBSTRING (pole_name, 18 , @int_num ),
									n_19 = SUBSTRING (pole_name, 19 , @int_num ),
									n_20 = SUBSTRING (pole_name, 20 , @int_num )

								/* складываем все слога в одну колонку  */
								insert #table_pre_13 (name_1) select n_01 from #table_pre_14 where len (n_01) = @int_num 
								insert #table_pre_13 (name_1) select n_02 from #table_pre_14 where len (n_02) = @int_num 
								insert #table_pre_13 (name_1) select n_03 from #table_pre_14 where len (n_03) = @int_num 
								insert #table_pre_13 (name_1) select n_04 from #table_pre_14 where len (n_04) = @int_num 
								insert #table_pre_13 (name_1) select n_05 from #table_pre_14 where len (n_05) = @int_num 
								insert #table_pre_13 (name_1) select n_06 from #table_pre_14 where len (n_06) = @int_num 
								insert #table_pre_13 (name_1) select n_07 from #table_pre_14 where len (n_07) = @int_num 
								insert #table_pre_13 (name_1) select n_08 from #table_pre_14 where len (n_08) = @int_num 
								insert #table_pre_13 (name_1) select n_09 from #table_pre_14 where len (n_09) = @int_num 
								insert #table_pre_13 (name_1) select n_10 from #table_pre_14 where len (n_10) = @int_num 
								insert #table_pre_13 (name_1) select n_11 from #table_pre_14 where len (n_11) = @int_num 
								insert #table_pre_13 (name_1) select n_12 from #table_pre_14 where len (n_12) = @int_num 
								insert #table_pre_13 (name_1) select n_13 from #table_pre_14 where len (n_13) = @int_num 
								insert #table_pre_13 (name_1) select n_14 from #table_pre_14 where len (n_14) = @int_num 
								insert #table_pre_13 (name_1) select n_15 from #table_pre_14 where len (n_15) = @int_num 
								insert #table_pre_13 (name_1) select n_16 from #table_pre_14 where len (n_16) = @int_num 
								insert #table_pre_13 (name_1) select n_17 from #table_pre_14 where len (n_17) = @int_num 
								insert #table_pre_13 (name_1) select n_18 from #table_pre_14 where len (n_18) = @int_num 
								insert #table_pre_13 (name_1) select n_19 from #table_pre_14 where len (n_19) = @int_num 
								insert #table_pre_13 (name_1) select n_20 from #table_pre_14 where len (n_20) = @int_num 

								/* Группируем слога, чтобы получить вес каждого слога */
								insert into #table_pre_12 (name_1, row_1)
								select name_1, count (*) from #table_pre_13 group by name_1 order by 2 desc

								/* Прописываем лучший вес каждому Ф.И.О */
								UPDATE
										#table_pre_14
								   SET
										name_1 = t2.name_1
								  FROM 
										#table_pre_12 t2
								 WHERE
										charindex (t2.name_1, #table_pre_14.pole_name ) > 0 and
										#table_pre_14.name_1 IS NULL

								/* Проставляем значение веса */
								UPDATE
										#table_pre_14
								   SET
										row_1 = t2.row_1
								  FROM 
										#table_pre_12 t2
								 WHERE
										#table_pre_14.name_1 = t2.name_1

								/* получаем список уникальные слов по три чиетыре или пять символов в зависимости от переменной @int_num */
								insert into #table_pre_15 (name_1)
								select distinct name_1 from #table_pre_14 where name_1 is not null 

								/* это наглядно видно здесь */
								--select top 10 * from #table_pre_14
								--select top 10 * from #table_pre_15

								/* Для просты работы со слогами проставляем полные их имя, но это только ПЕРВОЕ имя которое включает этот слог, их должно быть много! */
								UPDATE 
										#table_pre_15
								   SET 
										name_2 = p_14.pole_name
								  FROM
										#table_pre_14 p_14
								 WHERE
										p_14.name_1 = #table_pre_15.name_1

								/* количество слогов из Ф.И.О. */
								select	@row_count		= Count (*) from #table_pre_15
								if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 6, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @row_count) + ' количество слогов из Ф.И.О.' FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

								/* создаем скрипт поиска персональных данных ПО СЛОГАМ - (так как основное время уходи на поиск в тех таблицах, где совсем нет персональных данных, а ПО СЛОГАМ время сокращается в несколько раз) */
								/* в транзакции отрабатывает за 20.4343 секунд */
								INSERT INTO w_depersonalization_table_12 
								( 
												pole_1,						/* 1 Поиск полей с кириллицей */
												pole_2,						/* 2 Создание индекса */
												pole_3,						/* 3 резерв */
												pole_4,						/* 4 "таблица + поле" - идентификатор индекса */
												pole_5,						/* 5 "таблица + поле + имя" - идентификатор запроса */
												pole_6,					    /* 6 поисковое слово по слогам длиной - @int_num */
												DATA_TYPE,					/* 7 тип данных */
												CHARACTER_MAXIMUM_LENGTH,	/* 8 размер поля */
												occupied					/* 9 1 - если занята другой процедурой или 2 - запись уже отработана */
								) 
								SELECT 
										/* 1 Поиск полей с кириллицей [а-я] VARCHAR */
										'INSERT INTO ##table_10 ( TABLE_SCHEMA, table_name, COLUMN_NAME, DATA_TYPE, DATA_SIZE, pole_5) 
										SELECT DISTINCT ''' + 
										t3.TABLE_SCHEMA		+ ''', ''' + 
										t3.table_name		+ ''', ''' + 
										t3.COLUMN_NAME		+ ''', ''' + 
										t3.DATA_TYPE		+ ''', ''' + 
										Convert (varchar (100), t3.CHARACTER_MAXIMUM_LENGTH) + ''', ''' + 
										t3.TABLE_SCHEMA + '.'+ t3.table_name + '.' + t3.COLUMN_NAME + '.' + p5.name_2 + /* прописываем Ф.И.О. */ ''' 
										FROM ' + t3.TABLE_SCHEMA + '.' + t3.table_name + '  ( nolock )
										WHERE '  + 'PATINDEX(''%[а-я]%'', ' + t3.COLUMN_NAME + ' ) > 0 and ' + t3.COLUMN_NAME + ' IS NOT NULL' as pole_1 /* ищем кириллицу */
										, 
										/* 2 Поиск полей ПО СЛОГАМ длиной - @int_num */
										'INSERT INTO ##table_10 ( TABLE_SCHEMA, table_name, COLUMN_NAME, DATA_TYPE, DATA_SIZE, pole_5) 
										SELECT DISTINCT ''' + 
										t3.TABLE_SCHEMA		+ ''', ''' + 
										t3.table_name		+ ''', ''' + 
										t3.COLUMN_NAME		+ ''', ''' + 
										t3.DATA_TYPE		+ ''', ''' + 
										Convert (varchar (100), t3.CHARACTER_MAXIMUM_LENGTH) + ''', ''' + 
										t3.TABLE_SCHEMA + '.'+ t3.table_name + '.' + t3.COLUMN_NAME + '.' + p5.name_2 + /* прописываем Ф.И.О. */ '''		
										FROM ' + t3.TABLE_SCHEMA + '.' + t3.table_name + '  ( nolock )
										WHERE '  + 'PATINDEX(''%' + p5.name_1 +  '%'', ' + t3.COLUMN_NAME + ' ) > 0 and ' + t3.COLUMN_NAME + ' IS NOT NULL' as pole_1 /* ищем слог */
										,
										/* 3 резерв */
										'if INDEXPROPERTY (object_id (''' + t3.TABLE_SCHEMA + '.'+ t3.table_name + '''),  ''ids_'+ t3.table_name + '_' + t3.COLUMN_NAME + ''', ''IndexID'') > 0     DROP   INDEX ids_' +  t3.table_name + '_' + t3.COLUMN_NAME + ' ON ' + t3.TABLE_SCHEMA + '.' + t3.table_name
										,
										/* 4 "таблица + поле" - идентификатор индекса */
										t3.TABLE_SCHEMA + '.'+ t3.table_name + '.' + t3.COLUMN_NAME,					/* 4 "таблица + поле" - идентификатор индекса */
										t3.TABLE_SCHEMA + '.'+ t3.table_name + '.' + t3.COLUMN_NAME + '.' + p5.name_2,	/* 5 "таблица + поле + имя" как идентификатор поля */
										p5.name_1,																		/* 6 поисковое слово по слогам длиной - @int_num */
										t3.DATA_TYPE,																	/* 7 ип данных */
										t3.CHARACTER_MAXIMUM_LENGTH,													/* 8 размер поля */
										0 as occupied																	/* 9 1 - если занята другой процедурой или 2- запись уже отработана или 3 обрабатывается повторно */
								from 
										#table_03_VAR t3,
										#table_pre_15 p5
								where 
										t3.CHARACTER_MAXIMUM_LENGTH > 29 /* считаем что в поля менее 29 символов имен быть недолжно */ 
										and t3.DATA_TYPE  in ( 'text', 'ntext', 'nvarchar', 'varchar', 'char', 'nchar') 
							UNION
								select 
										/* 1 Поиск полей с кириллицей [а-я] XML */
										'INSERT INTO ##table_10 ( TABLE_SCHEMA, table_name, COLUMN_NAME, DATA_TYPE, DATA_SIZE, pole_5) 
										SELECT ''' + 
										t3.TABLE_SCHEMA		+ ''', ''' + 
										t3.table_name		+ ''', ''' + 
										t3.COLUMN_NAME		+ ''', ''' + 
										t3.DATA_TYPE		+ ''', ''' + 
										Convert (varchar (100), t3.CHARACTER_MAXIMUM_LENGTH) + ''', ''' + 
										t3.TABLE_SCHEMA + '.'+ t3.table_name + '.' + t3.COLUMN_NAME + '.' + p5.name_2 + ''' 
										FROM ' + t3.TABLE_SCHEMA + '.' + t3.table_name + ' (nolock) WHERE '  
										+ 'cast (' + t3.COLUMN_NAME + Space (1) + 'as nvarchar (max)) like ''%[А-я]%'' having Count (*) > 0'
										,
										/* 2 Поиск полей ПО СЛОГАМ длиной - @int_num */
										'INSERT INTO ##table_10 ( TABLE_SCHEMA, table_name, COLUMN_NAME, DATA_TYPE, DATA_SIZE, pole_5) 
										SELECT ''' + 
										t3.TABLE_SCHEMA		+ ''', ''' + 
										t3.table_name		+ ''', ''' + 
										t3.COLUMN_NAME		+ ''', ''' + 
										t3.DATA_TYPE		+ ''', ''' + 
										Convert (varchar (100), t3.CHARACTER_MAXIMUM_LENGTH) + ''', ''' + 
										t3.TABLE_SCHEMA + '.'+ t3.table_name + '.' + t3.COLUMN_NAME + '.' + p5.name_2 + ''' 
										FROM ' + t3.TABLE_SCHEMA + '.' + t3.table_name + ' (nolock) WHERE '  
										+ t3.COLUMN_NAME + '.exist(N''//*[contains(., ' + '"' + p5.name_2 + '"'+ ')]'') = 1 having Count (*) > 0'
										,
										/* 3 резерв */
										'if INDEXPROPERTY (object_id (''' + t3.TABLE_SCHEMA + '.'+ t3.table_name + '''),  ''ids_'+ t3.table_name + '_' + t3.COLUMN_NAME + ''', ''IndexID'') > 0     DROP   INDEX ids_' +  t3.table_name + '_' + t3.COLUMN_NAME + ' ON ' + t3.TABLE_SCHEMA + '.' + t3.table_name
										,
										t3.TABLE_SCHEMA + '.'+ t3.table_name + '.' + t3.COLUMN_NAME,					/* 4 "таблица + поле" - идентификатор индекса */
										t3.TABLE_SCHEMA + '.'+ t3.table_name + '.' + t3.COLUMN_NAME + '.' + p5.name_2,	/* 5 "таблица + поле + имя" как идентификатор поля */
										p5.name_1,																		/* 6 поисковое слово по слогам длиной - @int_num */
										t3.DATA_TYPE,																	/* 7 тип данных */
										t3.CHARACTER_MAXIMUM_LENGTH,													/* 8 размер поля */
										0 as occupied																	/* 9 1 - если занята другой процедурой или 2- запись уже отработана или 3 обрабатывается повторно */
								from 
										#table_03_VAR t3,
										#table_pre_15 p5
								where 
										t3.CHARACTER_MAXIMUM_LENGTH < 0 
										and t3.DATA_TYPE	= 'xml'	
				--			ORDER BY 
				--						t3.TABLE_SCHEMA,  t3.table_name,  t3.COLUMN_NAME, p5.name_1

									select	@row_count		= Count (*) from w_depersonalization_table_12 
									if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 7, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @row_count) + ' всего нужно обработать'  FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid
--goto err
						

									/* убираем поля которые уже обработаны в транзакции. DELETE отрабатывает за 35.9593 секунд, при удалении 2 190 750 записей (всех) */
									DELETE 
											p12 /* здесь лежат все гипотетические запросы */
									  FROM 
											w_depersonalization_table_12	p12 with (index (isx_w_depersonalization_table_12_occupied)), /* здесь лежат все гипотетические запросы */
											w_depersonalization_pole_3		p3	with (index (isx_w_depersonalization_pole_3_pole_1))     /* здесь лежат все обработанные запросы */
									 WHERE 
											p12.pole_5 = p3.pole_1

									/* осталось обработать  */
									select	@row_count		= Count (*) from w_depersonalization_table_12
									if @row_count = 0 
									begin
										/* вставляем одну запись, чтобы другие процедуры после окончания транзакции не пошли по этому пути */
										INSERT INTO w_depersonalization_table_12 (occupied) VALUES (@occupied_02)
									end

									/* всего нужно обработать  */
									if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 8, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @row_count) + ' после удаления обработанных, осталось обработать'  FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

					END 

					/*************************************/
					/* Завершение транзакции по TABLOCKX */
					COMMIT TRAN a1
					/*************************************/

				/* будем обрабатывать */
					select	@row_count		= Count (*) from w_depersonalization_table_12 (nolock) WHERE occupied = 0
					if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 9, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @row_count) + ' - будем обрабатывать. Если 0 - то все записи уже обработаны.' FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

					/* Получаем количество записей которые можно обработать */
					SELECT @occupied_12 = Count (*) FROM w_depersonalization_table_12  (nolock) WHERE occupied = 0
					SELECT @occupied_16 = Count (*) FROM w_depersonalization_table_12  (nolock) WHERE occupied = 1
					--	SELECT Count (*) FROM w_depersonalization_table_12 WHERE occupied = 0 /* occupied = 0 записи которые нужно обрабатывать */

					/******************************************************************/
					/* цикл по 10000 записей из таблицы w_depersonalization_table_12  */
					/* для того чтобы можно запустить параллельно несколько процедур   */
					/******************************************************************/
					WHILE  @occupied_12 > 0 or @occupied_16 > 0
					BEGIN
							if object_id('tempdb..#table_11',N'u')  is not null drop table #table_11
							/* таблица сбора всех данных по всем таблицам полям и подменяемым данным */
							create table #table_11
							( 
											id_identity					int					identity, 
											pole_1						nvarchar (4000)		null, /* Поиск полей для обезличивания */
											pole_2						nvarchar (1000)		null, /* Создание индекса */
											pole_3						nvarchar (1000)		null, /* Удаление индекса */
											pole_4						nvarchar (100)		null, /* "таблица + поле" - идентификатор индекса */
											pole_5						nvarchar (100)		null, /* "таблица + поле + имя" - идентификатор запроса */
											pole_6						nvarchar (100)		null, /* поисковое слово по слогам длиной - @int_num */
											DATA_TYPE					varchar  (255)		null, /* тип данных */
											CHARACTER_MAXIMUM_LENGTH	int					null, /* размер поля */
											occupied					int					null  /* 1 - если занята другой процедурой или 2- запись уже отработана */
							) 

							/***********************************************************************************************************************************************/
							/* Транзакция для блокировки таблицы по w_depersonalization_table_12 в момент выборки, чтобы параллельно не обрабатывались одни и теже записи  */
							/***********************************************************************************************************************************************/
							IF @occupied_12 > 0
							BEGIN
								BEGIN TRAN a2

								/* перебрасываем в новую таблицу чтобы обновить поле id_identity */
								INSERT INTO #table_11
								( 
										pole_1,							/* Поиск полей для обезличивания */
										pole_2,							/* Создание индекса */
										pole_3,							/* Удаление индекса */
										pole_4,							/* "таблица + поле" - идентификатор индекса */
										pole_5,							/* "таблица + поле + имя" - идентификатор запроса */
										pole_6,							/* поисковое слово по слогам длиной - @int_num */
										DATA_TYPE,						/* тип данных */
										CHARACTER_MAXIMUM_LENGTH,		/* размер поля */
										occupied						/* 1 - если занята другой процедурой или 2 - запись уже отработана - 3 обрабатывается повторно */
								) 
								SELECT TOP 10000 /* первые 10 000 записей для этой процедуры */
										pole_1,							/* Поиск полей для обезличивания */
										pole_2,							/* Создание индекса */
										pole_3,							/* Удаление индекса */
										pole_4,							/* "таблица + поле" - идентификатор индекса */
										pole_5,							/* "таблица + поле + имя" - идентификатор запроса */
										pole_6,							/* поисковое слово по слогам длиной - @int_num */
										DATA_TYPE,						/* тип данных */
										CHARACTER_MAXIMUM_LENGTH,		/* размер поля */
										occupied						/* 1 - если занята другой процедурой или запись уже отработана */
								  FROM 
										w_depersonalization_table_12 (TABLOCKX)
								 WHERE 
										occupied	= 0					/* 1 - если занята другой процедурой или 2 - запись уже отработана */
 								 ORDER BY
										pole_5

								/* Проставляем флаг occupied = 1 для забранных записей */
								UPDATE 
										w_depersonalization_table_12
								   SET
										occupied = 1 /*  1 для забранных записей */
								  FROM
										#table_11 t11
 								 WHERE
										t11.pole_5 = w_depersonalization_table_12.pole_5


								/****************************************************************************/
								/* Завершение транзакции по блокировке таблицы w_depersonalization_table_12 */
								/****************************************************************************/
								COMMIT TRAN a2
							END
							ELSE IF @occupied_16 > 0
							BEGIN
								/* перебрасываем в новую таблицу чтобы обновить поле id_identity */
								INSERT INTO #table_11
								( 
										pole_1,							/* Поиск полей для обезличивания */
										pole_2,							/* Создание индекса */
										pole_3,							/* Удаление индекса */
										pole_4,							/* "таблица + поле" - идентификатор индекса */
										pole_5,							/* "таблица + поле + имя" - идентификатор запроса */
										pole_6,							/* поисковое слово по слогам длиной - @int_num */
										DATA_TYPE,						/* тип данных */
										CHARACTER_MAXIMUM_LENGTH,		/* размер поля */
										occupied						/* 1 - если занята другой процедурой или 2 - запись уже отработана - 3 обрабатывается повторно */
								) 
								SELECT TOP 10000 /* первые 10 000 записей для этой процедуры */
										pole_1,							/* Поиск полей для обезличивания */
										pole_2,							/* Создание индекса */
										pole_3,							/* Удаление индекса */
										pole_4,							/* "таблица + поле" - идентификатор индекса */
										pole_5,							/* "таблица + поле + имя" - идентификатор запроса */
										pole_6,							/* поисковое слово по слогам длинной - @int_num */
										DATA_TYPE,						/* тип данных */
										CHARACTER_MAXIMUM_LENGTH,		/* размер поля */
										occupied						/* 1 - если занята другой процедурой или запись уже отработана */
								  FROM 
										w_depersonalization_table_12 (nolock)
								 WHERE 
										occupied	= 0					/* 1 - если занята другой процедурой или 2 - запись уже отработана */
 							  ORDER BY
										substring (Reverse (pole_5), CAST ((Rand () * 10) + 1  as int ), 3)  /* сортировка случайным образом 10 вариантов сортировки */
							END

							/* получаем количество записей по всем таблицам  */
							select	@row_count		= Count (*) from #table_11
							set		@id_identity	= 1
							set		@pole_1			= ''

							if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 10, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @row_count) + ' - нужно обработать SELECT(ов)' FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid
							/********************************************************/
							/* цикл символам кирилицы								*/
							/********************************************************/
							while	@id_identity <= @row_count
							begin

									select 
											@pole_1						= pole_1,					/* поиск для обезличивания */
											@pole_2						= pole_2,					/* создание индекса */
											@pole_3						= pole_3,					/* удаление индекса */
											@pole_4						= pole_4,					/* "таблица + поле" как идентификатор индекса */
											@pole_5						= pole_5,					/* "таблица + поле + имя" как идентификатор поля */
											@pole_6						= pole_6,					/* поисковое слово по слогам длиной - @int_num */
											@DATA_TYPE					= DATA_TYPE,				/* тип данных */
											@CHARACTER_MAXIMUM_LENGTH	= CHARACTER_MAXIMUM_LENGTH	/* размер поля */
									from	
											#table_11 
									where	
											id_identity = @id_identity

									if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 11, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), @pole_1 FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

									/* объединяем запросы в максимальную строку через UNION чтобы реже вызывать процедуру SP_EXECUTESQL */
									if datalength (@pole_1) > 0 and datalength (@pole_2) > 0
									begin

											/* Проверяем а не исполнил ли кто-то этот запрос  */
											SELECT 
													@occupied_01 = Max (t12.occupied) 
											  FROM
													w_depersonalization_table_12 t12 (nolock)
 											  WHERE
													t12.pole_5 = @pole_5

											/* если статус не равен двум, выполняем поиск */
											IF NOT @occupied_01 = @occupied_02
											BEGIN 

												/********************************************************************/
												/* Основная проверка на то, что в данном поле таблицы есть кирилица */
												/********************************************************************/
												EXEC SP_EXECUTESQL @pole_1
												set @pole_1 = ''

												if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 12, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), @pole_5 FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

											END

											IF EXISTS (select 1 from ##table_10 WHERE pole_5 = @pole_5) 
											BEGIN

												/* Удаляем данные так как это была проверка наналичие кирилицы в поле */
												DELETE FROM 
														##table_10 
												WHERE 
														pole_5 = @pole_5

												/* сохраняем идентификатор */
												SELECT @pole_44 = @pole_4	/* "таблица + поле" как идентификатор индекса */

												/********************************************************/
												/* цикл по полю для всех слогов из слов пользователей	*/
												/********************************************************/
												while	@id_identity <= @row_count and  @pole_44 = @pole_4
												begin

													/* сохраняем переменную */
													SET @pole_22 = @pole_2

													if datalength (@pole_2) > 0 
													begin

														/* Проверяем а не исполнил ли кто-то этот запрос  */
														SELECT 
																@occupied_01 = Max (t12.occupied) 
														  FROM
																w_depersonalization_table_12 t12 (nolock)
 														  WHERE
																t12.pole_5 = @pole_5

														/* если статус не равен двум, выполняем поиск */
														IF NOT @occupied_01 = @occupied_02
														BEGIN 

															/********************************************************************/
															/* Проверка поля по слогам, что в данном поле таблицы есть кирилица */
															/********************************************************************/
															EXEC SP_EXECUTESQL @pole_2

														END

														/* очищаем переменную */
														SET @pole_2 = ''

														if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 13, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), @pole_5 FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

														/* все отработанные запросы сохраняются в таблицу */
														INSERT INTO w_depersonalization_pole_3
														(
															pole_1,		/* "таблица + поле + имя " как идентификатор запроса */
															pole_6,		/* поисковое слово по слогам длиной - @int_num */
															DATA_TYPE,	/* тип данных поля */
															CHARACTER_MAXIMUM_LENGTH /* длина поля */
														)
														VALUES
														(
															@pole_5,	/* "таблица + поле + имя " как идентификатор запроса */
															@pole_6,	/* поисковое слово по слогам длиной - @int_num */
															@DATA_TYPE,	/* тип данных поля */
															@CHARACTER_MAXIMUM_LENGTH /* длина поля */
														)

														IF EXISTS (select 1 from ##table_10 WHERE pole_5 = @pole_5)
														BEGIN

															/* Вставка в стационарную таблицу найденные данные, */
															/* это сделано для того что операции не успевают пройти за стуки, */
															/* виртуалка перезапускается и теряется результат работы */
															INSERT INTO  w_depersonalization_table_9 
															(		id_identity, TABLE_SCHEMA, table_name, COLUMN_NAME, name_1, name_2, DATA_TYPE, DATA_SIZE	)
															SELECT 
																	id_identity, TABLE_SCHEMA, table_name, COLUMN_NAME, name_1, name_2, DATA_TYPE, DATA_SIZE  /* '-1' для XML */
															FROM
																	##table_10 (nolock)
															WHERE 
																	pole_5 = @pole_5
															/* очищаем таблицу в которую загружаются найденные данные для обезлички (если такие были найдены) */
															DELETE FROM 
																	##table_10 
															WHERE 
																	pole_5 = @pole_5

															if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 14, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), @pole_22 FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

															/* Так как в данной 'таблица + поле' персональные данные найдены, нет смысла продолжать поиск дальше */
															SET @pole_44 = 'Найдено!' /* это обозначает выход из второго цикла так как будет проверено @pole_44 = @pole_4 */
														END
													END

													/* если продолжаем крутится во втором цикле */
													IF @pole_44 = @pole_4
													BEGIN
														/* Проставляем флаг occupied = 2 для обработанных записей */
														UPDATE 
																w_depersonalization_table_12
															SET
																occupied = 2
 															WHERE
																w_depersonalization_table_12.pole_5 = @pole_5

														if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 15, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @id_identity) FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

														/* счетчик для цикла */
														set @id_identity = @id_identity + 1

														select 
																@pole_1						= pole_1,					/* поиск для обезличивания */
																@pole_2						= pole_2,					/* создание индекса */
																@pole_3						= pole_3,					/* удаление индекса */
																@pole_4						= pole_4,					/* "таблица + поле" как идентификатор индекса */
																@pole_5						= pole_5,					/* "таблица + поле + имя" как идентификатор поля */
																@pole_6						= pole_6,					/* поисковое слово по слогам длиной - @int_num */
																@DATA_TYPE					= DATA_TYPE,				/* тип данных */
																@CHARACTER_MAXIMUM_LENGTH	= CHARACTER_MAXIMUM_LENGTH	/* размер поля */
														from	
																#table_11 
														where	
																id_identity = @id_identity


													END
													ELSE
													BEGIN
														/* Выходи из второго цикал */
														SET @id_identity_old = @id_identity


														/* счетчик цикла */
														SELECT  
																@id_identity = IsNull (Min (id_identity), @row_count + 1)
															FROM
																#table_11 
															WHERE
																pole_4		<>  @pole_4			 and 
																id_identity >   @id_identity_old 

														if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 16, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()),  Convert (varchar, @id_identity_old) + '/' + Convert (varchar, @id_identity) FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

														/* все НЕотработанные запросы сохраняются в таблицу, так как персональные данные всеравно найдены */
														INSERT INTO w_depersonalization_pole_3
														(
																pole_1,						/* "таблица + поле + имя " как идентификатор запроса */
																pole_6,						/* поисковое слово по слогам длиной - @int_num */
																DATA_TYPE,					/* тип данных поля */
																CHARACTER_MAXIMUM_LENGTH	/* длина поля */
														)
														SELECT 
																pole_5,						/* "таблица + поле + имя " как идентификатор запроса */
																pole_6,						/* поисковое слово по слогам длиной - @int_num */
																DATA_TYPE,					/* тип данных поля */
																CHARACTER_MAXIMUM_LENGTH	/* длина поля */
															FROM
																#table_11 
														WHERE 	/* здесь именно '<' так как текущая запись уже сохранена */
																@id_identity_old < id_identity and id_identity < @id_identity

														/* Проставляем флаг occupied = 2 для обработанных */
														UPDATE 
																w_depersonalization_table_12
															SET
																occupied = 2
															FROM
																#table_11 t11
 															WHERE  /* здесь именно '<' так как текущая запись уже сохранена */
																w_depersonalization_table_12.pole_4 = t11.pole_4 and
																@id_identity_old <= t11.id_identity and t11.id_identity < @id_identity
													END
												END

												/* счетчик для цикла */
												--set @id_identity = @id_identity + 1 /* счетчик уже прибавился */
							
											END
											ELSE
											BEGIN
												SET @id_identity_old = @id_identity

												/* счетчик цикла */
												SELECT  
														@id_identity = IsNull (Min (id_identity), @row_count + 1)
													FROM
														#table_11 
													WHERE
														pole_4		<>  @pole_4			 and 
														id_identity >   @id_identity_old 

												/* все отработанные запросы сохраняются в таблицу */
												INSERT INTO w_depersonalization_pole_3
												(
														pole_1,						/* "таблица + поле + имя " как идентификатор запроса */
														pole_6,						/* поисковое слово по слогам длиной - @int_num */
														DATA_TYPE,					/* тип данных поля */
														CHARACTER_MAXIMUM_LENGTH	/* длина поля */
												)
												SELECT 
														pole_5,						/* "таблица + поле + имя " как идентификатор запроса */
														pole_6,						/* поисковое слово по слогам длиной - @int_num */
														DATA_TYPE,					/* тип данных поля */
														CHARACTER_MAXIMUM_LENGTH	/* длина поля */
													FROM
														#table_11 
												WHERE 	/* сдесь именно '<=' так как текущая запись НЕ сохранена */
														@id_identity_old <= id_identity and id_identity < @id_identity

												if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 17, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @id_identity_old ) + '/' + Convert (varchar, @id_identity ) FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

												/* Проставляем флаг occupied = 2 для обработанных */
												UPDATE 
														w_depersonalization_table_12
												   SET
														occupied = 2
												  FROM
														#table_11 t11
												 WHERE  
														/* сдесь именно '<=' так как текущая запись НЕ сохранена */
														w_depersonalization_table_12.pole_4 = t11.pole_4 and
														@id_identity_old <= t11.id_identity and t11.id_identity < @id_identity
											END
									end
									else
									begin
										/*  по идее сюща цикл попадать никогда не должен, но на всякий случай кусочек проработан */
										SET @id_identity_old = @id_identity

										/* счетчик цикла */
										SELECT  
												@id_identity = IsNull (Min (id_identity), @row_count + 1)
											FROM
												#table_11 
											WHERE
												datalength	(   @pole_1) > 0 and 
												datalength	(   @pole_2) > 0 and
												pole_4		<>  @pole_4		 and 
												id_identity  >  @id_identity_old

										if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 18, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @id_identity_old ) FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

									end 
							end

							/* удаляем таблицу чтобы обновить поле id_identity */
							drop table #table_11

							/* Получаем количество записей которые можно обработать */
							SELECT @occupied_12 = Count (*) FROM w_depersonalization_table_12  with (nolock, index (isx_w_depersonalization_table_12_occupied) ) WHERE occupied = 0
							SELECT @occupied_16 = Count (*) FROM w_depersonalization_table_12  with (nolock, index (isx_w_depersonalization_table_12_occupied) ) WHERE occupied = 1

					END

					if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 19, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @id_identity_old ) FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid
					-- SELECT Count (*) FROM w_depersonalization_table_12 WHERE occupied = 3  /* если осталис записи occupied = 3 то их нужно перевести occupied = 1 (так как их обработку прерывали ) */
			--		DELETE FROM w_depersonalization_table_12 WHERE occupied = 2 /* обработаны  */
			--		select Count (*) as 'обработано' from w_depersonalization_pole_3

			/*------ второй этап --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
					SELECT @occupied_12 = Count (*) FROM w_depersonalization_table_12 /*(TABLOCKX)*/   (NOLOCK) WHERE occupied <> 2 /* проверка на все ли записи обработаны? */
					/* Ожидание когда закончат работу паралельные процедуры так как свободных записей уже не осталось, все в работе */
					IF @occupied_12 > 0 
					BEGIN
						/* цикл ожидания пока все записи не обработаются */
						while	@occupied_12 > 0
						BEGIN
							if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 20, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), 'WAITFOR DELAY 00:01:00' FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid
							/* Задержка на указанное время  WAITFOR DELAY '00:01:00' одна минута */
							WAITFOR DELAY '00:01:00'
							SELECT @occupied_12 = Count (*) FROM w_depersonalization_table_12 /*(TABLOCKX)*/  (NOLOCK) WHERE occupied <> 2 /* проверка на все ли записи обработаны? */
						END
					END 
					--SELECT Count (*) FROM w_depersonalization_table_12 (TABLOCKX) /* (NOLOCK)*/ WHERE occupied <> 2 /* все ли записи обработаны */

					/* транзакция для блокировки w_depersonalization_table_13 */
					BEGIN TRAN a3

					SELECT @RowCount_table_13 = Count (*) FROM w_depersonalization_table_13  (TABLOCK) /*(TABLOCKX)*/

					/* если записей нет, то создаем их */
					IF @RowCount_table_13 = 0 
					BEGIN 
						/* Группируем результат всей предыдущей работы  */
						insert into #table_12 (TABLE_SCHEMA, table_name, COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, pole_5 ) select TABLE_SCHEMA, table_name, COLUMN_NAME, DATA_TYPE, Convert (int, DATA_SIZE), Count (*) from w_depersonalization_table_9  GROUP BY TABLE_SCHEMA, table_name, COLUMN_NAME, DATA_TYPE,	DATA_SIZE order by TABLE_SCHEMA,	table_name,	COLUMN_NAME, DATA_TYPE,	DATA_SIZE 

						truncate table #table_01
						/* список всех Ф.И.О. для получения списка обезличивания */
						insert into #table_01 (name_1)
						select distinct			/* Фамилии  */	s_U_FamilyName		from t_user tu (nolock) where IIF (Rtrim (s_U_FamilyName)	= '''', NULL, s_U_FamilyName)	IS NOT NULL and Len (s_U_FamilyName)> 1	and ASCII (tu.s_U_FamilyName)	> 191 and charindex (' ', s_U_FamilyName )	= 0 and Len (s_U_FamilyName) > 1
						union select distinct	/* Имена    */  s_U_FirstName		from t_user tu (nolock) where IIF (Rtrim (s_U_FirstName)	= '''', NULL, s_U_FirstName)	IS NOT NULL and Len (s_U_FirstName)	> 1	and ASCII (tu.s_U_FirstName)	> 191 and charindex (' ', s_U_FirstName )	= 0 and Len (s_U_FirstName) > 1
						union select distinct	/* Отчества */  s_U_LastName		from t_user tu (nolock) where IIF (Rtrim (s_U_LastName)		= '''', NULL, s_U_LastName)		IS NOT NULL and Len (s_U_LastName)	> 1	and ASCII (tu.s_U_LastName)		> 191 and charindex (' ', s_U_LastName )	= 0 and Len (s_U_LastName) > 1

						if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 21, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), null FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

						/* самый простой способо сделать второй список пользователей в другой последовательности */
						insert into  #table_02 (name_2)
						select name_1 from #table_01 order by substring (name_1, 2, 3) desc, id_identity desc

						/* просталяем второй столбец пользователей */
						UPDATE t1 SET name_2 = t2.name_2 FROM #table_01 t1, #table_02 t2 WHERE t2.id_identity = t1.id_identity and NOT t1.name_1 = t2.name_2

						/* проходимся еще раз, так как может остаться одно пустое поле */
						UPDATE t1 SET name_2 = t2.name_2 FROM #table_01 t1, #table_02 t2 WHERE t1.name_2 IS NULL	 and NOT t1.name_1 = t2.name_2

						if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time, sec, descr) SELECT 22, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), null FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

						/* в транзации отрабатывает за 346.486 секунд это около 6 минут  */
						INSERT INTO w_depersonalization_table_13
						( 
										pole_1,						/* 1 Поиск полей с кирилицей */
										pole_2,						/* 2 Создание индекса */
										pole_3,						/* 3 резерв */
										pole_4,						/* 4 "таблица + поле" - идентификатор индекса */
										pole_5,						/* 5 "таблица + поле + имя" - идентификатор запроса */
										pole_6,					    /* 6 поисковое слово по слогам длиной - @int_num */
										DATA_TYPE,					/* 7 тип данных */
										CHARACTER_MAXIMUM_LENGTH,	/* 8 размер поля */
										occupied					/* 9 1 - если занята другой процедурой или 2 - запись уже отработана */
						) 
						SELECT 
										'INSERT INTO ##table_8 ( TABLE_SCHEMA, table_name, COLUMN_NAME, name_1, name_2, DATA_TYPE, DATA_SIZE, pole_5) 
										SELECT DISTINCT ''' + 
										t2.TABLE_SCHEMA		+ ''', ''' + 
										t2.table_name		+ ''', ''' + 
										t2.COLUMN_NAME		+ ''', ''' + 
										p1.name_1			+ ''', ''' + 
										p1.name_2			+ ''', ''' + 
										t2.DATA_TYPE		+ ''', ''' + 
										Convert (varchar (100), t2.CHARACTER_MAXIMUM_LENGTH) + ''', ''' + 
										t2.TABLE_SCHEMA + '.'+ t2.table_name + '.' + t2.COLUMN_NAME + '.' + p1.name_1 + ''' 
										FROM ' + t2.TABLE_SCHEMA + '.' + t2.table_name + ' (nolock' +
													--CASE 
													--		WHEN t2.CHARACTER_MAXIMUM_LENGTH < 900 THEN  ' index ( ids_'+ t2.table_name + '_' + t2.COLUMN_NAME + ')'
													--		ELSE	''
													--END	+ 
													') ' + '
										WHERE '  + 'PATINDEX(''%' + p1.name_1 + '%'', ' + t2.COLUMN_NAME + ' ) > 0 and ' + t2.COLUMN_NAME + ' IS NOT NULL'
										,
										/* 2 резерв, так как индекс не нужен  */
										CASE 
													WHEN t2.CHARACTER_MAXIMUM_LENGTH < 900 THEN 'if INDEXPROPERTY (object_id (''' + t2.TABLE_SCHEMA + '.'+ t2.table_name + '''),  ''ids_'+ t2.table_name + '_' + t2.COLUMN_NAME + ''', ''IndexID'') is null CREATE INDEX ids_' +  t2.table_name + '_' + t2.COLUMN_NAME + ' ON ' + t2.TABLE_SCHEMA + '.' + t2.table_name + ' (' + t2.COLUMN_NAME + ')'
													ELSE	''
										END
										,
										/* 3 резерв, так как индекс не нужен  */
										'if INDEXPROPERTY (object_id (''' + t2.TABLE_SCHEMA + '.'+ t2.table_name + '''),  ''ids_'+ t2.table_name + '_' + t2.COLUMN_NAME + ''', ''IndexID'') > 0     DROP   INDEX ids_' +  t2.table_name + '_' + t2.COLUMN_NAME + ' ON ' + t2.TABLE_SCHEMA + '.' + t2.table_name
										,
										/* 4 "таблица + поле" - идентификатор индекса */
										t2.TABLE_SCHEMA + '.'+ t2.table_name + '.' + t2.COLUMN_NAME,					/* 4 "таблица + поле" - идентификатор индекса */
										t2.TABLE_SCHEMA + '.'+ t2.table_name + '.' + t2.COLUMN_NAME + '.' + p1.name_1,	/* 5 "таблица + поле + имя" как идентификатор поля */
										p1.name_2,																		/* 6 поисковое слово по слогам длиной - @int_num */
										t2.DATA_TYPE,																	/* 7 ип данных */
										t2.CHARACTER_MAXIMUM_LENGTH,													/* 8 размер поля */
										0 as occupied																	/* 9 1 - если занята другой процедурой или 2- запись уже отработана или 3 обрабатывается повторно */
								from 
										#table_01	p1,	/* списиок персональных данных */
										#table_12	t2  /* список таблиц, где скорее всего есть персональные данные, так как эти таблицы были проерены по слогам  */
								where 
										t2.CHARACTER_MAXIMUM_LENGTH > 29 /* считаем что в поля менее 29 символов имен быть недолжно */ 
										and t2.DATA_TYPE  in ( 'text', 'ntext', 'nvarchar', 'varchar', 'char', 'nchar') 
							UNION
								select 
										/* 2 Поиск полей ПО СЛОГАМ длиной - @int_num */
										'INSERT INTO ##table_8 ( TABLE_SCHEMA, table_name, COLUMN_NAME, name_1, name_2, DATA_TYPE, DATA_SIZE, pole_5) 
										SELECT ''' + 
										t2.TABLE_SCHEMA		+ ''', ''' + 
										t2.table_name		+ ''', ''' + 
										t2.COLUMN_NAME		+ ''', ''' + 
										p1.name_1			+ ''', ''' + 
										p1.name_2			+ ''', ''' + 
										t2.DATA_TYPE		+ ''', ''' + 
										Convert (varchar (100), t2.CHARACTER_MAXIMUM_LENGTH) + ''', ''' + 
										t2.TABLE_SCHEMA + '.'+ t2.table_name + '.' + t2.COLUMN_NAME + '.' + p1.name_1 + ''' 
										FROM ' + t2.TABLE_SCHEMA + '.' + t2.table_name + ' (nolock) WHERE '  
										+ t2.COLUMN_NAME + '.exist(N''//*[contains(., ' + '"' + p1.name_1 + '"'+ ')]'') = 1 having Count (*) > 0'
										,
										/* 2 резерв */
										NULL
										,
										/* 3 резерв */
										'if INDEXPROPERTY (object_id (''' + t2.TABLE_SCHEMA + '.'+ t2.table_name + '''),  ''ids_'+ t2.table_name + '_' + t2.COLUMN_NAME + ''', ''IndexID'') > 0     DROP   INDEX ids_' +  t2.table_name + '_' + t2.COLUMN_NAME + ' ON ' + t2.TABLE_SCHEMA + '.' + t2.table_name
										,
										t2.TABLE_SCHEMA + '.'+ t2.table_name + '.' + t2.COLUMN_NAME,					/* 4 "таблица + поле" - идентификатор индекса */
										t2.TABLE_SCHEMA + '.'+ t2.table_name + '.' + t2.COLUMN_NAME + '.' + p1.name_2,	/* 5 "таблица + поле + имя" как идентификатор поля */
										p1.name_1,																		/* 6 поисковое слово по слогам длиной - @int_num */
										t2.DATA_TYPE,																	/* 7 тип данных */
										t2.CHARACTER_MAXIMUM_LENGTH,													/* 8 размер поля */
										0 as occupied																	/* 9 1 - если занята другой процедурой или 2- запись уже отработана или 3 обрабатывается повторно */
								from 
										#table_01		p1, /* списиок персональных данных */
										#table_12		t2  /* список таблиц, где скорее всего есть персональные данные, так как эти таблицы были проерены по слогам  */
								where 
										t2.CHARACTER_MAXIMUM_LENGTH < 0 
										and t2.DATA_TYPE	= 'xml'	

								select	@row_count		= Count (*) from w_depersonalization_table_13
								if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 23, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @row_count) + ' всего нужно обрабоать'  FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

								/* убираем поля которые уже обработаны в транзакции. DELETE отрабатывает за 35.9593 секунд, при удалени 2 190 750 записей (всех) */
								DELETE 
										p13 /* здесь лежат все гипотетические запросы */
								  FROM 
										w_depersonalization_table_13	p13 with (nolock, index (isx_w_depersonalization_table_13_occupied)), /* здесь лежат все гипотетические запросы */
										w_depersonalization_pole_1		p1	(nolock)	/* здесь лежат все обработанные запросы */
								 WHERE 
										p13.pole_5 = p1.pole_1

								select	@row_count		= Count (*) from w_depersonalization_table_13
								if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 24, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @row_count) + ' но осталось обрабоать'  FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

								

								/* осталось обрабоать  */
								select	@row_count		= Count (*) from w_depersonalization_table_13
								if @row_count = 0 
								begin
									/* вставыляем одну запись, чтобы другие процедуры после окончания транзакии не пошли по этому пути */
									INSERT INTO w_depersonalization_table_13 (occupied) VALUES (@occupied_02)
								end

					END

					COMMIT TRAN a3


					/* Получаем количество записей которые можно обработать */
					SELECT @occupied_13 = Count (*) FROM w_depersonalization_table_13  (nolock) WHERE occupied = 0
					SELECT @occupied_14 = Count (*) FROM w_depersonalization_table_13  (nolock) WHERE occupied = 1
					--	SELECT Count (*) FROM w_depersonalization_table_12 WHERE occupied = 0 /* occupied = 0 записи которые нужно обрабатывать,  occupied = 1 в работе,  occupied = 2 для обработанных записей (обработка завершена ) */

					/******************************************************************/
					/* цикл по 10000 записей из таблицы w_depersonalization_table_12  */
					/* для того чтобы можно запустить паралельно несколько процедур   */
					/******************************************************************/
					WHILE  @occupied_13 > 0 or @occupied_14 > 0
					BEGIN
							if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) 
							SELECT 25, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @occupied_13) + '/' + Convert (varchar, @occupied_14) + ' цикл по 10 000 записей '  
							FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) 
							WHERE spid = @@spid

							if object_id('tempdb..#table_13',N'u')		is not null drop table #table_13
							/* таблица сбора всех данных по всем таблицам, полям и подменяемым данным */
							create table #table_13
							( 
											id_identity					int					identity, 
											pole_1						nvarchar (4000)		null, /* Поиск полей для обезличивания */
											pole_2						nvarchar (1000)		null, /* Создание индекса */
											pole_3						nvarchar (1000)		null, /* Удаление индекса */
											pole_4						nvarchar (100)		null, /* "таблица + поле" - идентификатор индекса */
											pole_5						nvarchar (100)		null, /* "таблица + поле + имя" - идентификатор запроса */
											pole_6						nvarchar (100)		null, /* поисковое слово по слогам длиной - @int_num */
											DATA_TYPE					varchar  (255)		null, /* тип данных */
											CHARACTER_MAXIMUM_LENGTH	int					null, /* размер поля */
											occupied					int					null  /* 1 - если занята другой процедурой или 2- запись уже отработана */
							) 

							/***********************************************************************************************************************************************/
							/* Транзакция для блокировки таблицы по w_depersonalization_table_12 в момент выборки, чтобы параллельно не обрабатывались одни и теже записи  */
							/***********************************************************************************************************************************************/
							IF @occupied_13 > 0
							BEGIN
								BEGIN TRAN a4

								/* перебрасываем в новую таблицу чтобы обновить поле id_identity */
								INSERT INTO #table_13
								( 
										pole_1,							/* Поиск полей для обезличивания */
										pole_2,							/* Создание индекса */
										pole_3,							/* Удаление индекса */
										pole_4,							/* "таблица + поле" - идентификатор индекса */
										pole_5,							/* "таблица + поле + имя" - идентификатор запроса */
										pole_6,							/* поисковое слово по слогам длиной - @int_num */
										DATA_TYPE,						/* тип данных */
										CHARACTER_MAXIMUM_LENGTH,		/* размер поля */
										occupied						/* 1 - если занята другой процедурой или 2 - запись уже отработана - 3 обрабатывается повторно */
								) 
								SELECT TOP 10000 /* первые 10 000 записей для этой процедуры */
										pole_1,							/* Поиск полей для обезличивания */
										pole_2,							/* Создание индекса */
										pole_3,							/* Удаление индекса */
										pole_4,							/* "таблица + поле" - идентификатор индекса */
										pole_5,							/* "таблица + поле + имя" - идентификатор запроса */
										pole_6,							/* поисковое слово по слогам длиной - @int_num */
										DATA_TYPE,						/* тип данных */
										CHARACTER_MAXIMUM_LENGTH,		/* размер поля */
										occupied						/* 1 - если занята другой процедурой или запись уже отработана */
								  FROM 
										w_depersonalization_table_13 (TABLOCKX)
								 WHERE 
										occupied	= 0					/* 1 - если занята другой процедурой или 2 - запись уже отработана */
 								 ORDER BY
										pole_5 asc

								/* Проставляем флаг occupied = 1 для забранных записей */
								UPDATE 
										w_depersonalization_table_13
								   SET
										occupied = 1 /*  1 для забранных записей */
								  FROM
										#table_13 t11
 								 WHERE
										t11.pole_5 = w_depersonalization_table_13.pole_5

								/****************************************************************************/
								/* Завершение транзакции по блокировке таблицы w_depersonalization_table_13 */
								/****************************************************************************/
								COMMIT TRAN a4
							END
							ELSE IF @occupied_14 > 0
							BEGIN

								/* перебрасываем в новую таблицу чтобы обновить поле id_identity */
								INSERT INTO #table_13
								( 
										pole_1,							/* Поиск полей для обезличивания */
										pole_2,							/* Создание индекса */
										pole_3,							/* Удаление индекса */
										pole_4,							/* "таблица + поле" - идентификатор индекса */
										pole_5,							/* "таблица + поле + имя" - идентификатор запроса */
										pole_6,							/* поисковое слово по слогам длиной - @int_num */
										DATA_TYPE,						/* тип данных */
										CHARACTER_MAXIMUM_LENGTH,		/* размер поля */
										occupied						/* 1 - если занята другой процедурой или 2 - запись уже отработана - 3 обрабатывается повторно */
								) 
								SELECT TOP 10000 /* первые 10 000 записей для этой процедуры */
										pole_1,							/* Поиск полей для обезличивания */
										pole_2,							/* Создание индекса */
										pole_3,							/* Удаление индекса */
										pole_4,							/* "таблица + поле" - идентификатор индекса */
										pole_5,							/* "таблица + поле + имя" - идентификатор запроса */
										pole_6,							/* поисковое слово по слогам длиной - @int_num */
										DATA_TYPE,						/* тип данных */
										CHARACTER_MAXIMUM_LENGTH,		/* размер поля */
										occupied						/* 1 - если занята другой процедурой или запись уже отработана */
								  FROM 
										w_depersonalization_table_13 (NOLOCK)
								 WHERE 
										occupied	= 1					/* 1 - если занята другой процедурой или 2 - запись уже отработана */
							  ORDER BY
										SubString (Reverse (pole_5), CAST ((Rand () * 10) + 1  as int ), 3)  /* сортировка случайным образом - 10 случайных вариантов */

							END 


							/* получаем количество записей по всем таблицам  */
							select	@row_table_13	= Count (*) from #table_13 (NOLOCK)
						--	set		@row_table_13	= 1000 /* если нужно поставить огранчения для отладки */
							set		@id_identity	= 1
							set		@pole_1			= ''

							if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 26, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @row_table_13) + ' - нужно обработать SELECT(ов) цикл по символам кирилицы' FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid
							/********************************************************/
							/* цикл по символам кирилицы							*/
							/********************************************************/


							/* Цикл для формирования строк формата:	
							схема_таблицы		пример:	dbo
							таблица				пример:	t_User
							колонка				пример:	s_U_LastName
							подменяемое_имя		пример:	Харитон
							на_что_меняем		пример:	Иванович
							тип_данных			пример:	varchar
							размер				пример:	40	*/
							while	@id_identity <= @row_table_13
							begin
								set @pole_1 = ''

								select 
										@pole_1						= pole_1,					/* поиск для обезличивания */
										@pole_2						= pole_2,					/* создание индекса */
										@pole_3						= pole_3,					/* удаление индекса */
										@pole_4						= pole_4,					/* "таблица + поле" как идентификатор индекса */
										@pole_5						= pole_5,					/* "таблица + поле + имя" как идентификатор поля */
										@DATA_TYPE					= DATA_TYPE,				/* тип данных */
										@CHARACTER_MAXIMUM_LENGTH	= CHARACTER_MAXIMUM_LENGTH	/* размер поля */
								from	
										#table_13 
							   where	
										id_identity = @id_identity

								if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 27, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar (10), @id_identity) + ' - № записи ' FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid
		
								IF Len (@pole_1) > 0 and Len (@pole_5) > 0 
								BEGIN
									/* Проверяем а не исполнил ли кто-то этот запрос  */
									SELECT 
											@occupied_01 = Max (t13.occupied) 
									  FROM
											w_depersonalization_table_13 t13 (NOLOCK)
 									  WHERE
											t13.pole_5 = @pole_5

									/* если статус не равен двум, выполняем поиск */
									IF NOT @occupied_01 = @occupied_02
									BEGIN 
											/*********************************/
											/* поиск полей для обезличивания */
											/*********************************/
											EXEC SP_EXECUTESQL @pole_1

											/* все отработанные запросы сохраняются в таблицу */
											INSERT INTO w_depersonalization_pole_1
											(
												pole_1,
												DATA_TYPE,
												CHARACTER_MAXIMUM_LENGTH
											)
											VALUES
											(
												@pole_5, /* "таблица + поле + имя " как идентификатор запроса */
												@DATA_TYPE,
												@CHARACTER_MAXIMUM_LENGTH
											)

											if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 28, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), @pole_5 FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid 

											/* Вставка в стационарную таблицу найденные данные, это сделано для того что операции не успевают пройти за стуки, */
											/* виртуалка перезапускается и теряется результат работы */
											INSERT INTO  w_depersonalization_table_8
											(
														id_identity,	
														TABLE_SCHEMA,
														table_name,
														COLUMN_NAME,
														name_1,
														name_2,
														DATA_TYPE,
														DATA_SIZE,
														pole_5
											)
											SELECT 
														id_identity,	
														TABLE_SCHEMA,
														table_name,
														COLUMN_NAME,
														name_1,
														name_2,
														DATA_TYPE,
														DATA_SIZE,
														pole_5
											FROM
														##table_8 (NOLOCK)
											WHERE 
														pole_5 = @pole_5

											/* Сколько найдено полей с персональными данными */
											SELECT @row_count = Count (*) FROM ##table_8  WHERE pole_5 = @pole_5
											if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 29, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), 'найдено: ' + Convert (varchar, @row_count)  FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

											if @row_count > 0 
											BEGIN
												/* очищаем таблицу в которую загружаются найденные данные для обезлички (если такие были найдены) */
												DELETE FROM 
														##table_8 
												WHERE 
														pole_5 = @pole_5
											END
		
											/* Проставляем флаг occupied = 1 для забранных записей */
											UPDATE 
													w_depersonalization_table_13
											   SET
													occupied = 2 /* occupied = 2 для обработанных записей (обработка завершена ) */
 											 WHERE
													w_depersonalization_table_13.pole_5 = @pole_5
									END 
								END


								set @id_identity = @id_identity + 1
							END

							if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 30, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), NULL FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid
							SELECT @occupied_13 = Count (*) FROM w_depersonalization_table_13  (nolock) WHERE occupied = 0
							SELECT @occupied_14 = Count (*) FROM w_depersonalization_table_13  (nolock) WHERE occupied = 1
					END

			/*-- третий этап --*/

					SELECT @occupied_13 = Count (*) FROM w_depersonalization_table_13 /*(TABLOCKX)*/   (NOLOCK) WHERE occupied <> 2 /* проверка на все ли записи обработаны? */
					/* Ожидание когда закончат работу паралельные процедуры так как свободных записей уже не осталось, все в работе */
					IF @occupied_13 > 0 
					BEGIN
						/* цикл ожидания пока все записи не обработаются */
						while	@occupied_13 > 0
						BEGIN
							if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 31, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), 'WAITFOR DELAY 00:01:00' FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid
							/* Задержка на указанное время  WAITFOR DELAY '00:01:00' одна минута */
							WAITFOR DELAY '00:01:00'
							SELECT @occupied_13 = Count (*) FROM w_depersonalization_table_13 /*(TABLOCKX)*/   (NOLOCK) WHERE occupied <> 2 /* проверка на все ли записи обработаны? */
						END
					END 


					/* транзакция для блокировки w_depersonalization_table_10 */
					BEGIN TRAN a5
					SELECT @RowCount_table_10 = Count (*) FROM w_depersonalization_table_10  (TABLOCK) /*(TABLOCKX)*/

					/* если записей нет, то создаем их */
					IF @RowCount_table_10 = 0 
					BEGIN 
							/* в этой таблице лежат конечные UPDATE базы данных для обезличивания */
							INSERT INTO w_depersonalization_table_10
							(
									pole_1,				/* текст скрипта для обезличивания базы данных */
									pole_5,				/* "таблица + поле + имя" - идентификатор запроса */
									occupied			/* 1 - если занята другой процедурой или 2- запись уже отработана */
							)
							select distinct 
									'UPDATE ' + TABLE_SCHEMA  + '.' + table_name  + 
									  ' SET ' +  column_name + ' = Convert ( xml,  replace ( Convert (varchar (max), ' + COLUMN_NAME + '), ''' + name_1 + ''', ''' + name_2 + ''' )) 
									  WHERE ' + column_name + '.exist(N''//*[contains(., ' + '"' + name_1 + '"'+ ')]'') = 1',
									  pole_5,				/* "таблица + поле + имя" - идентификатор запроса */
									  0 as occupied
							  from 
									w_depersonalization_table_8
							  where 
									DATA_TYPE = 'xml' and
									table_name not like '%dbo.w_%' 

							UNION
							select distinct 
									'UPDATE ' + TABLE_SCHEMA  + '.' + table_name  + 
									  ' SET ' +  column_name + ' = Convert ( ' + DATA_TYPE + ',  replace ( Convert (varchar (max), ' + COLUMN_NAME + '), ''' + name_1 + ''', ''' + name_2 + ''' )) 
									  WHERE '  + 'PATINDEX(''%' + name_1 + '%'', ' + COLUMN_NAME + ' ) > 0 and ' + COLUMN_NAME + ' IS NOT NULL',
									  pole_5,				/* "таблица + поле + имя" - идентификатор запроса */
									  0 as occupied
							  from 
									w_depersonalization_table_8
							  where 
									DATA_TYPE in ('ntext', 'text') and
									table_name not like '%dbo.w_%' 
							UNION
							select distinct 
									'UPDATE ' + TABLE_SCHEMA  + '.' + table_name  + 
									  ' SET ' +  column_name + ' = replace ( ' + COLUMN_NAME + ', ''' + name_1 + ''', ''' + name_2 + ''' ) 
									  WHERE '  + 'PATINDEX(''%' + name_1 + '%'', ' + COLUMN_NAME + ' ) > 0 and ' + COLUMN_NAME + ' IS NOT NULL',
									  pole_5,				/* "таблица + поле + имя" - идентификатор запроса */
									  0 as occupied
							  from 
									w_depersonalization_table_8
							  where 
									/* здесь должны обрабатываться DATA_TYPE  только 'nvarchar' и 'varchar' но если будут какие то еще типы, то они или могут создать скрипт с ошибой , но только так их можно отловить */
									DATA_TYPE not in ('ntext', 'text', 'xml') and 
									table_name not like '%dbo.w_%' 
					END
					/* конец транзакции для блокировки w_depersonalization_table_10 */
					COMMIT TRAN a5

		END

		/******************************************************************************************************************************************************************/
		/* Получаем количество записей которые можно обработать, но они должны быть в статусе occupied = 0 иначе считается что они обрабатываются паралельной процедурой  */
		SELECT @occupied_10 = Count (*) FROM w_depersonalization_table_10  (nolock) WHERE occupied = 0
		SELECT @occupied_11 = Count (*) FROM w_depersonalization_table_10  (nolock) WHERE occupied = 1
		/******************************************************************************************************************************************************************/
		if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 32, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @occupied_10) + '/' + Convert (varchar, @occupied_11) + ' Цикл по реальным Ф.И.О '  FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid
		
		--	SELECT Count (*) FROM w_depersonalization_table_12 WHERE occupied = 0 /* occupied = 0 записи которые нужно обрабатывать,  occupied = 1 в работе, occupied = 2 для обработанных записей (обработка завершена ) */

		/******************************************************************/
		/* цикл по 10000 записей из таблицы w_depersonalization_table_12  */
		/* для того чтобы можно запустить паралельно несколько процедур   */
		/******************************************************************/
		WHILE  @occupied_10 > 0 or @occupied_11 > 0
		BEGIN
			if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) 
			SELECT 32, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @occupied_10) + '/' + Convert (varchar, @occupied_10) + ' цикл по 10 000 записей Ф.И.О'  
			FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

			/* таблица пересоздается чтоб обновилось поле id_identity */
			if object_id('tempdb..#table_13',N'u')		is not null drop table #table_10
			create table #table_10
			( 
					id_identity					int					identity, 
					pole_1						nvarchar (4000)		null, /* текст скрипта для обезличивания базы данных */
					pole_5						nvarchar (100)		NULL, /* "таблица + поле + имя" - идентификатор запроса */
					occupied					int					NULL  /* 1 - если занята другой процедурой или 2- запись уже отработана */
			) 

			if @occupied_10 > 0 
			BEGIN
				BEGIN TRAN a6

				/* получаем 1000 записей для обезличивания */
				INSERT INTO #table_10
				( 
						pole_1,		/* текст скрипта для обезличивания базы данных */
						pole_5,		/* "таблица + поле + имя" - идентификатор запроса */
						occupied	/* 1 - если занята другой процедурой или 2- запись уже отработана */
				) 
				SELECT  top 1000
						pole_1,		/* текст скрипта для обезличивания базы данных */
						pole_5,		/* "таблица + поле + имя" - идентификатор запроса */
						occupied	/* 1 - если занята другой процедурой или 2- запись уже отработана */
				 FROM
						w_depersonalization_table_10 (TABLOCKX) 
				WHERE 
						occupied = 0 

				/* Проставляем флаг occupied = 1 для забранных записей */
				UPDATE 
						w_depersonalization_table_10
					SET
						occupied = 1 /*  1 для забранных записей */
					FROM
						#table_10 t10
 					WHERE
						t10.pole_5 = w_depersonalization_table_10.pole_5

				COMMIT TRAN a6

			END
			ELSE IF @occupied_11 > 0 
			BEGIN

				/* получаем 1000 записей для обезличивания */
			   INSERT INTO #table_10
				( 
						pole_1,		/* текст скрипта для обезличивания базы данных */
						pole_5,		/* "таблица + поле + имя" - идентификатор запроса */
						occupied	/* 1 - если занята другой процедурой или 2- запись уже отработана */
				) 
			   SELECT  top 1000
						pole_1,		/* текст скрипта для обезличивания базы данных */
						pole_5,		/* "таблица + поле + имя" - идентификатор запроса */
						occupied	/* 1 - если занята другой процедурой или 2- запись уже отработана */
				 FROM
						w_depersonalization_table_10 (NOLOCK) 
				WHERE 
						occupied = 1
		     ORDER BY 
						SubString (Reverse (pole_5), CAST ((Rand () * 10) + 1  as int ), 3)  /* сортировка случайным образом - 10 случайных вариантов */

			END

					/* начальные установки */
			select	@row_count		= Count (*) from #table_10
	--		set		@row_count		= 100 /* если нужно поставить огранчения для отладки */
			set		@id_identity	= 1
			set		@pole_1			= ''

			/* Цикл обезличивания таблиц всей базы */
			while	@id_identity <= @row_count
			begin
				select 
						@pole_1 = pole_1,  
						@pole_5 = pole_5 
				  from	
						#table_10 
				 where	
						id_identity = @id_identity

				SELECT 
						@occupied_01 = Max (t10.occupied) 
				  FROM
						w_depersonalization_table_10 t10
 				  WHERE
						t10.pole_5 = @pole_5

				IF NOT @occupied_01 = @occupied_02
				BEGIN 
					if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 33, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @id_identity) + '/' + Convert (varchar, @row_count) + ' цикл обедличка по 10 000 записей'  FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

					/* обезличивание */	
--					EXEC SP_EXECUTESQL @pole_1

					/* проставляем флаг - запись обезличина */
					UPDATE 
							w_depersonalization_table_10
					   SET
							occupied = 2 /*  2- запись обезличина */
 					  WHERE
							pole_5 = @pole_5
				END
				if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 34, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), @pole_5 FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

				/* переходим к следующей записи */
				set @id_identity = @id_identity + 1
			end 

			SELECT @occupied_10 = Count (*) FROM w_depersonalization_table_10  (nolock) WHERE occupied = 0
			SELECT @occupied_11 = Count (*) FROM w_depersonalization_table_10  (nolock) WHERE occupied = 1

		END

		SELECT @occupied_10 = Count (*) FROM w_depersonalization_table_10 /*(TABLOCKX)*/   (NOLOCK) WHERE occupied <> 2 /* проверка на все ли записи обработаны? */
		/* Ожидание когда закончат работу паралельные процедуры так как свободных записей уже не осталось, все в работе */
		IF @occupied_10 > 0 
		BEGIN
			/* цикл ожидания пока все записи не обработаются */
			while	@occupied_10 > 0
			BEGIN
				if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 35, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), 'WAITFOR DELAY 00:01:00' FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid
				/* Задержка на указанное время  WAITFOR DELAY '00:01:00' одна минута */
				WAITFOR DELAY '00:01:00'
				SELECT @occupied_10 = Count (*) FROM w_depersonalization_table_13 /*(TABLOCKX)*/   (NOLOCK) WHERE occupied <> 2 /* проверка на все ли записи обработаны? */
			END
		END 

		BEGIN TRAN a7

		SELECT @occupied_10 = Count (*) FROM w_depersonalization_table_10 (NOLOCK) /*  (NOLOCK)*/ WHERE occupied = 2 /* проверка на все ли записи обработаны? */
		SELECT @occupied_12 = Count (*) FROM w_depersonalization_table_10 (TABLOCKX) /*  (NOLOCK)*/ WHERE occupied <> 2 /* проверка на все ли записи обработаны? */
		IF @occupied_10 > 0 and @occupied_12 = 0
		BEGIN
				/* эти DELETE(ы) удаляют всю статичтику и ключи обезличивания, после этого удаления нельзя проанализировать как и скольк по времение работала процедура  */
				TRUNCATE TABLE w_depersonalization_pole_1   /* 2 137 862 записей, стационарная таблица в которой накапливаются 'таблици + поля + значения' которые были обработаны на 2-м этапе */
				TRUNCATE TABLE w_depersonalization_pole_3   /* 2 212 970 записей, стационарная таблица в которой накапливаются 'таблици + поля + значения' которые были обработаны на 1-м этапе */
				TRUNCATE TABLE w_depersonalization_table_8  /* 121 393 записей, стационарная таблица в которой накапливаются 'таблици + поля + значения' КОТОРЫЕ НУЖНО ОБЕЗЛИЧИТЬ  */
				TRUNCATE TABLE w_depersonalization_table_9  /* 7 377 записей, стационарная таблица в которой накапливаются 'таблици + поля + значения' КОТОРЫЕ НУЖНО ОБЕЗЛИЧИТЬ  */
				TRUNCATE TABLE w_depersonalization_table_10 /* 116 873 записей, стационарная таблица в которой накапливаются 'таблици + поля + значения' КОТОРЫЕ НУЖНО ОБЕЗЛИЧИТЬ  */
				TRUNCATE TABLE w_depersonalization_table_12 /* 1 150 записей, таблица сбора всех данных по всем таблицам полям и подменяемым данным */
				TRUNCATE TABLE w_depersonalization_table_13 /* 2 118 060 записей, таблица сбора всех данных по всем таблицам полям и подменяемым данным */
				if object_id('tempdb..##table_8',N'u') is not null drop table ##table_8
				if object_id('tempdb..##table_10',N'u') is not null drop table ##table_10
				TRUNCATE TABLE w_getdate	/* 6 615 544 запией всех операций */
		END
		COMMIT TRAN a7
		
err:

		drop table #table_01
		drop table #table_02
		drop table #table_12
		drop table #table_name_1
		drop table #table_pre_12
		drop table #table_pre_13
		drop table #table_pre_14 
		drop table #table_pre_15
		drop table #table_03_VAR 
--		drop table ##table_10 /* эту таблицу нужно удалить если добавляем в нее поля */

		SELECT @occupied_13 = Count (*) FROM w_depersonalization_table_13  (nolock) WHERE occupied = 0
		if user_name() = @user_name INSERT INTO w_getdate ( num, spid, date_time,sec, descr) SELECT 36, @@spid, GetDate (), DATEDIFF(ms, Max (date_time), GetDate ()), Convert (varchar, @occupied_13) + ' конечных запросов' FROM w_getdate with (nolock, index(isx_w_getdate_date_time_spid)) WHERE spid = @@spid

end 


...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Помогите написать запрос для обезличивания данных.
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]