sql >> Databáze >  >> RDS >> Sqlserver

Msg 6522, varování úrovně 16 během provádění uložené procedury clr

V tomto kódu probíhá několik problémů, které je třeba vyřešit:

  1. 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 z EXTERNAL_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 na TRUSTWORTHY 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.
    • 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 v SAFE 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 .
      • 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.

  2. 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 je Server = (local) který používá sdílenou paměť, zatímco ostatní mohou někdy používat TCP/IP, což není tak efektivní.

  3. Pokud k tomu nemáte zcela konkrétní důvod, nepoužívejte Persist Security Info=True;

  4. Je dobrým zvykem Dispose() vašeho SqlCommand

  5. Je efektivnější volat insertcommand.Parameters.Add() těsně před for smyčky a poté uvnitř smyčky jednoduše nastavte hodnotu pomocí firstname.Value = , kterou již provádíte, takže stačí přesunout insertcommand.Parameters.Add() řádky těsně před for řádek.

  6. tel / @tel / listtelnumber jsou INT místo VARCHAR / 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 jako ex. znamenat "prodloužení".

  7. 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ých INSERT 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ísto INNER 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 do nums CTE, nebo lze dotaz restrukturalizovat na jednoduše CROSS JOIN všechny proměnné tabulky obsahují ROW_COUNT() a uchopte TOP(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čí odkomentovat INSERT aby dotaz provedl skutečnou operaci DML.


  1. Jak tento web opravuje kódování?

  2. Vypočítaná hodnota pole na základě jiného sloupce při vkládání

  3. MariaDB JSON_COMPACT() vysvětleno

  4. Získejte záznamy za aktuální měsíc