2008-09-18 7 views
5

Oto coś, czego nie udało mi się naprawić, a wyglądam wszędzie wszędzie. Być może ktoś tutaj się dowie!Wyzwalacze T-SQL wyzwalające "Nazwa kolumny lub liczba podanych wartości nie pasuje do definicji tabeli" błąd

Mam tabelę o nazwie dandb_raw, z trzema kolumnami w szczególności: dunsId (PK), name i searchName. Mam też wyzwalacz, który działa na tej tabeli:

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 

Spust powoduje wstawia się nie powiedzie:

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

Z tego błędu:

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. 

Najciekawsze jest to, że każda z indywidualnych instrukcji wyzwalacza działa samodzielnie. To prawie tak, jakby wstawiony był jednorazowym tabelą, która infekuje tymczasowe tabele, jeśli spróbujesz przenieść wstawiony do jednego z nich.

Co powoduje, że wyzwalacz nie działa? Jak można go zatrzymać?

Odpowiedz

2

Myślę, że David i Cervo razem mają tu problem.

Jestem prawie pewien, że częścią tego, co się dzieje, było użycie #newMatches w wielu wyzwaniach. Gdy jeden wyzwalacz zmienił kilka wierszy, uruchomiłby inny wyzwalacz, który próbowałby użyć połączenia o numerze #newMatches.

W rezultacie spróbuje znaleźć tablicę już istniejącą o innym schemacie, umrzeć i wygenerować powyższy komunikat. Jeden dowód, który przemawiałby na korzyść: Czy wstawiony używa zakresu stylów stosu (zagnieżdżone wyzwalacze mają własne wstawki?)

Nadal spekulują - przynajmniej teraz wszystko działa!

+0

Zagnieżdżone wyzwalacze mają swój własny wstawiony magiczny stół. –

1

Co to jest enterprises_contactInfo_updateTerritories? Rzeczywista referencja wspomina procedurę "enterprises_contactInfo_updateTerritories", ale nie widzę jej w podanym kodzie. Również nie widzę, gdzie się nazywa. O ile nie pochodzi to z twojej aplikacji, która wywołuje SQL i dlatego nie ma znaczenia ...

Jeśli wszystko przetestowałeś i zadziałało, ale teraz to nie działa, to coś musi być inne. Jedna rzecz do rozważenia to bezpieczeństwo. Zauważyłem, że po prostu dzwonisz do stołu [dandb_raw], a nie [dbo]. [Dandb_raw]. Więc jeśli użytkownik miał tabelę o tej samej nazwie [użytkownik]. [Dandb_raw], ta tabela będzie używana do sprawdzania definicji zamiast twojej tabeli. Ponadto wyzwalacz tworzy tabele tymczasowe. Ale jeśli niektóre tabele tymczasowe już istniały z jakiegokolwiek powodu, ale z różnymi definicjami, może to być również problem.

+0

To było bardzo przydatne ... Brakowało mi spustu firm_contactInfo_updateTerritories. Zamierzam przyjrzeć się temu dokładniej i sprawdzić, czy uda mi się ustalić problem. – Chris

1

Nie widzę żadnych oczywistych problemów w kodzie.

"SELECT .. INTO" jest słabym kung-fu. Spróbuj jawnie tworzenia definicji tabeli temp:

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

Kiedy skończysz z #newMatches, należy się go pozbyć, więc można utworzyć go ponownie później (tabele tymczasowe są połączenia scoped !!)

DROP TABLE #newMatches 
+0

Należy również rozważyć użycie tabel zmiennych, ponieważ są one zdefiniowane jako zmienne. DECLARE @newMatches TABLE (CompanyId int PRIMARY KEY, DunsId int) –

0

Kod wyzwalacza (ponieważ musi być uruchamiany za każdym razem, gdy dane są aktualizowane) musi być wydajny i musi uwzględniać wiele wstawień rekordu. Udało ci się na drugim, ale nie pierwszym.Zrobiliście to zbyt skomplikowanym i wykorzystaliście takie rzeczy, jak Nie w instrukcjach, które są zwykle mniej skuteczne niż przy użyciu lewego sprzężenia. Tabele tymczasowe są tutaj niepotrzebne (nigdy bym nie rozważył użycia jednego w wyzwalaczu), ponieważ zwiększają one nieefektywność wyzwalacza. Nie ma powodu, aby nie pisać Od włożona i zamiast OD (wybierz dunsId, nazwę od #magic) i

Pierwszym będzie prawdopodobnie szybciej i prościej jest przeczytać i zachować.

tutaj: join (wybierz przypadek kiedy charIndex ('/', url) <> 0 a następnie w lewo (URL, CHARINDEX ('/' url -1)) else koniec url urlMatch, * od firm) C ON dandb.url = c.urlMatch

Wybieracie wszystkie pola w tabeli, mimo że wydaje się, że używacie tylko jednego. Czemu? Prowadzisz również sprawę na wszystkich zapisach w firmie, mimo że po dołączeniu do niej może nie być ich wszystkich.

Również ogólnie unikałbym używania opcji select *, ale szczególnie w wyzwalaczu. Przypuśćmy, że wstawiasz do innej tabeli i użyłeś select * z jakiejś tabeli dołączonej do wstawionej lub usuniętej. Dodanie kolumny do tej tabeli spowoduje, że wyzwalacz ulegnie awarii i zatrzyma wszystkie zmiany danych, dopóki nie zostanie naprawiony.

Użyto również funkcji w wyzwalaczu. Ten coudl będzie boleśnie powolny, jeśli masz dużą wkładkę. Sugeruję, abyś to przetestował, aktualizując dużą grupę rekordów i sprawdzając, co się stanie. Wszystkie zmiany danych nie następują tylko z poziomu interfejsu użytkownika, po jednym rekordzie na raz. Będą chwile, gdy jedno pole zostanie zaktualizowane z zapytania ad-hoc w studio zarządzania (kiedy wszystkie ceny muszą zostać skorygowane o 10% jako najprostszy przykład, jaki przychodzi na myśl.) Twój wyzwalacz musi być w stanie obsłużyć te typy, jeśli aktualizacje, a także te, których się spodziewasz. Uruchomiłbym test case aktualizujący 100000 wierszy i zobacz, jak bardzo ten spust spowalnia działanie.

Może to nie odpowiada na twój problem, ale wyzwalacz jest tak daleki od optymalnego, musiałem to powiedzieć.

+0

W rzeczywistości tabele tymczasowe zniknęły. Nie wiem, do czego służą dodatkowe kolumny, więc też ich nie ma. Ostatecznie musimy uruchomić funkcję w każdym rzędzie. Uzyskaliśmy dobry wskaźnik wydajności, ponieważ ładujemy zbiorczo. Mogę wyłączyć wyzwalacz, jeśli użycie procedury luzem jest szybsze ... – Chris

+0

Czy wykonałbym AKTUALIZACJĘ po tym, jak ładunek zbiorczy byłby szybszy niż równoważny wyzwalacz? – Chris