PDA

View Full Version : Trigger زمانی که تنها یه فیلد خاص تغییر کند



golnaz_a
پنج شنبه 03 اردیبهشت 1394, 10:55 صبح
سلام دوستان
من یک جدول به صورت زیر دارم:
id Value
----------- -----------
100 1
400 2
200 3



می خوام اگر فقط مثلا فیلد value با id =1 تغییر کرد trigger من اجرا بشه و مثلا یه table رو update کنه اگر فیلد value با بقیه id ها تغییر کرد نمی خوام این triger اجرا بشه
لطفا اگر کسی از دوستان راه حلی برای این مسئله داره کمک کنه
ممنون

pezhvakco
پنج شنبه 03 اردیبهشت 1394, 19:37 عصر
شاید

Create TRIGGER dbo.Triggers_Name
ON dbo.Table_Name
AFTER INSERT,UPDATE
AS
BEGIN

SET NOCOUNT ON;

if EXISTS(select id from inserted where inserted.id = 1)
/*
Run Command
*/
END

golnaz_a
جمعه 04 اردیبهشت 1394, 09:40 صبح
ممنون دوست عزیز اما کد شما در صورت تغییر هر کدام از value ها اجرا میشه چون همیشه id=1 وجود دارد

alireza_s_84
جمعه 04 اردیبهشت 1394, 10:25 صبح
سلام دوستان
من یک جدول به صورت زیر دارم:
id Value
----------- -----------
100 1
400 2
200 3



می خوام اگر فقط مثلا فیلد value با id =1 تغییر کرد trigger من اجرا بشه و مثلا یه table رو update کنه اگر فیلد value با بقیه id ها تغییر کرد نمی خوام این triger اجرا بشه
لطفا اگر کسی از دوستان راه حلی برای این مسئله داره کمک کنه
ممنون

چیزی که به ذهن من میرسه اینه:
شما یک جدول Log برای همون جدول مورد نظرتون بسازید. بعد هروقت جدول اصلی آپدیت شد و رکورد با Id=1 هم به روز شد شما تغییرات رو توی جدول Log درج کنید. حالا تریگر خودتون رو روی جدول Log اعمال کنید. اینطوری تریگر فقط زمانی اجرا میشه که طبق خواسته شماست.

SabaSabouhi
جمعه 04 اردیبهشت 1394, 11:23 صبح
ممنون دوست عزیز اما کد شما در صورت تغییر هر کدام از value ها اجرا میشه چون همیشه id=1 وجود دارد

سلام
1. اگه تریگر بنویسی حتماً همیشه اجرا می‌شه.
2. دوستمون pezhvakco راه حل مناسب رو برای مساله‌ی شما ارائه کرده، اگه دنبال راه حل هستی که می‌تونی به راحتی ازش استفاده کنی.
3. صورت مساله اصولاً درست نیست. چرا باید فقط برای کد 1 اجرا بشه، اصولاً به این کار می‌گن HardCode و اگه اشتباه نکنم اولین چیزی که
تو برنامه نویسی پیشرفته باید به دانش‌جو یاد بدن این هست که تو برنامه نویسی این کار مثل «گناه» می‌مونه.
4. و به هیچ عنوان دنبال راه حل‌هایی مثل چیزی که دوستمون alireza_s_84 نوشته هم نرو، چون اگه وارد این مسیر از برنامه نویسی بشی،
به هیچ جای خوبی نمی‌رسی.

به‌تر بود صورت مساله واقعی رو بیان می‌کردی تا دوستان راه حل مناسب و صحیح رو بهت پیش‌نهاد بدن.

صبا صبوحی

