Hay varios problemas en este código que deben abordarse:
-
Con respecto a la pregunta indicada, cuando recibe una System.Security.SecurityException error, que se refiere al código que intenta llegar fuera de la base de datos, algo que no está permitido en un
SAFE
asamblea. La forma en que solucione esto depende de lo que intente lograr.- Si está tratando de acceder al sistema de archivos, leer del registro, obtener una variable de entorno, acceder a la red para una conexión que no sea de SQL Server (por ejemplo, http, ftp), etc., entonces el ensamblado necesita un
PERMISSION_SET
deEXTERNAL_ACCESS
. Para configurar su ensamblaje en algo que no seaSAFE
, debe:- Cree un certificado o clave asimétrica basado en la misma clave que usó para firmar su ensamblaje (es decir, asígnele un nombre seguro), cree un inicio de sesión basado en ese certificado o clave asimétrica y luego otorgue el
EXTERNAL ACCESS ASSEMBLY
permiso para ese inicio de sesión. Este método es muy preferido sobre el otro método, que es: - Establecer la base de datos que contiene el ensamblado en
TRUSTWORTHY ON
. Este método solo debe usarse como último recurso si no es posible firmar el ensamblaje. O para fines de prueba rápida. Establecer una base de datos enTRUSTWORTHY ON
abre su instancia a posibles amenazas de seguridad y debe evitarse, incluso si es más rápido o más fácil que el otro método.
- Cree un certificado o clave asimétrica basado en la misma clave que usó para firmar su ensamblaje (es decir, asígnele un nombre seguro), cree un inicio de sesión basado en ese certificado o clave asimétrica y luego otorgue el
-
Si está intentando acceder a la instancia de SQL Server en la que ya ha iniciado sesión, tiene la opción de utilizar la conexión en proceso de
Context Connection = true;
que se puede hacer en unSAFE
asamblea. Esto es lo que sugirió @Marc en su respuesta. Si bien definitivamente hay beneficios en el uso de este tipo de conexión, y aunque la Conexión de contexto fue la opción adecuada en este escenario en particular, es demasiado simplista e incorrecto afirmar que debe siempre utilizar este tipo de conexión. Veamos los aspectos positivos y negativos de la Conexión de contexto :- Positivos:
- Se puede hacer en un
SAFE
montaje. - Sobrecarga de conexión muy baja, si la hay, ya que no es una conexión adicional.
- Es parte de la sesión actual, por lo que cualquier SQL que ejecute tenga acceso a elementos basados en la sesión, como tablas temporales locales y
CONTEXT_INFO
.
- Se puede hacer en un
-
Negativos:
- No se puede usar si se ha habilitado la suplantación de identidad.
- Solo se puede conectar a la instancia actual de SQL Server.
- Cuando se usa en funciones (escalares y con valores de tabla), tiene todas las mismas restricciones que tienen las funciones de T-SQL (por ejemplo, no se permiten operaciones con efectos secundarios), excepto que puede ejecutar procedimientos almacenados de solo lectura.
- Las funciones con valores de tabla no pueden transmitir sus resultados si leen un conjunto de resultados.
Todos estos "negativos" están permitidos cuando se utiliza una conexión normal/externa, incluso si se trata de la misma instancia desde la que está ejecutando este código.
- Positivos:
- Si está tratando de acceder al sistema de archivos, leer del registro, obtener una variable de entorno, acceder a la red para una conexión que no sea de SQL Server (por ejemplo, http, ftp), etc., entonces el ensamblado necesita un
-
Si se está conectando a la instancia desde la que está ejecutando este código y usa una conexión externa/regular, entonces no es necesario especificar el nombre del servidor o incluso usar
localhost
. La sintaxis preferida esServer = (local)
que usa memoria compartida, mientras que los demás a veces pueden usar TCP/IP, que no es tan eficiente. -
A menos que tenga una razón muy específica para hacerlo, no use
Persist Security Info=True;
-
Es una buena práctica
Dispose()
de suSqlCommand
-
Es más eficiente llamar a
insertcommand.Parameters.Add()
justo antes delfor
bucle, y luego dentro del bucle, simplemente establezca el valor a través defirstname.Value =
, lo que ya está haciendo, así que simplemente muevainsertcommand.Parameters.Add()
líneas justo antes delfor
línea. -
tel
/@tel
/listtelnumber
sonINT
en lugar deVARCHAR
/string
. Los números de teléfono, al igual que los códigos postales y los Números de Seguro Social (SSN), no números, incluso si lo parecen.INT
no se puede almacenar el0
inicial s o algo así comoex.
para significar una "extensión". -
Habiendo dicho todo eso, incluso si se corrige todo lo anterior, todavía hay un gran problema con este código que debe abordarse :esta es una operación bastante simple para realizar en T-SQL directo, y hacerlo en SQLCLR es demasiado complicado, más difícil y más costoso de mantener, y mucho más lento. Este código está realizando 10,000 transacciones separadas, mientras que podría realizarse fácilmente como una única consulta basada en conjuntos (es decir, una transacción). Podrías envolver tu
for
bucle en una transacción que la aceleraría, pero siempre será más lento que el enfoque T-SQL basado en conjuntos, ya que aún necesita emitir 10,000INSERT
separados declaraciones. Puede aleatorizar fácilmente en T-SQL usandoNEWID()
o CRYPT_GEN_RANDOM que se introdujo en SQL Server 2008. (consulte la ACTUALIZACIÓN sección a continuación)
Si desea obtener más información sobre SQLCLR, consulte la serie que estoy escribiendo para SQL Server Central: Escalera a SQLCLR (se requiere registro gratuito).
ACTUALIZAR
Aquí hay un método T-SQL puro para generar estos datos aleatorios, usando los valores de la Pregunta. Es fácil agregar nuevos valores a cualquiera de las 4 variables de la tabla (para aumentar el número de combinaciones posibles) ya que la consulta ajusta dinámicamente el rango de aleatorización para adaptarse a cualquier dato que haya en cada variable de la tabla (es decir, filas 1 - n).
DECLARE @TelNumber TABLE (TelNumberID INT NOT NULL IDENTITY(1, 1),
Num VARCHAR(30) NOT NULL);
INSERT INTO @TelNumber (Num) VALUES ('1525407'), ('5423986'), ('1245398'), ('32657891'),
('123658974'), ('7896534'), ('12354698');
DECLARE @FirstName TABLE (FirstNameID INT NOT NULL IDENTITY(1, 1),
Name NVARCHAR(30) NOT NULL);
INSERT INTO @FirstName (Name) VALUES ('Babak'), ('Carolin'), ('Martin'), ('Marie'),
('Susane'), ('Michail'), ('Ramona'), ('Ulf'), ('Dirk'), ('Sebastian');
DECLARE @LastName TABLE (LastNameID INT NOT NULL IDENTITY(1, 1),
Name NVARCHAR(30) NOT NULL);
INSERT INTO @LastName (Name) VALUES ('Bastan'), ('Krause'), ('Rosner'),
('Gartenmeister'), ('Rentsch'), ('Benn'), ('Kycik'), ('Leuoth'),
('Kamkar'), ('Kolaee');
DECLARE @Address TABLE (AddressID INT NOT NULL IDENTITY(1, 1),
Addr NVARCHAR(100) NOT NULL);
INSERT INTO @Address (Addr) VALUES ('Deutschlan Chemnitz Sonnenstraße 59'), (''),
('Deutschland Chemnitz Arthur-Strobel straße 124'),
('Deutschland Chemnitz Brückenstraße 3'),
('Iran Shiraz Chamran Blvd, Niayesh straße Nr.155'), (''),
('Deutschland Berlin Charlotenburg Pudbulesky Alleee 52'),
('United State of America Washington DC. Farbod Alle'), ('');
DECLARE @RowsToInsert INT = 10000;
;WITH rowcounts AS
(
SELECT (SELECT COUNT(*) FROM @TelNumber) AS [TelNumberRows],
(SELECT COUNT(*) FROM @FirstName) AS [FirstNameRows],
(SELECT COUNT(*) FROM @LastName) AS [LastNameRows],
(SELECT COUNT(*) FROM @Address) AS [AddressRows]
), nums AS
(
SELECT TOP (@RowsToInsert)
(CRYPT_GEN_RANDOM(1) % rc.TelNumberRows) + 1 AS [RandomTelNumberID],
(CRYPT_GEN_RANDOM(1) % rc.FirstNameRows) + 1 AS [RandomFirstNameID],
(CRYPT_GEN_RANDOM(1) % rc.LastNameRows) + 1 AS [RandomLastNameID],
(CRYPT_GEN_RANDOM(1) % rc.AddressRows) + 1 AS [RandomAddressID]
FROM rowcounts rc
CROSS JOIN msdb.sys.all_columns sac1
CROSS JOIN msdb.sys.all_columns sac2
)
-- INSERT dbo.Unsprstb(Firstname, Lastname, Tel, Address)
SELECT fn.Name, ln.Name, tn.Num, ad.Addr
FROM @FirstName fn
FULL JOIN nums
ON nums.RandomFirstNameID = fn.FirstNameID
FULL JOIN @LastName ln
ON ln.LastNameID = nums.RandomLastNameID
FULL JOIN @TelNumber tn
ON tn.TelNumberID = nums.RandomTelNumberID
FULL JOIN @Address ad
ON ad.AddressID = nums.RandomAddressID;
Notas:
- La
FULL JOIN
se necesitan s en lugar deINNER JOIN
s para obtener el@RowsToInsert
completo cantidad de filas. - Las filas duplicadas son posibles debido a la naturaleza misma de esta aleatorización Y no filtrarlas usando
DISTINCT
. Sin embargo,DISTINCT
no se puede usar con los datos de muestra proporcionados en la pregunta, ya que la cantidad de elementos en cada matriz/variable de tabla proporciona solo 6300 combinaciones únicas y la cantidad solicitada de filas para generar es 10,000. Si se agregan más valores a las variables de la tabla de modo que el total de combinaciones únicas posibles supere el número solicitado de filas, entoncesDISTINCT
la palabra clave se puede agregar a losnums
CTE, o la consulta se puede reestructurar para simplementeCROSS JOIN
toda la variable de la tabla, incluya unROW_COUNT()
y toma elTOP(n)
usandoORDER BY NEWID()
. - El
INSERT
está comentado para que sea más fácil ver que la consulta anterior produce el resultado deseado. Simplemente descomente elINSERT
para que la consulta realice la operación DML real.