Триггеры T-SQL выдают ошибку «Имя столбца или количество предоставленных значений не соответствует определению таблицы» - PullRequest
5 голосов
/ 18 сентября 2008

Вот то, что я не смог исправить, и я посмотрел везде . Возможно, кто-то здесь узнает!

У меня есть таблица с именем dandb_raw, с тремя столбцами, в частности: dunsId (PK), name и searchName. У меня также есть триггер, который действует на эту таблицу:

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

Триггер вызывает сбой вставки:

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

С этой ошибкой:

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.

Самое любопытное в этом то, что каждое из отдельных утверждений в триггере работает само по себе. Это почти как если бы вставленная была одноразовой таблицей, которая заражает временные таблицы, если вы пытаетесь переместить вставленную в одну из них.

Так, что вызывает отказ триггера? Как это можно остановить?

Ответы [ 4 ]

2 голосов
/ 18 сентября 2008

Я думаю, что Дэвид и Черво вместе решают эту проблему.

Я почти уверен, что часть того, что происходило, заключалась в том, что мы использовали #newMatches в нескольких триггерах. Когда один триггер изменил несколько строк, он запустит другой триггер, который попытается использовать область действия соединения # newMatches.

В результате он попытается найти уже существующую таблицу с другой схемой, умрет и выдаст сообщение выше. Одно из доказательств, которое было бы в пользу: использует ли вставленная область стека (вложенные триггеры имеют свои собственные вставки?)

Тем не менее, все еще спекулируют - по крайней мере, сейчас все работает!

1 голос
/ 18 сентября 2008

Я не вижу очевидной проблемы в коде.

«ВЫБРАТЬ. В» - это слабое кунг-фу. Попробуйте явно создать определение временной таблицы:

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

Когда вы закончите с #newMatches, вы должны избавиться от него, чтобы вы могли создать его позже (временные таблицы имеют границы соединения !!)

DROP TABLE #newMatches
1 голос
/ 18 сентября 2008

Что такое companies_contactInfo_updateTerritories? Фактическая ссылка упоминает процедуру "companies_contactInfo_updateTerritories", но я не вижу ее в приведенном коде. Также я не вижу, где это называется. Если это не из вашего приложения, которое вызывает SQL и, следовательно, не имеет значения ....

Если вы проверили все, и это работало, но теперь это не работает, тогда что-то должно быть по-другому. Одна вещь, чтобы рассмотреть это безопасность. Я заметил, что вы просто вызываете таблицу [dandb_raw], а не [dbo]. [Dandb_raw]. Поэтому, если у пользователя есть таблица с тем же именем [user]. [Dandb_raw], эта таблица будет использоваться для проверки определений вместо вашей таблицы. Также триггер создает временные таблицы. Но если некоторые временные таблицы уже существуют по какой-либо причине, но с другими определениями, это также может быть проблемой.

0 голосов
/ 20 сентября 2008

Триггерный код (потому что он должен запускаться при каждом обновлении данных) должен быть эффективным и должен учитывать несколько вставок записей. Вы преуспели на втором, но не первом. Вы сделали это слишком сложным и использовали такие вещи, как Not в выражениях, которые обычно менее эффективны, чем использование левого соединения. Временные таблицы здесь не нужны (я бы никогда не подумал об их использовании в триггере), поскольку они увеличивают неэффективность триггера. Нет причин не писать Из вставленного я вместо ОТ (выберите dunsId, имя из #magic) i

Первый, скорее всего, будет быстрее, его проще читать и обслуживать.

Здесь: JOIN (выберите случай, когда charindex ('/', url) <> 0 затем слева (url, charindex ('/', url) -1), иначе url end urlMatch, * из компаний) c ON dandb.url = c.urlMatch

Вы выбираете все поля в таблице, даже если вы используете только одно из них. Зачем? Вы также ведете эту регистрационную запись по всем записям в компании, хотя после присоединения вам могут не понадобиться все из них.

Также в целом я бы избегал использовать select *, но особенно в триггере. Предположим, вы вставляете в другую таблицу и используете select * из некоторой таблицы, присоединенной к вставленной или удаленной. Добавление столбца к этой таблице вызовет сбой триггера и остановит все изменения данных, пока он не будет исправлен.

Вы также использовали функцию в триггере. Это может быть мучительно медленно, если у вас есть большой вкладыш. Я предлагаю вам проверить это, обновив большую группу записей и посмотреть, что произойдет. Все изменения данных происходят не только из пользовательского интерфейса, по одной записи за раз. Будут времена, когда одно поле обновляется из специального запроса в Management Studio (когда все цены должны быть скорректированы на 10%, как самый простой пример, который приходит на ум.) Ваш триггер должен быть в состоянии обрабатывать эти типы, если обновления, а также те, которые вы ожидаете. Я бы запустил тестовый пример, обновляющий 100000 строк, и увидел бы, насколько сильно этот триггер замедляет работу.

Возможно, это не совсем отвечает вашей проблеме, но триггер просто далек от оптимального, я должен был это сказать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...