gatilhos T-SQL disparando um “nome da coluna ou número de valores fornecidos não corresponde a definição da tabela” erro

StackOverflow https://stackoverflow.com/questions/95218

  •  01-07-2019
  •  | 
  •  

Pergunta

O Aqui algo que eu não tenho sido capaz de correção, e eu olhei em todos os lugares . Talvez alguém aqui vai saber!

Eu tenho uma tabela chamada dandb_raw, com três colunas em particular: dunsId (PK), nome e searchName. Eu também tenho um gatilho que atua sobre esta tabela:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER TRIGGER [dandb_raw_searchNames]
    ON [dandb_raw]
    FOR INSERT, UPDATE
    AS

SET NOCOUNT ON

  select dunsId, name into #magic from inserted

        UPDATE dandb
            SET dandb.searchName = company_generateSearchName(dandb.name)
            FROM (select dunsId, name from #magic) i
            INNER JOIN dandb_raw dandb
                on i.dunsId = dandb.dunsId


        --Add new search matches
        SELECT c.companyId, dandb.dunsId
            INTO #newMatches
            FROM dandb_raw dandb
            INNER JOIN (select dunsId, name from #magic) a
                on a.dunsId = dandb.dunsId
            INNER JOIN companies c
                ON dandb.searchName = c.searchBrand
                --avoid url matches that are potentially wrong
                AND (lower(dandb.url) = lower(c.url)
                    OR dandb.url = ''
                    OR c.url = ''
                    OR c.url is null)


        INSERT INTO #newMatches (companyId, dunsId)
        SELECT c.companyId, max(dandb.dunsId) dunsId
            FROM dandb_raw dandb
            INNER JOIN
                (
                    select
                    case when charindex('/',url) <> 0 then left(url, charindex('/',url)-1)
                    else url
                    end urlMatch, * from companies
                ) c
                ON dandb.url = c.urlMatch
            where subsidiaryOf = 1 and isReported = 1 and dandb.url <> ''
                and c.companyId not in (select companyId from #newMatches)
            group by companyId
            having count(dandb.dunsId) = 1

        UPDATE cd
            SET cd.dunsId = nm.dunsId
            FROM companies_dandb cd
            INNER JOIN #newMatches nm
                ON cd.companyId = nm.companyId
GO

O gatilho faz com inserções a falhar:

insert into  [dandb_raw](dunsId, name)
    select 3442355, 'harper'
    union all
    select 34425355, 'har 466per'
update [dandb_raw] set name ='grap6767e'

Com este erro:

Msg 213, Level 16, State 1, Procedure companies_contactInfo_updateTerritories, Line 20
Insert Error: Column name or number of supplied values does not match table definition.

O mais curioso sobre isso é que cada uma das afirmações individuais no gatilho trabalha por conta própria. É quase como se inserido é um one-off tabela que infecta as tabelas temporárias se você tentar mover inserido em um deles.

Então, o que faz com que o gatilho para falhar? Como ele pode ser parado?

Foi útil?

Solução

Eu acho que David e Cervo combinados têm hit sobre o problema aqui.

Eu tenho certeza que parte do que estava acontecendo era que estávamos usando #newMatches em vários gatilhos. Quando um gatilho mudou algumas linhas, seria disparar outro gatilho, que iria tentar usar a conexão com escopo #newMatches.

Como resultado, ele iria tentar, encontrar a tabela já existia com um esquema diferente, morrer, e produzir a mensagem acima. Um pedaço de evidência de que seria a favor: Does inserido uso de um escopo estilo pilha (disparadores aninhados têm seus próprios inserteds?)

Ainda especulando embora - pelo menos as coisas parecem estar trabalhando agora

Outras dicas

O que é companies_contactInfo_updateTerritories? A referência real menciona procedimento "companies_contactInfo_updateTerritories" mas eu não vejo isso no código fornecido. Também não vejo onde está sendo chamado. A menos que seja do seu aplicativo que está chamando a SQL e, portanto, irrelevante ....

Se você testou tudo e funcionou, mas agora ele não funciona, então algo deve ser diferente. Uma coisa a considerar é a segurança. Notei que você acabou de chamar a mesa [dandb_raw] e não [dbo]. [Dandb_raw]. Portanto, se o usuário tinha uma tabela com o mesmo nome [usuário]. [Dandb_raw], que a tabela seria usado para verificar as definições em vez da tabela. Além disso, o gatilho cria tabelas temporárias. Mas se algumas das tabelas temporárias já existia por qualquer motivo, mas com definições diferentes, isso também pode ser um problema.

Eu não vejo nenhum problema óbvio no código.

"SELECT .. INTO" é fraco kung-fu. Tente explicitamente a criação da definição tabela temporária:

CREATE TABLE #newMatches
(
  CompanyID int PRIMARY KEY,
  DunsID int
)

Quando você é feito com #newMatches, você deve se livrar dele assim que você pode criá-la novamente mais tarde (tabelas temporárias são ligação com escopo !!)

DROP TABLE #newMatches

código de gatilho (porque ele deve ser executado sempre que o dado é atualizado) deve ser eficiente e deve levar em conta várias inserções recordes. Você conseguiu no segundo, mas não o primeiro. Você fez isso as coisas muito complicadas e usaram como Não em declarações que são geralmente menos efficeint do que usar uma associação à esquerda. tabelas temporárias são desnecessárias aqui (eu nunca iria considerar o uso de um em um gatilho) pois contribuem para a ineficiência do gatilho. Não há razão para não escrever De i inserido ao invés de FROM (seleccionar dunsId, nome de #magic) i

O primeiro é provável que seja mais rápido e é mais fácil de ler e manter.

Aqui: JOIN (select caso quando charindex ( '/', url) <> 0, em seguida, à esquerda (url, charindex ( '/', url) -1) else final url urlMatch, * de empresas) c ON dandb.url = c.urlMatch

Você está selecionando todos os campos na tabela mesmo que você só parecem estar usando um. Por quê? Também estão em execução que stament caso em todos os registros na empresa, mesmo que depois que você entrar, você pode não precisar de todos eles.

Também em I geral seria evitar o uso de select * mas especialmente em um gatilho. Suponha que você está inserindo em outra tabela e você usou select * from alguma tabela se juntou ao inserido ou excluído. Adicionando uma coluna para que a tabela faria com que o gatilho para falhar e parar todas as alterações de dados até que ele foi corrigido.

Você também usei uma função no gatilho. Este coudl ser dolorosamente lento se você havea grande inserção. Eu sugiro que você testar esta atualizando um grande grupo de registros e ver o que acontece. Todas as alterações de dados não acontecem apenas a partir da interface do usuário, um registro de cada vez. Haverá momentos em que um campo é atualizado a partir de uma consulta ad-hoc no estúdio de gestão (quando todos os preços precisam ser ajustados em 10% como o exemplo mais simples que vem à mente.) As suas necessidades de gatilho para ser capaz de lidar com esses tipos se atualizações, bem como os que você está esperando. Eu executar um caso de teste de atualização 100000 linhas e ver o quanto esse gatilho atrasa as coisas.

Talvez isso não é realmente responder o seu problema, mas o gatilho apenas está tão longe de ser ideal, eu tinha que dizê-lo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top