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 / 12596
Accepted
Pressacco
Pressacco
Asked: 2012-02-10 13:54:53 +0800 CST2012-02-10 13:54:53 +0800 CST 2012-02-10 13:54:53 +0800 CST

usando *tabelas* como parâmetros com valor de tabela (TVP)

  • 772

O MS SQL 2008 oferece suporte a TVP: um recurso útil para upload de dados em massa para um procedimento armazenado para processamento.

Em vez de criar um tipo definido pelo usuário, é possível aproveitar uma definição de tabela existente? Por exemplo, é possível criar um procedimento armazenado com a seguinte assinatura?

CREATE PROCEDURE usp_InsertProductionLocation
@TVP **LocationTable** READONLY

A documentação parece sugerir que isso não é possível.

CÓDIGO DE AMOSTRA

/*
Sample code from:
http://msdn.microsoft.com/en-us/library/bb510489.aspx
*/

USE AdventureWorks2008R2;
GO

/* Create a table type. */
CREATE TYPE LocationTableType AS TABLE 
( LocationName VARCHAR(50)
, CostRate INT );
GO

/* Create a procedure to receive data for the table-valued parameter. */
CREATE PROCEDURE usp_InsertProductionLocation
    @TVP LocationTableType READONLY
    AS 
    SET NOCOUNT ON
    INSERT INTO [AdventureWorks2008R2].[Production].[Location]
           ([Name]
           ,[CostRate]
           ,[Availability]
           ,[ModifiedDate])
        SELECT *, 0, GETDATE()
        FROM  @TVP;
        GO

/* Declare a variable that references the type. */
DECLARE @LocationTVP 
AS LocationTableType;

/* Add data to the table variable. */
INSERT INTO @LocationTVP (LocationName, CostRate)
    SELECT [Name], 0.00
    FROM 
    [AdventureWorks2008R2].[Person].[StateProvince];

/* Pass the table variable data to a stored procedure. */
EXEC usp_InsertProductionLocation @LocationTVP;
GO

/*
The following is not part of the original source code:
*/

CREATE TABLE LocationTable(
 LocationName VARCHAR(50)
, CostRate INT );
GO
sql-server-2008
  • 3 3 respostas
  • 8663 Views

