5

これは私が修正できなかったものであり、あらゆる場所を見てきました。ここならわかる人もいるかも!

dandb_raw という名前のテーブルがあり、特に 3 つの列があります: 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.

これに関する最も興味深い点は、トリガー内の個々のステートメントがそれぞれ独自に機能することです。挿入されたテーブルの 1 つに挿入されたものを移動しようとすると、一時テーブルに感染する 1 回限りのテーブルであるかのようです。

では、トリガーが失敗する原因は何でしょうか? どうすれば止められますか?

4

4 に答える 4

2

DavidとCervoを合わせて、ここで問題が発生したと思います。

起こっていたことの一部は、複数のトリガーで#newMatchesを使用していたことだと確信しています。1つのトリガーがいくつかの行を変更すると、別のトリガーが起動され、接続スコープの#newMatchesを使用しようとします。

その結果、別のスキーマですでに存在しているテーブルを見つけて停止し、上記のメッセージを生成しようとします。支持される証拠の1つ:挿入はスタックスタイルのスコープを使用しますか(ネストされたトリガーには独自の挿入がありますか?)

しかし、まだ推測しています-少なくとも今はうまくいっているようです!

于 2008-09-18T19:07:23.443 に答える
1

コードに明らかな問題は見当たりません。

「SELECT .. INTO」は弱いカンフーです。一時テーブル定義を明示的に作成してみてください。

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

#newMatches を使い終わったら、後でもう一度作成できるように、それを削除する必要があります (一時テーブルはコネクション スコープです!!)

DROP TABLE #newMatches
于 2008-09-18T19:04:06.137 に答える
1

company_contactInfo_updateTerritories とは何ですか? 実際の参照では、手順「companies_contactInfo_updateTerritories」に言及していますが、指定されたコードには表示されません。また、どこで呼び出されているのかわかりません。SQLを呼び出しているアプリケーションからのものでない限り、無関係なので....

すべてをテストしてうまくいったのに、今はうまくいかない場合は、何かが違うはずです。考慮すべきことの 1 つは、セキュリティです。[dbo].[dandb_raw] ではなく、テーブル [dandb_raw] を呼び出していることに気付きました。したがって、ユーザーが [user].[dandb_raw] という同じ名前のテーブルを持っていた場合、テーブルの代わりにそのテーブルが定義のチェックに使用されます。また、トリガーは一時テーブルを作成します。ただし、何らかの理由で定義が異なる一時テーブルがすでに存在している場合、これも問題になる可能性があります。

于 2008-09-18T18:49:47.760 に答える
0

トリガー コード (データが更新されるたびに実行する必要があるため) は効率的で、複数のレコード挿入に対応する必要があります。2 回目は成功しましたが、1 回目では成功しませんでした。これを過度に複雑にし、ステートメントで Not などを使用しましたが、通常は左結合を使用するよりも効率的ではありません。一時テーブルは、トリガーの非効率性を増すため、ここでは不要です (トリガーで一時テーブルを使用することは考えません)。FROM (select dunsId, name from #magic) i の代わりに From Inserted i を書かない理由はありません。

前者の方が高速で、読み取りと保守が簡単です。

ここで: 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

1 つしか使用していないように見えますが、テーブル内のすべてのフィールドを選択しています。なんで?また、入社後はすべてのレコードが必要ない場合でも、会社のすべてのレコードでそのケースステートメントを実行しています。

また、一般的に select * の使用は避けますが、特にトリガーでは使用しません。別のテーブルに挿入していて、select * from some table join to insert または deleted を使用したとします。そのテーブルに列を追加すると、トリガーが失敗し、修正されるまですべてのデータ変更が停止します。

また、トリガーで関数を使用しました。大きなインサートがある場合、これは非常に遅くなる可能性があります。多数のレコードを更新してこれをテストし、何が起こるかを確認することをお勧めします。すべてのデータ変更は、一度に 1 レコードずつ、ユーザー インターフェイスからだけ行われるわけではありません。管理スタジオのアドホック クエリから 1 つのフィールドが更新される場合があります (思いつく最も単純な例として、すべての価格を 10% 調整する必要がある場合)。次の場合、トリガーはこれらのタイプを処理できる必要があります。アップデートだけでなく、あなたが期待しているもの。100000 行を更新するテスト ケースを実行し、このトリガーがどれだけ速度を低下させるかを確認します。

たぶん、これはあなたの問題に本当に答えているわけではありませんが、トリガーは最適とはほど遠いので、私はそれを言わなければなりませんでした.

于 2008-09-19T21:49:25.503 に答える