2008-10-03 23 views
9

Estoy buscando una manera casera de codificar los datos de producción para su uso en el desarrollo y la prueba. He creado un par de scripts que crean números aleatorios de la seguridad social, cambian las fechas de nacimiento, codifican los correos electrónicos, etc. Pero me he topado con una pared tratando de mezclar los nombres de los clientes. Quiero conservar los nombres reales para que podamos usarlos o buscarlos de manera que la generación de letras al azar esté fuera. Lo que he intentado hasta ahora es construir una tabla temporal de todos los apellidos en la tabla y luego actualizar la tabla de clientes con una selección aleatoria de la tabla temporal. De esta manera:Ofuscación/máscara/información personal de Scramble

DECLARE @Names TABLE (Id int IDENTITY(1,1),[Name] varchar(100)) 

/* Scramble the last names (randomly pick another last name) */ 
INSERT @Names SELECT LastName FROM Customer ORDER BY NEWID(); 
WITH [Customer ORDERED BY ROWID] AS 
(SELECT ROW_NUMBER() OVER (ORDER BY NEWID()) AS ROWID, LastName FROM Customer) 
UPDATE [Customer ORDERED BY ROWID] SET LastName=(SELECT [Name] FROM @Names WHERE ROWID=Id) 

Esto funcionó bien en la prueba, pero completamente atasca tratar con grandes cantidades de datos (> 20 minutos para 40K filas)

Todo eso a preguntar, ¿cómo codificar los nombres de clientes mientras mantiene los nombres reales y el peso de los datos de producción?

ACTUALIZACIÓN: Nunca falla, intenta poner toda la información en la publicación y olvida algo importante. Esta información también se usará en nuestros entornos de demostración & de ventas que están disponibles públicamente. Algunas de las respuestas son lo que intento hacer para "cambiar" los nombres, pero mi pregunta es, literalmente, ¿cómo codificar en T-SQL?

Respuesta

1

Una solución muy simple sería ROT13 el texto.

Una pregunta mejor puede ser por qué sientes la necesidad de codificar los datos? Si tiene una clave de cifrado, también podría considerar ejecutar el texto a través de DES o AES o similar. Sin embargo, esto tendría posibles problemas de rendimiento.

+0

Como dije, necesito nombres reales con un peso similar/similar a la producción, por lo que las búsquedas se realizan de forma similar. –

+0

ROT13 adicional en realidad no codifica los datos, ya que es un algoritmo fácilmente reversible ... – Guvante

+0

sí, es fácilmente reversible, pero cumple los criterios de "máscara" u "ocultación": al menos debe reconocer que es sido ROT13, y lo DESTRUYE :) – warren

3

Yo uso generatedata. Es un script php de código abierto que puede generar todo tipo de datos ficticios.

+0

punta excelente - gracias. [Es una de esas cosas que he querido escribir durante años pero nunca tuve tiempo] ... –

-1

Francamente, no estoy seguro de por qué esto es necesario. Sus entornos de desarrollo/prueba deben ser privados, detrás de su firewall y no accesibles desde la web.

Sus desarrolladores deben ser de confianza, y usted tiene un recurso legal contra ellos si no cumplen con su confianza.

Creo que la verdadera pregunta debería ser "¿Debería codificar los datos?", Y la respuesta es (en mi opinión) 'no'.

Si lo va a enviar fuera del sitio por alguna razón, o si tiene que tener sus entornos accesibles a través de la web, o si está paranoico, implementaría un cambio aleatorio. En lugar de crear una tabla temporal, ejecute los interruptores entre cada ubicación y una fila aleatoria en la tabla, intercambiando una pieza de datos a la vez.

El resultado final será una tabla con todos los mismos datos, pero con la reorganización aleatoria. También debería ser más rápido que tu tabla temporal, creo.

Debería ser lo suficientemente simple para implementar el Fisher-Yates Shuffle en SQL ... o al menos en una aplicación de consola que lea el archivo db y lo escriba en el destino.

Editar (2): Fuera de la respuesta del manguito en T-SQL:

