V tomto kódu probíhá několik problémů, které je třeba vyřešit:
-
Pokud jde o uvedenou otázku, když získáte System.Security.SecurityException chyba, která odkazuje na kód, který se pokouší dostat mimo databázi, něco, co není povoleno v
SAFE
shromáždění. Jak to napravíte, závisí na tom, čeho se snažíte dosáhnout.- Pokud se pokoušíte přistupovat k systému souborů, číst z registru, získat proměnnou prostředí, přistupovat k síti pro připojení jiného než SQL Server (např. http, ftp) atd., pak sestavení potřebuje
PERMISSION_SET
zEXTERNAL_ACCESS
. Chcete-li nastavit sestavu na cokoli jiného nežSAFE
, musíte buď:- Vytvořte certifikát nebo asymetrický klíč na základě stejného klíče, který jste použili k podpisu sestavy (tj. dejte mu silný název), vytvořte přihlášení na základě tohoto certifikátu nebo asymetrického klíče a poté udělte
EXTERNAL ACCESS ASSEMBLY
povolení k tomuto přihlášení. Tato metoda je skvělá upřednostňována před druhou metodou, kterou je: - Nastavte databázi obsahující sestavení na
TRUSTWORTHY ON
. Tato metoda by měla být vždy použita pouze jako poslední možnost, pokud není možné podepsat shromáždění. Nebo pro účely rychlého testování. Nastavení databáze naTRUSTWORTHY ON
otevírá vaši instanci potenciálním bezpečnostním hrozbám a je třeba se jim vyhnout, i když je to rychlejší / jednodušší než druhá metoda.
- Vytvořte certifikát nebo asymetrický klíč na základě stejného klíče, který jste použili k podpisu sestavy (tj. dejte mu silný název), vytvořte přihlášení na základě tohoto certifikátu nebo asymetrického klíče a poté udělte
-
Pokud se pokoušíte přistupovat k instanci serveru SQL, ke které jste již přihlášeni, máte možnost použít připojení v procesu
Context Connection = true;
což lze provést vSAFE
shromáždění. To je to, co @Marc navrhl ve své odpovědi. I když používání tohoto typu připojení rozhodně přináší výhody, a přestože kontextové připojení bylo v tomto konkrétním scénáři vhodnou volbou, je příliš zjednodušené a nesprávné tvrdit, že byste měli vždy použijte tento typ připojení. Podívejme se na pozitivní a negativní aspekty Kontextového spojení :- Pozitivní:
- Lze provést v
SAFE
sestavení. - Velmi nízké, pokud vůbec nějaké, režie připojení, protože se nejedná o další připojení.
- Je součástí aktuální relace, takže každý SQL, který spustíte, má přístup k položkám založeným na relaci, jako jsou místní dočasné tabulky a
CONTEXT_INFO
.
- Lze provést v
-
Zápory:
- Nelze použít, pokud bylo povoleno zosobnění.
- Lze se připojit pouze k aktuální instanci SQL Server.
- Při použití ve funkcích (skalární a tabulkové) má všechna stejná omezení jako funkce T-SQL (např. nejsou povoleny žádné operace s vedlejšími efekty), kromě toho, že můžete spouštět uložené procedury pouze pro čtení.
- Funkce s hodnotou tabulky nemají povoleno streamovat své výsledky zpět, pokud čtou sadu výsledků.
Všechny tyto „zápory“ jsou povoleny při použití běžného / externího připojení, i když se jedná o stejnou instanci, ze které spouštíte tento kód.
- Pozitivní:
- Pokud se pokoušíte přistupovat k systému souborů, číst z registru, získat proměnnou prostředí, přistupovat k síti pro připojení jiného než SQL Server (např. http, ftp) atd., pak sestavení potřebuje
-
Pokud se připojujete k instanci, ze které spouštíte tento kód, a používáte externí / běžné připojení, není třeba zadávat název serveru nebo dokonce používat
localhost
. Preferovaná syntaxe jeServer = (local)
který používá sdílenou paměť, zatímco ostatní mohou někdy používat TCP/IP, což není tak efektivní. -
Pokud k tomu nemáte zcela konkrétní důvod, nepoužívejte
Persist Security Info=True;
-
Je dobrým zvykem
Dispose()
vašehoSqlCommand
-
Je efektivnější volat
insertcommand.Parameters.Add()
těsně předfor
smyčky a poté uvnitř smyčky jednoduše nastavte hodnotu pomocífirstname.Value =
, kterou již provádíte, takže stačí přesunoutinsertcommand.Parameters.Add()
řádky těsně předfor
řádek. -
tel
/@tel
/listtelnumber
jsouINT
místoVARCHAR
/string
. Telefonní čísla, stejně jako PSČ a čísla sociálního zabezpečení (SSN), nejsou čísla, i když se zdá, že jsou.INT
nelze uložit úvodní0
s nebo něco jakoex.
znamenat "prodloužení". -
Vše, co bylo řečeno, i když je vše výše uvedené opraveno, stále existuje obrovský problém s tímto kódem, který je třeba vyřešit :toto je poněkud zjednodušující operace, kterou lze provádět v přímém T-SQL, a provádění této operace v SQLCLR je příliš komplikované, obtížnější a nákladnější na údržbu a mnohem pomalejší. Tento kód provádí 10 000 samostatných transakcí, zatímco jej lze tak snadno provést jako jeden dotaz založený na sadě (tj. jedna transakce). Můžete zabalit
for
smyčka v transakci, která by ji urychlila, ale stále bude vždy pomalejší než přístup T-SQL založený na sadě, protože stále potřebuje vydat 10 000 samostatnýchINSERT
prohlášení. V T-SQL můžete snadno randomizovat pomocíNEWID()
nebo CRYPT_GEN_RANDOM který byl představen v SQL Server 2008. (viz AKTUALIZACE sekce níže)
Pokud se chcete dozvědět více o SQLCLR, podívejte se prosím na sérii, kterou píšu pro SQL Server Central: Schodiště do SQLCLR (vyžadována bezplatná registrace).
AKTUALIZACE
Zde je čistá metoda T-SQL pro generování těchto náhodných dat pomocí hodnot z otázky. Je snadné přidat nové hodnoty do kterékoli ze 4 proměnných tabulky (pro zvýšení počtu možných kombinací), protože dotaz dynamicky upravuje rozsah randomizace tak, aby odpovídal všem datům, která jsou v každé proměnné tabulky (tj. řádky 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;
Poznámky:
FULL JOIN
s jsou potřeba místoINNER JOIN
s získat celý@RowsToInsert
počet řádků.- Duplicitní řádky jsou možné díky samotné povaze tohoto náhodného uspořádání a neodfiltrování pomocí
DISTINCT
. NicméněDISTINCT
nelze použít s danými ukázkovými daty v otázce, protože počet prvků v každé proměnné pole / tabulky poskytuje pouze 6300 jedinečných kombinací a požadovaný počet řádků k vygenerování je 10 000. Pokud je do proměnných tabulky přidáno více hodnot tak, že celkový počet možných jedinečných kombinací přesáhne požadovaný počet řádků, pak buďDISTINCT
klíčové slovo lze přidat donums
CTE, nebo lze dotaz restrukturalizovat na jednodušeCROSS JOIN
všechny proměnné tabulky obsahujíROW_COUNT()
a uchopteTOP(n)
pomocíORDER BY NEWID()
. - Položka
INSERT
je zakomentován, takže je snazší vidět, že výše uvedený dotaz poskytuje požadovaný výsledek. Stačí odkomentovatINSERT
aby dotaz provedl skutečnou operaci DML.