@Jason Quinonesが言ったように、Transact-SQLはFOR EACH ROW
トリガーをサポートしていません。どちらもサポートしていません。BEFORE
そのため、彼と私の答えの両方がAFTER
トリガーを提供します。実際のところ、INSTEAD OF
T-SQLにはトリガーがあり、トリガーの代わりに使用されることもありBEFORE
ますが、それでも2つはまったく異なります(名前が示すように)。
とにかく、AFTER
トリガーはこの問題に対して完全に機能するはずなので、ここに別のTransact-SQLバージョンがあります。
CREATE TRIGGER locations_format_phone
ON locations
AFTER INSERT, UPDATE
AS
BEGIN
UPDATE locations
SET phone = '(' + STUFF(STUFF(RIGHT('907' + RTRIM(i.phone), 10), 7, 0, '-'), 4, 0, ') ')
FROM inserted AS i
WHERE i.location_id = locations.location_id
AND LEN(i.phone) IN (7, 10)
END
ご覧のとおり、トリガーは、の長さがphone
7文字または10文字の場合にのみ更新を実行します。(したがって、他の長さの値は変更されません。)
値が指定された長さの1つである場合、最初に長さが10であることを確認します。デフォルトの907
プレフィックスが最初に追加され、結果の最後の10文字が取得されます。したがって、メソッドがどのように機能するかを説明するために、元の長さが7の場合、次のようになります。
'907' + '1234567' -> '9071234567' -> '9071234567'
^^^^^^^^^^ (10 chars) (same as before)
そしてそれが10の場合、これは何が起こるかです:
'907' + '1234567890' -> '9071234567890' -> '1234567890'
^^^^^^^^^^ (10 chars) (original value)
次に、STUFF
関数が2回呼び出され、結果の数値の中央にa-
とaが挿入されます。)
挿入位置は変更されていない10桁の数字に関連しているため、-
最初にが挿入され、次に)
(位置のシフトを考慮する必要があります):
#4 #7
| |
v v
0) 'xxxxxxxxxx'
1) 'xxxxxx-xxxx'
2) 'xxx) xxx-xxxx'
最後に、a(
は最初に単純に連結されます。
この問題に関連して覚えておく価値のあるもう1つのことは、同じテーブルを更新するトリガーによって、それ自体が再度起動する可能性があることです。これは、トリガーの再帰AFTER UPDATE
と呼ばれる現象です。トリガー再帰はデフォルトで無効になっていますが、対応するオプションが変更されていないかどうかわからない場合は、現在の状態を確認することをお勧めします。クエリは1つの方法です。sys.databases
SELECT is_recursive_triggers_on
FROM sys.databases
WHERE name = 'your database name'
列と同様is_recursive_triggers_on
に、0はを表し、1はを表します。bit
off
on
上記のトリガーは、無制限の再帰を妨げないように設計されています。ネストされた呼び出しは、ある時点で行の更新を停止しますが(LEN(i.phone) IN (7, 10)
条件がfalse
最終的になるため)、トリガーは引き続き呼び出されます。これを修正するには、最初にこのチェックを追加するだけです。
IF NOT EXISTS (SELECT * FROM inserted)
RETURN
;
再帰トリガーの詳細については、こちらをご覧ください。