Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Msg 6522, предупреждение от ниво 16 по време на изпълнение на съхранена процедура clr

В този код възникват няколко проблема, които трябва да бъдат решени:

  1. По отношение на посочения въпрос, когато получите System.Security.SecurityException грешка, която се отнася до кода, който се опитва да достигне извън базата данни, нещо, което не е разрешено в SAFE монтаж. Как ще поправите това зависи от това, което се опитвате да постигнете.

    • Ако се опитвате да осъществите достъп до файловата система, да прочетете от системния регистър, да получите променлива на средата, да получите достъп до мрежата за връзка, различна от SQL Server (напр. http, ftp) и т.н., тогава асемблирането се нуждае от PERMISSION_SET от EXTERNAL_ACCESS . За да настроите сборката си на нещо различно от SAFE , трябва да:
      • Създайте сертификат или асиметричен ключ въз основа на същия ключ, който сте използвали за подписване на вашата сборка (т.е. дайте му силно име), създайте вход въз основа на този сертификат или асиметричен ключ и след това предоставете EXTERNAL ACCESS ASSEMBLY разрешение за това влизане. Този метод е чудесен предпочитан пред другия метод, който е:
      • Настройте базата данни, съдържаща сборката, на TRUSTWORTHY ON . Този метод трябва да се използва само в краен случай, ако не е възможно да се подпише сборката. Или за целите на бързото тестване. Задаване на база данни на TRUSTWORTHY ON отваря екземпляра ви за потенциални заплахи за сигурността и трябва да се избягва, дори ако е по-бърз/лесен от другия метод.
    • Ако се опитвате да получите достъп до екземпляра на SQL Server, в който вече сте влезли, тогава имате опцията да използвате връзката в процеса на Context Connection = true; което може да се направи в SAFE монтаж. Това предложи @Marc в своя отговор. Въпреки че определено има предимства от използването на този тип връзка и докато контекстната връзка беше подходящият избор в този конкретен сценарий, е прекалено опростено и неправилно да се твърди, че трябва винаги използвайте този тип връзка. Нека да разгледаме положителните и отрицателните аспекти на контекстната връзка :

      • Положителни:
        • Може да се направи в SAFE монтаж.
        • Много ниско, ако има такова, натоварване на връзката, тъй като това не е допълнителна връзка.
        • Е част от текущата сесия, така че всеки SQL, който изпълнявате, има достъп до елементи, базирани на сесия, като локални временни таблици и CONTEXT_INFO .
      • Негативи:

        • Не може да се използва, ако имитацията е активирана.
        • Може да се свързва само с текущия екземпляр на SQL Server.
        • Когато се използва във функции (скаларни и с таблични стойности), той има всички същите ограничения, които имат T-SQL функциите (напр. не са разрешени операции със страничен ефект), освен че можете да изпълнявате съхранени процедури само за четене.
        • На функциите с таблични стойности не е разрешено да предават своите резултати обратно, ако прочетат набор от резултати.

        Всички тези „негативи“ са разрешени при използване на обикновена/външна връзка, дори ако е към същия екземпляр, от който изпълнявате този код.

  2. Ако се свързвате към екземпляра, от който изпълнявате този код, и използвате външна/обикновена връзка, тогава няма нужда да посочвате името на сървъра или дори да използвате localhost . Предпочитаният синтаксис е Server = (local) който използва споделена памет, докато другите може понякога да използват TCP/IP, което не е толкова ефективно.

  3. Освен ако нямате много конкретна причина да го направите, не използвайте Persist Security Info=True;

  4. Добра практика е Dispose() на вашия SqlCommand

  5. По-ефективно е да извикате insertcommand.Parameters.Add() точно преди for цикъл и след това вътре в цикъла просто задайте стойността чрез firstname.Value = , което вече правите, така че просто преместете insertcommand.Parameters.Add() редове точно преди for ред.

  6. tel / @tel / listtelnumber са INT вместо VARCHAR / string . Телефонните номера, също като пощенските кодове и социалноосигурителните номера (SSN), не числа, дори ако изглеждат такива. INT не може да съхранява водещ 0 s или нещо като ex. за означаване на „разширение“.

  7. Като се има предвид всичко това, дори всичко по-горе да бъде коригирано, все още има огромен проблем с този код, който трябва да се реши :това е доста опростена операция за изпълнение в прав T-SQL и правенето на това в SQLCLR е прекалено сложно, по-трудно и по-скъпо за поддръжка и много по-бавно. Този код изпълнява 10 000 отделни транзакции, докато може толкова лесно да се направи като една заявка, базирана на набор (т.е. една транзакция). Можете да опаковате своя for цикъл в транзакция, което би я ускорило, но все пак винаги ще бъде по-бавно от базирания на набор T-SQL подход, тъй като все още трябва да издаде 10 000 отделни INSERT изявления. Можете лесно да рандомизирате в T-SQL, като използвате NEWID() или CRYPT_GEN_RANDOM който беше въведен в SQL Server 2008. (моля, вижте АКТУАЛИЗАЦИЯ раздел по-долу)

Ако искате да научите повече за SQLCLR, моля, разгледайте поредицата, която пиша за SQL Server Central: Стълбище към SQLCLR (изисква се безплатна регистрация).

АКТУАЛИЗАЦИЯ

Ето един чист T-SQL метод за генериране на тези произволни данни, като се използват стойностите от въпроса. Лесно е да добавите нови стойности към която и да е от 4-те променливи на таблицата (за да увеличите броя на възможните комбинации), тъй като заявката динамично настройва диапазона на рандомизиране, за да пасне на каквито и да е данни във всяка променлива на таблицата (т.е. редове 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;

Бележки:

  • FULL JOIN s са необходими вместо INNER JOIN s, за да получите целия @RowsToInsert количество редове.
  • Възможни са дублиращи се редове поради самото естество на тази рандомизация И не филтрирането им с помощта на DISTINCT . Въпреки това, DISTINCT не може да се използва с дадените примерни данни във въпроса, тъй като броят на елементите във всяка променлива на масив / таблица осигурява само 6300 уникални комбинации, а заявеният брой редове за генериране е 10 000. Ако към променливите на таблицата се добавят повече стойности, така че общият брой възможни уникални комбинации да се повиши над заявения брой редове, тогава или DISTINCT ключова дума може да се добави към nums CTE или заявката може да бъде преструктурирана просто до CROSS JOIN цялата променлива на таблицата включва ROW_COUNT() и вземете TOP(n) използвайки ORDER BY NEWID() .
  • INSERT е коментиран, така че е по-лесно да се види, че заявката по-горе дава желания резултат. Просто премахнете коментара от INSERT за да накарате заявката да извърши действителната DML операция.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Не може да разреши конфликта на съпоставяне между SQL_AltDiction_CP850_CI_AS и SQL_Latin1_General_CP1_CI_AS в операцията равно на

  2. Проблем с Sql функция Последният оператор, включен във функция, трябва да бъде оператор за връщане

  3. Общ табличен израз, защо точка и запетая?

  4. Изпълнение на SQL DELETE

  5. Актуализирайте полето varbinary(MAX) в SQLServer 2012 Загубени последните 4 бита