Det finns flera problem som pågår i den här koden som måste åtgärdas:
-
Angående den angivna frågan, när du får en System.Security.SecurityException fel, som hänvisar till koden som försöker nå utanför databasen, något som inte är tillåtet i en
SAFE
hopsättning. Hur du åtgärdar detta beror på vad du försöker åstadkomma.- Om du försöker komma åt filsystemet, läsa från registret, hämta en miljövariabel, få åtkomst till nätverket för en icke-SQL-serveranslutning (t.ex. http, ftp), etc, så behöver sammansättningen en
PERMISSION_SET
avEXTERNAL_ACCESS
. För att ställa in din assembly på något annat änSAFE
måste du antingen:- Skapa ett certifikat eller asymmetrisk nyckel baserat på samma nyckel som du använde för att signera din sammansättning (dvs. ge den ett starkt namn), skapa en inloggning baserat på det certifikatet eller asymmetriska nyckeln och ge sedan
EXTERN ÅTKOMST MONTERING behörighet att logga in. Den här metoden är mycket föredras framför den andra metoden, som är: - Ställ in databasen som innehåller sammansättningen till
TRUSTWORTHY ON
. Denna metod bör endast användas som en sista utväg om det inte är möjligt att signera sammansättningen. Eller för snabba teständamål. Ställer in en databas påTRUSTWORTHY ON
öppnar din instans för potentiella säkerhetshot och bör undvikas, även om det är snabbare/enklare än den andra metoden.
- Skapa ett certifikat eller asymmetrisk nyckel baserat på samma nyckel som du använde för att signera din sammansättning (dvs. ge den ett starkt namn), skapa en inloggning baserat på det certifikatet eller asymmetriska nyckeln och ge sedan
-
Om du försöker komma åt SQL Server-instansen som du redan är inloggad på, har du möjlighet att använda den pågående anslutningen av
Context Connection =true;
vilket kan göras i enSAFE
hopsättning. Detta är vad @Marc föreslog i sitt svar. Även om det definitivt finns fördelar med att använda den här typen av anslutning, och även om kontextanslutningen var det lämpliga valet i det här specifika scenariot, är det alltför förenklat och felaktigt att säga att du alltid ska använd denna typ av anslutning. Låt oss titta på de positiva och negativa aspekterna av Kontextkopplingen :- Positivt:
- Kan göras i en
SAFE
montering. - Mycket låg, om någon, anslutningskostnad eftersom det inte är en extra anslutning.
- Är en del av den aktuella sessionen så att alla SQL du kör har tillgång till sessionsbaserade objekt som lokala temporära tabeller och
CONTEXT_INFO
.
- Kan göras i en
-
Negativa:
- Kan inte användas om identitetsstöld har aktiverats.
- Kan bara ansluta till den aktuella SQL Server-instansen.
- När den används i funktioner (skalär och tabellvärderad) har den samma begränsningar som T-SQL-funktioner har (t.ex. inga sidoverkande operationer är tillåtna) förutom att du kan köra skrivskyddade lagrade procedurer.
- Tabellvärderade funktioner får inte streama sina resultat tillbaka om de läser en resultatuppsättning.
Alla dessa "negativa" är tillåtna när du använder en vanlig/extern anslutning, även om det är till samma instans som du kör den här koden från.
- Positivt:
- Om du försöker komma åt filsystemet, läsa från registret, hämta en miljövariabel, få åtkomst till nätverket för en icke-SQL-serveranslutning (t.ex. http, ftp), etc, så behöver sammansättningen en
-
Om du ansluter till instansen som du kör den här koden från och använder en extern/vanlig anslutning behöver du inte ange servernamnet eller ens använda
localhost
. Den föredragna syntaxen ärServer =(lokal)
som använder delat minne medan de andra ibland kan använda TCP/IP som inte är lika effektivt. -
Använd inte
Persist Security Info=True;
om du inte har en mycket specifik anledning till att göra det. -
Det är en god praxis att
Kassera()
av dittSqlCommand
-
Det är mer effektivt att anropa
insertcommand.Parameters.Add()
precis föreför
loop, och sedan inuti loopen, ställ helt enkelt in värdet viafirstname.Value =
, vilket du redan gör, så flytta barainsertcommand.Parameters.Add()
rader till strax föreför
rad. -
tel
/@tel
/listtelnummer
ärINT
istället förVARCHAR
/sträng
. Telefonnummer, precis som postnummer och personnummer (SSN), är inte siffror, även om de verkar vara det.INT
kan inte lagra inledande0
s eller något somex.
för att beteckna en "förlängning". -
Allt detta sagt, även om allt ovan är korrigerat, finns det fortfarande ett stort problem med den här koden som bör åtgärdas :detta är en ganska förenklad operation att utföra i rak T-SQL, och att göra detta i SQLCLR är alltför komplicerat, svårare och dyrare att underhålla och mycket långsammare. Den här koden utför 10 000 separata transaktioner medan den så lätt kan göras som en enda uppsättningsbaserad fråga (dvs en transaktion). Du kan slå in din
för
slinga i en transaktion som skulle påskynda den, men den kommer fortfarande alltid att vara långsammare än den uppsättningsbaserade T-SQL-metoden eftersom den fortfarande behöver utfärda 10 000 separataINSERT
uttalanden. Du kan enkelt randomisera i T-SQL genom att använda antingenNEWID()
eller CRYPT_GEN_RANDOM som introducerades i SQL Server 2008. (se UPPDATERING avsnitt nedan)
Om du vill lära dig mer om SQLCLR, kolla in serien jag skriver för SQL Server Central: Trappa till SQLCLR (gratis registrering krävs).
UPPDATERA
Här är en ren T-SQL-metod för att generera denna slumpmässiga data, med hjälp av värdena från frågan. Det är lätt att lägga till nya värden till någon av de fyra tabellvariablerna (för att öka antalet möjliga kombinationer) eftersom frågan dynamiskt justerar randomiseringsintervallet för att passa vilken data som finns i varje tabellvariabel (d.v.s. rad 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;
Anmärkningar:
FULL JOIN
s behövs istället förINNER JOIN
s för att få hela@RowsToInsert
antal rader.- Duplicerade rader är möjliga på grund av själva karaktären av denna randomisering OCH att inte filtrera bort dem med
DISTINCT
. MenDISTINCT
kan inte användas med givna exempeldata i frågan eftersom antalet element i varje array/tabellvariabel endast ger 6300 unika kombinationer och det begärda antalet rader att generera är 10 000. Om fler värden läggs till i tabellvariablerna så att det totala antalet möjliga unika kombinationer stiger över det begärda antalet rader, kan antingenDISTINCT
nyckelord kan läggas till inums
CTE, eller frågan kan omstruktureras till att helt enkeltCROSS JOIN
all tabellvariabel, inkluderar enROW_COUNT()
och ta tag iTOP(n)
medORDER BY NEWID()
. INSERT kommenteras bort så att det är lättare att se att frågan ovan ger önskat resultat. Kommentera bara INSERT
för att få frågan att utföra den faktiska DML-operationen.