golnaz_a
جمعه 04 اردیبهشت 1394, 12:00 عصر
مسئله اینجاست که من در جدول اول یک سری واحد پول دارم مثلا دلار ، یورو و قیمت روز این واحد های پول را نگهداری می کنم در جدول دوم هم قیمت محصولات در یک ستون به دلار هست و در یک ستون به ریال می خواهم اگر فقط قیمت دلار تغییر کرد جدول اول تغییر کرد با محاسباتی بتونم قیمت محصول را در جدول دوم به روز کنم
البته می تونم یک trigger بنویسم که فقط روی تغییر ستون value فایر بشه و بعد هم توی یک where بگم فقط فلان فیلد منو در محاسبات دخیل کن ولی در این صورت هر تغییری در ستون value باعث میشه که trigger من فایر بشه حالا چه دلار تغییر کنه چه یورو
من به دنبال راه حل بهینه هستم و کلا کنجکاوم بدونم توی trigger میشه اینکارو کرد یا خیر

alireza_s_84
جمعه 04 اردیبهشت 1394, 21:02 عصر
و به هیچ عنوان دنبال راه حل‌هایی مثل چیزی که دوستمون alireza_s_84 نوشته هم نرو، چون اگه وارد این مسیر از برنامه نویسی بشی،
به هیچ جای خوبی نمی‌رسی.

لطفا در مورد ایرادات روش ارائه شده توضیح بدین!!!

SabaSabouhi
شنبه 05 اردیبهشت 1394, 06:54 صبح
لطفا در مورد ایرادات روش ارائه شده توضیح بدین!!!

سلام
دوست عزیز، تو نیت خیر شما شکی نیست. اما دوستمون golnaz_a واقعاً نیازش این نیست که تریگرش درست کار کنه. اصلاً راه رو داره
اشتباه می‌ره. من و شما باید روشنش کنیم که مسیر رو درست بره و نه این که کار اشتباهش رو چطوری ظاهراً درست کنه.
اگه قرار به این روش‌ باشه باید برای هر چند تا جدول، چند تا هم جدول برای تصحیح اطلاعاتش اضافه کنه.
من منظورم ناراحت کردن شما نبود، اگه نوشته‌ی من باعث ناراحتی شما شده باشه، من عذرخواهی می‌کنم.

صبا صبوحی

SabaSabouhi
شنبه 05 اردیبهشت 1394, 06:59 صبح
مسئله اینجاست که من در جدول اول یک سری واحد پول دارم مثلا دلار ، یورو و قیمت روز این واحد های پول را نگهداری می کنم در جدول دوم هم قیمت محصولات در یک ستون به دلار هست و در یک ستون به ریال می خواهم اگر فقط قیمت دلار تغییر کرد جدول اول تغییر کرد با محاسباتی بتونم قیمت محصول را در جدول دوم به روز کنم
البته می تونم یک trigger بنویسم که فقط روی تغییر ستون value فایر بشه و بعد هم توی یک where بگم فقط فلان فیلد منو در محاسبات دخیل کن ولی در این صورت هر تغییری در ستون value باعث میشه که trigger من فایر بشه حالا چه دلار تغییر کنه چه یورو
من به دنبال راه حل بهینه هستم و کلا کنجکاوم بدونم توی trigger میشه اینکارو کرد یا خیر

سلام
همانطور که گمان برده بودم، مسیر رو داری اشتباه می‌ری. هیچ کس با یه تریگر داده رو اصلاح نمی‌کنه.
اگه می‌خوای قیمت ریالی در زمان خرید رو نگهداری کنی که هیچ. ( در این صورت نیازی به اصلاح هم وجود نداره )
اما اگه می‌خوای قیمت فروش رو بر حسب ریال و متناسب با قیمت روز دلار نگهداری کنی، این اشتباه هست.
بجای «نگهداری»، «نمایش» بده.
یعنی هنگام نمایش با یه join قیمت ریالی رو محاسبه کن و نمایش بده.
نگهداری اطلاعاتی که لحظه به لحظه در حال تغییر هست، کاملاً اشتباه هست.
پرسیدی که تو تریگر می‌شه یا نه. جواب مثبت هست. بله می‌شه، اما اشتباهه. مثل اینه که بپرسی سوپ رو می‌شه با چنگال خورد یا نه.
هر ابرازی برای کار خاصی هست و برای این نیاز شما ابزار مناسب join هست و نه تریگر.
شما تو جدول محصولات در کنار ستون مبلغ، یه ستون نوع ارز هم بگذار و بر حسب همون ستون به جدول قیمت لحظه‌ای ارزها وصل شو
و محاسبه قیمت ریالی رو انجام بده.