declarar @ name varchar (50) conjunto @ name = (SELECT lastName de persona donde PERSONID = (número de identificación aleatorio) actualización persona conjunto apellido = @ name = DONDE PERSONID (ID de la persona de la fila actual)

terminar con esto en un bucle, y seguir las directrices de Fisher-Yates para modificar las restricciones de valor al azar, y le fijarán.

+0

Nunca falla, tratas de poner toda la información en la publicación, y te olvidas de algo importante. Estas necesidades de datos también se usarán en nuestros entornos de ventas y demostración que están disponibles públicamente. Tu idea es lo que estoy tratando de hacer para 'cambiar' los nombres, pero mi pregunta es, literalmente, ¿cómo codificar? –

+0

Puede probar el Fisher-Yates Shuffle Debe ser lo suficientemente simple de implementar en SQL ... o en una aplicación de consola simple que lee en el archivo db y escribe en el archivo db de destino. – Jeff

+0

http://en.wikipedia.org/wiki/Fisher-Yates_shuffle Ese es el enlace correcto, supongo que tengo que aprender más sobre el medio ambiente aquí;) Actualizando mi respuesta. – Jeff

1

Cuando hago algo así, normalmente Puedo escribir un pequeño programa que primero carga muchos nombres y apellidos en dos matrices, y luego simplemente actualiza la base de datos usando nombres/apellidos aleatorios de las matrices. Funciona muy rápido incluso para conjuntos de datos muy grandes (200,000+ registros)

0

Use una tabla temporal en su lugar y la consulta es muy rápida. Corrí en 60K filas en 4 segundos. Voy a usar este en el futuro.

DECLARE TABLE #Names 
(Id int IDENTITY(1,1),[Name] varchar(100)) 

/* Scramble los apellidos (escogerán aleatoriamente otro apellido) */

INSERT #Names 
    SELECT LastName 
    FROM Customer 
    ORDER BY NEWID(); 
WITH [Customer ORDERED BY ROWID] AS 
(SELECT ROW_NUMBER() OVER (ORDER BY NEWID()) AS ROWID, LastName FROM Customer) 

UPDATE [Customer ORDERED BY ROWID] 

SET LastName=(SELECT [Name] FROM #Names WHERE ROWID=Id) 

DROP TABLE #Names 
+0

Aún podría terminar con una mala tirada y tener dos ... esperar. NewID() crea UUID. Estoy corregido. – Broam

0

estoy trabajando en esto en mi empresa en este momento - y que resulta ser muy complicado cosa. Desea tener nombres que sean realistas, pero no debe revelar ninguna información personal real.

Mi enfoque ha sido primero crear un "mapeo" aleatorizado de apellidos a otros apellidos, luego usar ese mapeo para cambiar todos los apellidos. Esto es bueno si tiene registros de nombres duplicados. Supongamos que tiene 2 registros "John Smith" que representan a la misma persona real. Si cambió un registro a "John Adams" y el otro a "John Best", ¡entonces su única "persona" ahora tiene 2 nombres diferentes! Con un mapeo, todas las ocurrencias de "Smith" se cambian a "Jones", por lo que los duplicados (o incluso los miembros de la familia) aún terminan con el mismo apellido, manteniendo los datos más "realistas".

También tendré que codificar las direcciones, números de teléfono, números de cuentas bancarias, etc. ... y no estoy seguro de cómo me acercaré a ellos. Mantener los datos "realistas" mientras lucha es ciertamente un tema profundo. Esto debe haberlo hecho muchas veces muchas compañías, ¿quién lo hizo antes? ¿Qué aprendiste?

0

El siguiente enfoque funcionó para nosotros, digamos que tenemos 2 mesas de clientes y productos.

CREATE FUNCTION [dbo].[GenerateDummyValues] 
(
    @dataType varchar(100), 
    @currentValue varchar(4000)=NULL 
) 
RETURNS varchar(4000) 
AS 
BEGIN 
IF @dataType = 'int' 
    BEGIN 
     Return '0' 
    END 
ELSE IF @dataType = 'varchar' OR @dataType = 'nvarchar' OR @dataType = 'char' OR @dataType = 'nchar' 
    BEGIN 
     Return 'AAAA' 
    END 
ELSE IF @dataType = 'datetime' 
    BEGIN 
     Return Convert(varchar(2000),GetDate()) 
    END 
-- you can add more checks, add complicated logic etc 
Return 'XXX' 
END 

La función anterior le ayudará en la generación de datos diferentes en función del tipo de datos que entra

Ahora , para cada columna de cada tabla que no tiene palabra "id" en él, utilizar siguiente consulta para generar más consultas para manipular los datos:

select 'select ''update '' + TABLE_NAME + '' set '' + COLUMN_NAME + '' = '' + '''''''' + dbo.GenerateDummyValues(Data_type,'''') + '''''' where id = '' + Convert(varchar(10),Id) from INFORMATION_SCHEMA.COLUMNS, ' + table_name + ' where RIGHT(LOWER(COLUMN_NAME),2) <> ''id'' and TABLE_NAME = '''+ table_name + '''' + ';' from INFORMATION_SCHEMA.TABLES; 

Cuando y ou ejecutar por encima de consulta que va a generar consultas de actualización para cada tabla y para cada columna de dicho cuadro, por ejemplo:

select 'update ' + TABLE_NAME + ' set ' + COLUMN_NAME + ' = ' + '''' + dbo.GenerateDummyValues(Data_type,'') + ''' where id = ' + Convert(varchar(10),Id) from INFORMATION_SCHEMA.COLUMNS, Customers where RIGHT(LOWER(COLUMN_NAME),2) <> 'id' and TABLE_NAME = 'Customers'; 
select 'update ' + TABLE_NAME + ' set ' + COLUMN_NAME + ' = ' + '''' + dbo.GenerateDummyValues(Data_type,'') + ''' where id = ' + Convert(varchar(10),Id) from INFORMATION_SCHEMA.COLUMNS, Products where RIGHT(LOWER(COLUMN_NAME),2) <> 'id' and TABLE_NAME = 'Products'; 

Ahora, cuando se ejecuta por encima de consultas obtendrá consultas de actualización finales, que actualizará los datos de tus tablas

Puede ejecutar esto en cualquier base de datos de SQL Server, no importa cuántas tablas tenga, generará consultas para usted que se pueden ejecutar más.

Espero que esto ayude.

0

Otro sitio para generar conformado conjuntos de datos falsos, con una opción para la salida de T-SQL: https://mockaroo.com/

0

Aquí está una manera usando ROT47 que es reversible, y otra que es al azar. Puede agregar un PK para vincularse a las versiones "no codificadas"

declare @table table (ID int, PLAIN_TEXT nvarchar(4000)) 
insert into @table 
values 
(1,N'Some Dudes name'), 
(2,N'Another Person Name'), 
(3,N'Yet Another Name') 

--split your string into a column, and compute the decimal value (N) 
if object_id('tempdb..#staging') is not null drop table #staging 
select 
    substring(a.b, v.number+1, 1) as Val 
    ,ascii(substring(a.b, v.number+1, 1)) as N 
    --,dense_rank() over (order by b) as RN 
    ,a.ID 
into #staging 
from (select PLAIN_TEXT b, ID FROM @table) a 
    inner join 
     master..spt_values v on v.number < len(a.b) 
where v.type = 'P' 

--select * from #staging 


--create a fast tally table of numbers to be used to build the ROT-47 table. 

;WITH 
    E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)), 
    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows 
    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max 
    cteTally(N) AS 
    (
     SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4 
    ) 



