sql >> Database teknologi >  >> RDS >> Sqlserver

Msg 6522, niveau 16 advarsel under udførelse af clr lagret procedure

Der er flere problemer i gang i denne kode, som skal løses:

  1. Med hensyn til det angivne spørgsmål, når du får en System.Security.SecurityException fejl, der henviser til koden, der forsøger at nå uden for databasen, noget der ikke er tilladt i en SAFE montage. Hvordan du løser dette, afhænger af, hvad du forsøger at opnå.

    • Hvis du forsøger at få adgang til filsystemet, læse fra registreringsdatabasen, hente en miljøvariabel, få adgang til netværket for en ikke-SQL-serverforbindelse (f.eks. http, ftp) osv., så skal samlingen have en PERMISSION_SET af EXTERNAL_ACCESS . For at indstille din samling til noget andet end SAFE , skal du enten:
      • Opret et certifikat eller en asymmetrisk nøgle baseret på den samme nøgle, som du brugte til at underskrive din samling (dvs. giv den et stærkt navn), opret et login baseret på det pågældende certifikat eller den asymmetriske nøgle, og giv derefter EKSTERN ADGANG MONTERING tilladelse til det pågældende login. Denne metode er meget foretrækkes frem for den anden metode, som er:
      • Indstil databasen, der indeholder samlingen til TRUSTWORTHY ON . Denne metode bør kun bruges som en sidste udvej, hvis det ikke er muligt at underskrive forsamlingen. Eller til hurtige testformål. Indstilling af en database til TRUSTWORTHY ON åbner din instans op for potentielle sikkerhedstrusler og bør undgås, selvom det er hurtigere/lettere end den anden metode.
    • Hvis du forsøger at få adgang til den SQL Server-instans, som du allerede er logget på, så har du mulighed for at bruge den igangværende forbindelse af Context Connection =true; hvilket kan gøres i en SAFE montage. Dette er, hvad @Marc foreslog i sit svar. Selvom der helt sikkert er fordele ved at bruge denne type forbindelse, og selvom kontekstforbindelsen var det passende valg i dette særlige scenarie, er det alt for forsimplet og forkert at sige, at du altid skal bruge denne type forbindelse. Lad os se på de positive og negative aspekter af Kontekstforbindelsen :

      • Positivt:
        • Kan gøres i en SAFE samling.
        • Meget lave, hvis nogen, forbindelsesomkostninger, da det ikke er en ekstra forbindelse.
        • Er en del af den aktuelle session, så enhver SQL, du udfører, har adgang til sessionsbaserede elementer såsom lokale midlertidige tabeller og CONTEXT_INFO .
      • Negativer:

        • Kan ikke bruges, hvis personefterligning er blevet aktiveret.
        • Kan kun oprette forbindelse til den aktuelle SQL Server-instans.
        • Når den bruges i funktioner (skalær og tabelværdi), har den alle de samme begrænsninger, som T-SQL-funktioner har (f.eks. er der ingen bivirkninger tilladt), bortset fra at du kan udføre skrivebeskyttede lagrede procedurer.
        • Tabelværdierede funktioner har ikke tilladelse til at streame deres resultater tilbage, hvis de læser et resultatsæt.

        Alle disse "negative" er tilladt, når du bruger en almindelig/ekstern forbindelse, selvom det er til den samme instans, du udfører denne kode fra.

  2. Hvis du opretter forbindelse til den instans, som du udfører denne kode fra og bruger en ekstern / almindelig forbindelse, behøver du ikke angive servernavnet eller endda bruge localhost . Den foretrukne syntaks er Server =(lokal) som bruger delt hukommelse, mens de andre nogle gange bruger TCP/IP, hvilket ikke er så effektivt.

  3. Medmindre du har en meget specifik grund til at gøre det, skal du ikke bruge Persist Security Info=True;

  4. Det er en god praksis at Dispose() af din SqlCommand

  5. Det er mere effektivt at kalde insertcommand.Parameters.Add() lige før for løkke, og derefter inde i løkken, skal du blot indstille værdien via firstname.Value = , hvilket du allerede gør, så flyt bare insertcommand.Parameters.Add() linjer til lige før for linje.

  6. tlf / @tel / listenummer er INT i stedet for VARCHAR / streng . Telefonnumre, ligesom postnumre og socialsikringsnumre (SSN'er), er ikke tal, selvom de ser ud til at være det. INT kan ikke gemme førende 0 s eller noget som ex. for at betegne en "udvidelse".

  7. Når alt dette er sagt, selvom alt ovenstående er rettet, er der stadig et stort problem med denne kode, som bør løses :dette er en ret forenklet operation at udføre i lige T-SQL, og at gøre dette i SQLCLR er overkompliceret, sværere og dyrere at vedligeholde og meget langsommere. Denne kode udfører 10.000 separate transaktioner, hvorimod den så let kunne udføres som en enkelt sæt-baseret forespørgsel (dvs. én transaktion). Du kan pakke din til sløjfe i en transaktion, som ville fremskynde den, men den vil stadig altid være langsommere end den sæt-baserede T-SQL-tilgang, da den stadig skal udstede 10.000 separate INSERT udsagn. Du kan nemt randomisere i T-SQL ved at bruge enten NEWID() eller CRYPT_GEN_RANDOM som blev introduceret i SQL Server 2008. (se venligst OPDATERING afsnit nedenfor)

Hvis du vil lære mere om SQLCLR, så tjek venligst serien, jeg skriver til SQL Server Central: Trappe til SQLCLR (gratis registrering påkrævet).

OPDATERING

Her er en ren T-SQL-metode til at generere disse tilfældige data ved hjælp af værdierne fra spørgsmålet. Det er nemt at tilføje nye værdier til enhver af de 4 tabelvariabler (for at øge antallet af mulige kombinationer), da forespørgslen dynamisk justerer randomiseringsområdet, så det passer til de data, der er i hver tabelvariabel (dvs. række 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;

Bemærkninger:

  • FULD JOIN s er nødvendige i stedet for INNER JOIN s for at få hele @RowsToInsert antal rækker.
  • Duplikerede rækker er mulige på grund af selve arten af ​​denne randomisering OG ikke filtrering af dem ved at bruge DISTINCT . Dog DISTINCT kan ikke bruges med de givne eksempeldata i spørgsmålet, da antallet af elementer i hver array/tabelvariabel kun giver 6300 unikke kombinationer, og det ønskede antal rækker, der skal genereres, er 10.000. Hvis flere værdier tilføjes til tabelvariablerne, således at det samlede antal mulige unikke kombinationer stiger over det anmodede antal rækker, skal enten DISTINCT nøgleord kan tilføjes til nums CTE, eller forespørgslen kan omstruktureres til blot at CROSS JOIN alle tabelvariabler, inkludere en ROW_COUNT() feltet, og tag fat i TOP(n) ved hjælp af ORDER BY NEWID() .
  • INSERT er kommenteret ud, så det er nemmere at se, at forespørgslen ovenfor giver det ønskede resultat. Bare fjern kommentaren til INSERT for at få forespørgslen til at udføre den faktiske DML-operation.


  1. Få optegnelser over den aktuelle måned

  2. At iterere et ResultSet ved hjælp af JDBC for Oracle tager meget tid omkring 16s?

  3. Kan ikke oprette forbindelse til '/var/run/mysqld/mysqld.sock'

  4. Syntaksfejl ved eller nær END med kolonnenavn END