3 respostas

  • Voted
  1. Best Answer
    Aaron Bertrand
    2012-02-10T16:44:09+08:002012-02-10T16:44:09+08:00

    Não, você não pode aproveitar uma definição de tabela existente, você precisa definir um tipo explícito. Isso foi solicitado em 2007 e foi fechado como "não vai consertar", mas ainda o encorajo fortemente a votar e deixar um comentário descrevendo seu caso de uso e como isso ajudará sua empresa a ser mais produtiva. Você pode até apontar para esta questão para demonstrar como pode ser tedioso tentar automatizar isso.

    • Declare uma variável...(Anteriormente UserVoice #32891356 (Anteriormente Connect #294130))

    Você pode fazer isso hoje, dinamicamente, no entanto... por exemplo, para sua definição simples:

    -- you would pass these two in as parameters of course:
    DECLARE
      @TableName SYSNAME = N'LocationTable',
      @TypeName  SYSNAME = N'LocationTypeTable';
    
    DECLARE @sql NVARCHAR(MAX) = N'';
    
    SELECT @sql = @sql + N',' + CHAR(13) + CHAR(10) + CHAR(9) 
        + QUOTENAME(c.name) + ' '
        + s.name + CASE WHEN LOWER(s.name) LIKE '%char' THEN 
            '(' + CONVERT(VARCHAR(12), (c.max_length/
            (CASE LOWER(LEFT(s.name, 1)) WHEN N'n' THEN 2 ELSE 1 END))) + ')' 
            ELSE '' END
            -- need much more conditionals here for other data types
        FROM sys.columns AS c
        INNER JOIN sys.types AS s
        ON c.system_type_id = s.system_type_id
        AND c.user_type_id = s.user_type_id
        WHERE c.[object_id] = OBJECT_ID(@TableName);
    
    SELECT @sql = N'CREATE TYPE ' + @TypeName
        + ' AS TABLE ' + CHAR(13) + CHAR(10) + '(' + STUFF(@sql, 1, 1, '')
        + CHAR(13) + CHAR(10) + ');';
    
    PRINT @sql;
    -- EXEC sp_executesql @sql;
    

    Resultados:

    CREATE TYPE LocationTypeTable AS TABLE 
    (
        [LocationName] varchar(50),
        [CostRate] int
    );
    

    Isenção de responsabilidade: isso não lida com todos os tipos de outras coisas, como tipos MAX, precisão e escala para números etc.

    No SQL Server 2012, há novos DMVs e procedimentos armazenados que tornarão muito mais fácil derivar metadados de colunas de tabelas existentes (ou procedimentos armazenados ou até mesmo consultas ad hoc) sem ter que mexer com toda a lógica condicional contra sys.types e sys. colunas. Fiz um breve blog sobre essas melhorias em dezembro . Ainda é tedioso, mas está em algum lugar entre o terrível espaguete insustentável acima e a capacidade de apenas dizer "como cópia da [tabela x]"...

    • 19
  2. Jiten
    2014-03-29T21:14:02+08:002014-03-29T21:14:02+08:00

    Lidei com esse problema criando o seguinte procedimento armazenado para criar um tipo com o mesmo esquema que a tabela existente pode ter.

    CREATE PROCEDURE [dbo].[Sp_DefineTypeOutOfTableSchema] --or e.g. usp_DefineTypeFromTable
    @TableNames NVARCHAR(500)
    AS
    BEGIN
    
    DECLARE @TableName NVARCHAR(100)
    DECLARE @strSQL NVARCHAR(max)
    DECLARE @strSQLCol NVARCHAR(1000)
    DECLARE @ColName NVARCHAR(100)
    DECLARE @ColDataTaype NVARCHAR(50)
    DECLARE @ColDefault NVARCHAR(50)
    DECLARE @ColIsNulable NVARCHAR(50)
    DECLARE @ColFirst NVARCHAR(50)
    DECLARE @ColSecond NVARCHAR(50)
    DECLARE @ColID NVARCHAR(50)
    DECLARE @ColCompute NVARCHAR(50)
    
    IF LEN(@TableNames) > 0 SET @TableNames = @TableNames + ',' 
    WHILE LEN(@TableNames) > 0 
        BEGIN
            SELECT @TableName = TRIM(LEFT(@TableNames, CHARINDEX(',', @TableNames) - 1))
            DECLARE schemaCur CURSOR FOR 
                SELECT 
                    c.name as column_name,
                    t.name as [type_name],
                    c.is_nullable,
                    convert(nvarchar(4000), object_definition(ColumnProperty(c.object_id, c.name, 'default'))) as column_default,
                    CASE
                        WHEN c.collation_name IS NOT NULL THEN c.max_length 
                        WHEN t.name like 'datetime%' THEN c.scale
                        WHEN c.scale = 0 THEN NULL
                        ELSE c.precision
                    END as firstValue,
                    CASE
                        WHEN (c.scale = 0 or t.name like 'datetime%') THEN NULL
                        ELSE c.scale
                    END as secondValue,
                    c.is_identity, -- would be best to know seed,increment
                    c.is_computed -- should really look up col definition. `convert(nvarchar(4000), object_definition(ColumnProperty(c.object_id, c.name, 'computed')))` as computed ?
    
                FROM sys.columns as c join 
                     sys.all_objects as o 
                        on c.object_id=o.object_id join
                     sys.types as t
                        on c.user_type_id=t.user_type_id
                WHERE
                    o.type in ('U','V','TF','IF','TT') and --'S' to include built-in tables/types
                    o.name = @TableName
                ORDER BY o.name, c.column_id
            OPEN schemaCur
            SELECT @strSQL=''
            FETCH NEXT FROM schemaCur
                INTO @ColName,@ColDataTaype,@ColIsNulable,@ColDefault,@ColFirst,@ColSecond,@ColID,@ColCompute
            WHILE @@FETCH_STATUS = 0 BEGIN
    --            SELECT @strSQLCol=''
                SELECT @strSQLCol= '['+@ColName+'] '+'[' + @ColDataTaype +'] '
                IF @ColSecond is NULL
                    BEGIN
                        IF @ColFirst is not NULL SELECT @strSQLCol += '(' + @ColFirst + ') '
                    END 
                ELSE SELECT @strSQLCol += '(' + @ColFirst +',' +@ColSecond + ') '
                IF @ColID>0 SELECT @strSQLCol += ' IDENTITY(1,1)'
                IF @ColIsNulable>0 SELECT @strSQLCol += 'NULL'
                    ELSE SELECT @strSQLCol += ' NOT NULL'
                IF @ColDefault IS NOT NULL SELECT @strSQLCol += ' DEFAULT(' +@ColDefault + '),'
                    ELSE SELECT @strSQLCol += ','
                SELECT @strSQL += @strSQLCol
                    --print @strSQL
                FETCH NEXT FROM schemaCur
                INTO @ColName,@ColDataTaype,@ColIsNulable,@ColDefault,@ColFirst,@ColSecond,@ColID,@ColCompute
            END
    
            CLOSE schemaCur
            DEALLOCATE schemaCur
    
            SELECT @strSQL=left(@strSQL, len(@strSQL)-1)
    
            IF EXISTS (SELECT * FROM sys.types WHERE IS_TABLE_TYPE = 1 AND name = 'tt_' +@TableName)
            BEGIN           
                EXEC('DROP TYPE tt_' +@TableName )
            END
    
            SELECT @strSQL = 'CREATE TYPE tt_' + @TableName + ' AS TABLE (' +  @strSQL + ')'
            -- print @strSQL
            EXEC (@strSQL)
            SELECT @TableNames = SUBSTRING(@TableNames, CHARINDEX(',', @TableNames) + 1, LEN(@TableNames))
        END
    END
    

    você pode usar assim

    Exec Sp_DefineTypeOutOfTableSchema 'Table1name,Table2name'

    • 4
  3. Andrei Rînea
    2012-02-28T01:36:47+08:002012-02-28T01:36:47+08:00

    Erland Sommarskog tem um extenso artigo descrevendo como usar o TVP.

    Dê uma olhada, vale a pena!

    Resumindo, você não pode usar um tipo existente, assim como a resposta anterior de Aaron Bertrand . Mas pelo menos é uma transferência em massa.

    • 3

relate perguntas

  • Melhores práticas para conectar bancos de dados que estão em diferentes regiões geográficas

  • 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?

  • 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