--Here we put it all together with stuff and FOR XML 
select 
    PLAIN_TEXT 
    ,ENCRYPTED_TEXT = 
     stuff((
     select 
      --s.Val 
      --,s.N 
      e.ENCRYPTED_TEXT 
     from #staging s 
     left join(
     select 
      N as DECIMAL_VALUE 
      ,char(N) as ASCII_VALUE 
      ,case 
       when 47 + N <= 126 then char(47 + N) 
       when 47 + N > 126 then char(N-47) 
      end as ENCRYPTED_TEXT 
     from cteTally 
     where N between 33 and 126) e on e.DECIMAL_VALUE = s.N 
     where s.ID = t.ID 
     FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 0, '') 
from @table t 


--or if you want really random 
select 
    PLAIN_TEXT 
    ,ENCRYPTED_TEXT = 
     stuff((
     select 
      --s.Val 
      --,s.N 
      e.ENCRYPTED_TEXT 
     from #staging s 
     left join(
     select 
      N as DECIMAL_VALUE 
      ,char(N) as ASCII_VALUE 
      ,char((select ROUND(((122 - N -1) * RAND() + N), 0))) as ENCRYPTED_TEXT 
     from cteTally 
     where (N between 65 and 122) and N not in (91,92,93,94,95,96)) e on e.DECIMAL_VALUE = s.N 
     where s.ID = t.ID 
     FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 0, '') 
from @table t 
Cuestiones relacionadas