AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 12139
Accepted
billinkc
billinkc
Asked: 2012-02-03 11:38:12 +0800 CST2012-02-03 11:38:12 +0800 CST 2012-02-03 11:38:12 +0800 CST

sp_executesql com o tipo de tabela definido pelo usuário não se comportando corretamente

  • 772

Problema

Existe um problema conhecido com tipos de tabela definidos pelo usuário como parâmetros para sp_executesql ?

Configurar script

Este script cria uma tabela, um procedimento e um tipo de tabela definido pelo usuário (restrito somente SQL Server 2008+).

  • A finalidade do heap é fornecer uma auditoria de que sim, os dados foram inseridos no procedimento. Não há restrições, nem nada que impeça a inserção de dados.
  • O procedimento toma como parâmetro um tipo de tabela definido pelo usuário. Tudo o que o proc faz é inserir na tabela.
  • O tipo de tabela definido pelo usuário também é muito simples, apenas uma única coluna

Eu executei o seguinte contra 11.0.1750.32 (X64) e 10.0.4064.0 (X64)Sim, eu sei que a caixa pode ser corrigida, eu não controlo isso.

-- this table record that something happened
CREATE TABLE dbo.UDTT_holder
(
    ServerName varchar(200)
,   insert_time datetime default(current_timestamp)
)
GO

-- user defined table type transport mechanism
CREATE TYPE dbo.UDTT
AS TABLE
(
    ServerName varchar(200)
)
GO

-- Stored Procedure to reproduce issue
CREATE PROCEDURE dbo.Repro
(
    @MetricData dbo.UDTT READONLY
)
AS
BEGIN
    SET NOCOUNT ON

    INSERT INTO dbo.UDTT_holder 
    (ServerName)
    SELECT MD.* FROM @MetricData MD
END
GO

Reprodução de problemas

Este script demonstra o problema e deve levar cinco segundos para ser executado. Eu crio duas instâncias de meus tipos de tabela definidos pelo usuário e, em seguida, tento dois meios diferentes de passá-los para sp_executesql O mapeamento de parâmetro na primeira invocação imita o que capturei do SQL Profiler. Em seguida, chamo o procedimento sem o wrapper sp_executesql.

SET NOCOUNT ON
DECLARE 
    @p3 dbo.UDTT
,   @MetricData dbo.UDTT
INSERT INTO @p3 VALUES(N'SQLB\SQLB')
INSERT INTO @MetricData VALUES(N'SQLC\SQLC')

-- nothing up my sleeve
SELECT * FROM dbo.UDTT_holder

SELECT CONVERT(varchar(24), current_timestamp, 121) + ' Firing sp_executesql' AS commentary
-- This does nothing
EXECUTE sp_executesql N'dbo.Repro',N'@MetricData dbo.UDTT READONLY',@MetricData=@p3
-- makes no matter if we're mapping variables
EXECUTE sp_executesql N'dbo.Repro',N'@MetricData dbo.UDTT READONLY',@MetricData

-- Five second delay
waitfor delay '00:00:05'
SELECT CONVERT(varchar(24), current_timestamp, 121) + ' Firing proc' AS commentary
-- this does
EXECUTE dbo.Repro @p3

-- Should only see the latter timestamp
SELECT * FROM dbo.UDTT_holder

GO

Resultados

Abaixo estão meus resultados. A tabela está inicialmente vazia. Eu emito a hora atual e faço as duas chamadas para sp_executesql. Aguardo 5 segundos para passar e emito o tempo atual, seguido de chamada do próprio procedimento armazenado e, finalmente, despejo a tabela de auditoria.

Como você pode ver no carimbo de data/hora, o registro para o registro B corresponde à invocação direta do procedimento armazenado. Além disso, não há nenhum registro SQLC.

ServerName                                       insert_time
------------------------------------------------------------------------

commentary
-------------------------------------------------
2012-02-02 13:09:05.973 Firing sp_executesql

commentary
-------------------------------------------------
2012-02-02 13:09:10.983 Firing proc

ServerName                                       insert_time
------------------------------------------------------------------------
SQLB\SQLB                                        2012-02-02 13:09:10.983

Derrubar roteiro

Este script remove os objetos na ordem correta (você não pode descartar o tipo antes que a referência do procedimento tenha sido removida)

-- cleanup
DROP TABLE dbo.UDTT_holder
DROP PROCEDURE dbo.Repro
DROP TYPE dbo.UDTT
GO