صبا صبوحی

alireza_s_84
شنبه 05 اردیبهشت 1394, 09:27 صبح
سلام
دوست عزیز، تو نیت خیر شما شکی نیست. اما دوستمون golnaz_a واقعاً نیازش این نیست که تریگرش درست کار کنه. اصلاً راه رو داره
اشتباه می‌ره. من و شما باید روشنش کنیم که مسیر رو درست بره و نه این که کار اشتباهش رو چطوری ظاهراً درست کنه.
اگه قرار به این روش‌ باشه باید برای هر چند تا جدول، چند تا هم جدول برای تصحیح اطلاعاتش اضافه کنه.
من منظورم ناراحت کردن شما نبود، اگه نوشته‌ی من باعث ناراحتی شما شده باشه، من عذرخواهی می‌کنم.

صبا صبوحی
دوست عزیز من اصلا از پاسخ شما ناراحت نشدم فقط پرسیدم ایرادات روش کار من چیه. چون برخی مواقع پیش میاد که تریگر روی یک رکورد با شناسه خاص اجرا بشه و این هیچ ایرادی نداره که شما یک جدول Log برای تغییرات داشته باشین بخصوص اینکه لاگ کردن اون تغییرات مهم هم باشه.
ولی در کل اگر نیاز باشه تا اجرای یک Trigger مشروط باشه میشه از روش زیر هم استفاده کرد:

CREATE TRIGGER
[dbo].[AdminChanged]
ON
[dbo].[tbl_Admin]
FOR INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON


If (SELECT AdminId FROM INSERTED) <> 1
Begin
Return
End


--دستوراتی که باید اجرا شوند
...
END

درسته برای این خواسته ی دوست ما اصلا نیازی به استفاده از تریگر نیست و با یک Join ساده مشکل حل میشه.

golbafan
شنبه 05 اردیبهشت 1394, 09:35 صبح
من با ایجاد view بیشتر موافق هستم
اصولا همیشه باید تا جایی که ممکته از نوشتن کدهای اضافی و ایجاد سربار روی حافظه و پردازنده جلوگیری کرد

روشهایی که همه دوستان گفتن کاملا عملی هست ولی بهینه ترین روش، و راه حل استاندارد، اونیه که آقای صبوحی گفتن...

golnaz_a
شنبه 05 اردیبهشت 1394, 12:46 عصر
هیچ کس با یه تریگر داده رو اصلاح نمی‌کنه.

دوست عزیزممنون از راهنماییتون اما
اولا اگر با تریگر داده را اصلاح نمی کنند پس چرا تریگر برای update وجود دارد
در ثانی مسلما به ذهن من هم رسیده که میشه در زمان نمایش این محاسبه را انجام داد ولی در مورد کار من بسیار زمانبر تر از اجری trigger هست در مورد پروژه نمی تونم بیشتر توضیح بدم
اگر راه حلی با همین شرایط موجود داردید لطفا توضیح بدهید

SabaSabouhi
شنبه 05 اردیبهشت 1394, 14:09 عصر
[QUOTE=alireza_s_84;2204414]دوست عزیز من اصلا از پاسخ شما ناراحت نشدم فقط پرسیدم ایرادات روش کار من چیه. چون برخی مواقع پیش میاد که تریگر روی یک رکورد با شناسه خاص اجرا بشه و این هیچ ایرادی نداره که شما یک جدول Log برای تغییرات داشته باشین بخصوص اینکه لاگ کردن اون تغییرات مهم هم باشه.
ولی در کل اگر نیاز باشه تا اجرای یک Trigger مشروط باشه میشه از روش زیر هم استفاده کرد:

سلام
دوست من، شما بزرگوارید. حقیقت اینه که من ناگهان نگران شدم که مبادا شما رو ناراحت کرده باشم.
به نظر من درست نیست که برای به روز کردن یک یا چند سطر از یه جدول یه جدول دیگه درست کنیم و تریگر رو روی اون اجرا کنیم.
حداقل دیتابیس رو به شدت غیر نرمال می‌کنه. و یه کار اضافی هست که می‌تونه باعث چندگانگی اطلاعات بشه که برای جلوگیری
از اون باید کلی کد اضافه بنویسیم و . . .
من به خوبی با توانایی‌ها و امتیازهای ایجاد Log آشنایی دارم. ولی باور کن جاش اینجا نیست.

ضمن این که استفاده از عدد ثابت ( hardcode ) درون برنامه یا script بسیار کار بدی هست. اگه لازم هست چیزی تو تریگر کنترل بشه
باید تو جدول اصلی یا جدول‌های فرعی ثبت بشه و بعد تو تریگر کنترل بشه.

مثلاً اگه قرار هست سطرهایی که واحد پول اون‌ها دلار هست به روز بشن، باید با جدول ارز‌ها join کنیم و سطرهایی رو انتخاب کنیم
که «نام» ارز مثلاً USD باشه. چون اینجا هم استفاده از Id اشتباه هست. ( ممکنه به هر دلیلی تو سیستم مشتری Id دیگه‌ای به
ارز «دلار» اختصاص داده بشه.

صبا صبوحی

SabaSabouhi
شنبه 05 اردیبهشت 1394, 14:14 عصر
دوست عزیزممنون از راهنماییتون اما
اولا اگر با تریگر داده را اصلاح نمی کنند پس چرا تریگر برای update وجود دارد
در ثانی مسلما به ذهن من هم رسیده که میشه در زمان نمایش این محاسبه را انجام داد ولی در مورد کار من بسیار زمانبر تر از اجری trigger هست در مورد پروژه نمی تونم بیشتر توضیح بدم
اگر راه حلی با همین شرایط موجود داردید لطفا توضیح بدهید

سلام
1. با تریگر داده رو اصلاح می‌کنن. کی گفته که نمی‌کنن؟ اما نه این چیزی که شما می‌خوای انجام بدی
2. این که تریگر update داره، به معنی اصلاح اطلاعات نیست. به معنی این هست که پس از update تریگر فعال بشه.
3. مطمئن باش یه join ساده اون‌قدر query تو رو کند نمی‌کنه. با خیال راحت join کن
4. نیازی به شفاف کردن پروژه نیست. ممکنه پروژه‌ی شما محرمانه باشه، ممکنه هم نباشه، اما واقعاً نیازی نیست بیشتر توضیح بدی.
تا حدی که نیاز بود گفتی و کاملاً هم مشخصه که تریگر اینجا بی‌معنی و بی‌استفاده هس.
5. راه حل هم همونی هست که من و alireza_s_84 و golbafan بهت گفتیم، یعنی «JOIN».
مگه این که اصرار داشته باشی که تریگر بنویسی که دیگه من حرفی برای گفتن ندارم.

صبا صبوحی

ehstrn2010
چهارشنبه 09 اردیبهشت 1394, 13:31 عصر
ALTER TRIGGER TriggerOne ON Person
AFTER Insert, Update
AS
IF Update(LastName)
PRINT 'You modified the LastName column'
ELSE
PRINT 'The LastName column is untouched.'

....
تابیع Update() می گه که آیا تغییری ایجاد شده یا نه (البته اگر به همون مقدار قبلیش هم آپدیت بشه باز این تاریع True برمی گردونه)
از این منبع: TOTAL.TRAINING.ONLINE.MICROSOFT.SQL.SERVER.DEVELOP MENT-HELL

البته در عمل آپدیت برای مقایسه میتونی تو تریگر مربوطه از جدول Inserted , deleted کنی ، مثلا این جوری

if EXISTS(
select * from inserted inner join deleted on inserted.id=deleted.id
where (inserted.col1<>deleted.col1)
and (inserted.id=1)
)

یا یه چیزی تو مایه های بالا..