Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Msg 6522, aviso de nível 16 durante a execução do procedimento armazenado clr


Há vários problemas acontecendo neste código que precisam ser resolvidos:

  1. Em relação à pergunta declarada, quando você recebe uma System.Security.SecurityException erro, que se refere ao código tentando alcançar fora do banco de dados, algo que não é permitido em um SAFE conjunto. Como você corrige isso depende do que você está tentando realizar.
    • Se você estiver tentando acessar o sistema de arquivos, ler do registro, obter uma variável de ambiente, acessar a rede para uma conexão não-SQL Server (por exemplo, http, ftp), etc, o assembly precisa de um PERMISSION_SET de EXTERNAL_ACCESS . Para definir seu assembly para algo diferente de SAFE , você precisa:
      • Crie um certificado ou chave assimétrica com base na mesma chave que você usou para assinar seu assembly (ou seja, dê um nome forte), crie um login com base nesse certificado ou chave assimétrica e conceda o EXTERNAL ACCESS ASSEMBLY permissão para esse Login. Este método é muito preferido sobre o outro método, que é:
      • Defina o banco de dados que contém o assembly para TRUSTWORTHY ON . Este método só deve ser usado como último recurso se não for possível assinar o assembly. Ou para fins de teste rápido. Configurando um banco de dados para TRUSTWORTHY ON abre sua instância para possíveis ameaças de segurança e deve ser evitada, mesmo que seja mais rápido/fácil do que o outro método.

    • Se você estiver tentando acessar a instância do SQL Server na qual já está conectado, terá a opção de usar a conexão em processo de Context Connection = true; que pode ser feito em um SAFE conjunto. Isso é o que @Marc sugeriu em sua resposta. Embora haja definitivamente benefícios em usar esse tipo de conexão, e embora a Conexão de Contexto tenha sido a escolha apropriada nesse cenário específico, é muito simplista e incorreto afirmar que você deve sempre usar este tipo de conexão. Vejamos os aspectos positivos e negativos da Conexão de contexto :
      • Positivos:
        • Pode ser feito em um SAFE montagem.
        • Muito baixa, se houver, sobrecarga de conexão, pois não é uma conexão adicional.
        • Faz parte da sessão atual para que qualquer SQL que você execute tenha acesso a itens baseados em sessão, como tabelas temporárias locais e CONTEXT_INFO .

      • Negativos:
        • Não pode ser usado se a representação estiver ativada.
        • Só pode se conectar à instância atual do SQL Server.
        • Quando usado em funções (escalar e com valor de tabela), ele tem todas as mesmas restrições que as funções T-SQL têm (por exemplo, nenhuma operação de efeito colateral é permitida), exceto que você pode executar procedimentos armazenados somente leitura.
        • >
        • As funções com valor de tabela não têm permissão para transmitir seus resultados de volta se lerem um conjunto de resultados.

        Todos esses "negativos" são permitidos ao usar uma conexão regular/externa, mesmo que seja para a mesma instância da qual você está executando este código.

  2. Se você estiver se conectando à instância da qual está executando este código e usando uma conexão externa/regular, não será necessário especificar o nome do servidor ou mesmo usar localhost . A sintaxe preferida é Server = (local) que usa Memória Compartilhada enquanto os outros às vezes podem usar TCP/IP que não é tão eficiente.

  3. A menos que você tenha um motivo muito específico para fazer isso, não use Persist Security Info=True;

  4. É uma boa prática Dispose() do seu SqlCommand

  5. É mais eficiente chamar o insertcommand.Parameters.Add() logo antes do for loop e, em seguida, dentro do loop, basta definir o valor por meio de firstname.Value = , o que você já está fazendo, então apenas mova o insertcommand.Parameters.Add() linhas imediatamente antes do for linha.

  6. tel / @tel / listtelnumber são INT em vez de VARCHAR / string . Números de telefone, assim como CEPs e Números de Seguro Social (SSNs), não números, mesmo que pareçam ser. INT não é possível armazenar o 0 inicial s ou algo como ex. para significar uma "extensão".

  7. Tudo isso dito, mesmo que todos os itens acima sejam corrigidos, ainda há um grande problema com este código que deve ser resolvido :esta é uma operação bastante simplista para executar em T-SQL direto, e fazer isso em SQLCLR é muito complicado, mais difícil e mais caro de manter e muito mais lento. Este código está realizando 10.000 transações separadas, enquanto poderia ser feito tão facilmente como uma única consulta baseada em conjunto (ou seja, uma transação). Você pode envolver seu for loop em uma transação que a aceleraria, mas ainda será sempre mais lenta do que a abordagem T-SQL baseada em conjunto, pois ainda precisa emitir 10.000 INSERT separados declarações. Você pode facilmente randomizar em T-SQL usando NEWID() ou CRYPT_GEN_RANDOM que foi introduzido no SQL Server 2008. (consulte o UPDATE seção abaixo)

Se você quiser saber mais sobre SQLCLR, confira a série que estou escrevendo para o SQL Server Central: Escadaria para SQLCLR (inscrição gratuita obrigatória).

ATUALIZAÇÃO

Aqui está um método T-SQL puro de gerar esses dados aleatórios, usando os valores da pergunta. É fácil adicionar novos valores a qualquer uma das 4 variáveis ​​da tabela (para aumentar o número de combinações possíveis), pois a consulta ajusta dinamicamente o intervalo de randomização para ajustar os dados em cada variável da tabela (ou seja, linhas 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;

Notas:
  • O FULL JOIN s são necessários em vez de INNER JOIN s para obter todo o @RowsToInsert quantidade de linhas.
  • Linhas duplicadas são possíveis devido à própria natureza dessa randomização E não filtrá-las usando DISTINCT . No entanto, DISTINCT não pode ser usado com os dados de amostra fornecidos na pergunta, pois o número de elementos em cada variável de matriz/tabela fornece apenas 6.300 combinações únicas e o número solicitado de linhas a serem geradas é 10.000. Se mais valores forem adicionados às variáveis ​​da tabela de forma que o total de combinações únicas possíveis fique acima do número de linhas solicitado, então o DISTINCT palavra-chave pode ser adicionada ao nums CTE, ou a consulta pode ser reestruturada para simplesmente CROSS JOIN todas as variáveis ​​da tabela, inclua um ROW_COUNT() campo e pegue o TOP(n) usando ORDER BY NEWID() .
  • O INSERT é comentada para que seja mais fácil ver que a consulta acima produz o resultado desejado. Apenas descomente o INSERT para que a consulta faça a operação DML real.