Por que isso importa

O código parece bobo, mas não tenho muito controle sobre o uso do sp_execute versus uma chamada "direta" para o proc. Mais acima na cadeia de chamadas, estou usando a biblioteca ADO.NET e transmitindo um TVP como fiz anteriormente . O tipo do parâmetro está definido corretamente como System.Data.SqlDbType.Structured e o CommandType está definido como System.Data.CommandType.StoredProcedure .

sql-server sql-server-2008
  • 3 3 respostas
  • 7780 Views

3 respostas

  • Voted
  1. Best Answer
    Rob Farley
    2012-02-03T15:19:33+08:002012-02-03T15:19:33+08:00

    sp_executesqlé para executar ad-hoc T-SQL. Então você deve tentar:

    EXECUTE sp_executesql N'exec dbo.Repro @MetricData',N'@MetricData dbo.UDTT READONLY',@MetricData=@p3
    
    • 11
  2. billinkc
    2012-02-04T07:53:06+08:002012-02-04T07:53:06+08:00

    Fiquei tentado a excluir esta pergunta, mas imaginei que outra pessoa poderia passar por uma situação semelhante.

    Notas de resolução

    Rob e Martin Smith (resposta excluída 10k+) viram o que eu não estava vendo - a instrução passada para sp_executesql não usava o @MetricDataparâmetro. Um parâmetro mapeado/não aprovado não será usado.

    A causa principal foi que eu $updateCommandnão havia definido o CommandType. O valor padrão é Text, então meu procedimento armazenado estava sendo chamado corretamente. Meus parâmetros estavam sendo criados e passados, mas conforme observado nas outras respostas, apenas porque os parâmetros estão disponíveis não significa que eles estão sendo usados .

    Código caso alguém se interesse pelo meu erro

        $updateConnection = New-Object System.Data.SqlClient.SqlConnection("Data Source=localhost\localsqla;Initial Catalog=baseline;Integrated Security=SSPI;")
        $updateConnection.Open()
    
        $updateCommand = New-Object System.Data.SqlClient.SqlCommand($updateQuery)
        $updateCommand.Connection = $updateConnection
    
        # This is what I was missing
        $updateCommand.CommandType = [System.Data.CommandType]::StoredProcedure
        #$updateCommand.CommandType = [System.Data.CommandType]::Text
        #$updateCommand.CommandType = [System.Data.CommandType]::TableDirect
    
        $DataTransferFormat = $updateCommand.Parameters.AddWithValue("@MetricData", $dataTable)
        $DataTransferFormat.SqlDbType = [System.Data.SqlDbType]::Structured
        $DataTransferFormat.TypeName = $udtt
        $results = $updateCommand.ExecuteNonQuery()
    

    A execução com um valor de CommandType de Text exigiria a solução de @rob_farley de alterar o valor de $updateQuerypara "EXEC dbo.Repro @MetricData". Nesse ponto, o sp_executesql mapeará os valores corretamente e a vida estará boa.

    A execução com um CommandTypeof TableDirectnão é suportada pelo SqlClient Data Provider, como indica a documentação.

    O uso CommandTypede StoredProceduretraduz-se em uma invocação direta do procedimento armazenado sem o sp_executesqlwrapper e funciona muito bem.

    • 4
  3. MPost
    2021-05-02T21:17:28+08:002021-05-02T21:17:28+08:00

    Eu tive um problema semelhante e a resposta aceita acima QUASE funcionou. No entanto, eu precisava me qualificar totalmente com o nome do banco de dados. Eu precisava de algo assim:

     EXECUTE sp_executesql N'exec mydb.myschema.Repro @MetricData',N'@MetricData mydb.myschema.UDTT READONLY',@MetricData=@p3
    

    No meu caso, não estava usando 'dbo', então pode ser necessário apenas nesse caso.

    • 0

relate perguntas

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Quanto "Padding" coloco em meus índices?

  • Existe um processo do tipo "práticas recomendadas" para os desenvolvedores seguirem para alterações no banco de dados?

  • Como determinar se um Índice é necessário ou necessário

  • Downgrade do SQL Server 2008 para 2005

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como ver a lista de bancos de dados no Oracle?

    • 8 respostas
  • Marko Smith

    Quão grande deve ser o mysql innodb_buffer_pool_size?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    restaurar a tabela do arquivo .frm e .ibd?

    • 10 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Como selecionar a primeira linha de cada grupo?

    • 6 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve