View Full Version : حرفه ای: بدست آوردن uid رکوردی که insert شده
مرتضی حمزه ئی
شنبه 26 دی 1388, 16:47 عصر
با سلام خدمت اساتید خواهش میکنم این راهم کمک کنید
اگر یک insert داخل یک جدول داشته باشیم که pk اون uid باشه چطوری میتونیم uid آنرا بدست آوریم چون
scop_identity خروجیش ازجنس int است ونمیتونیم استفاده کنیم و max() اون ستون را هم نمیتونیم بگیریم حالا چطوری میتونم مقدار uid مربوط به اون رکورد رابدست آورم
شرمنده تمام اساتید
AminSobati
شنبه 26 دی 1388, 19:35 عصر
سلام دوست عزیزم،
بهتره newid رو قبل از Insert خودتون تولید کنید. در غیر اینصورت باید از نسخه 2005 استفاده کنید تا عبارت OUTPUT در دستورات DML وجود داشته باشه. به کمک OUTPUT از جدول inserted میتونین newid رو بدست بیارین
محمد سلیم آبادی
شنبه 26 دی 1388, 21:50 عصر
سلام دوست عزیزم،
بهتره newid رو قبل از Insert خودتون تولید کنید. در غیر اینصورت باید از نسخه 2005 استفاده کنید تا عبارت OUTPUT در دستورات DML وجود داشته باشه. به کمک OUTPUT از جدول inserted میتونین newid رو بدست بیارین
پروفسور (به معنای استاد) جان فکر نمی کنم هیچ بایدی وجود داشته باشه...
دوست عزیزم یک راه این است که یک قید پیشفرض (default constraint) روی ستون مورد نظر قرار بدین که از تابع newsequentialid استفاده شده باشد. با استفاده از این تابع شما یک GUID تولید می کنید که از از GUID قبلی تولید شده در یک کامپیوتر مشخص بزرگتر باشد. با این حساب براحتی می توانین با تابع max آخرین GUID تولید شده (درج شده در جدول) را بدست آورین.
بطور مثال می تونین از این کد الگو بگیرین:
declare @t table
(i uniqueidentifier default NEWSEQUENTIALID(), j int primary key)
insert into @t values (default,1)
insert into @t values (default,2)
insert into @t values (default,3)
select * from @t
select * from @t
order by i
/*
i j
------------------------------------ -----------
C64F2B59-2505-DF11-9CB9-00241D05D1A0 1
C74F2B59-2505-DF11-9CB9-00241D05D1A0 2
C84F2B59-2505-DF11-9CB9-00241D05D1A0 3
i j
------------------------------------ -----------
C64F2B59-2505-DF11-9CB9-00241D05D1A0 1
C74F2B59-2505-DF11-9CB9-00241D05D1A0 2
C84F2B59-2505-DF11-9CB9-00241D05D1A0 3
*/
مرتضی حمزه ئی
شنبه 26 دی 1388, 22:03 عصر
پروفسور (به معنای استاد) جان فکر نمی کنم هیچ بایدی وجود داشته باشه...
دوست عزیزم یک راه این است که یک قید پیشفرض (default constraint) روی ستون مورد نظر قرار بدین که از تابع newsequentialid استفاده شده باشد. با استفاده از این تابع شما یک GUID تولید می کنید که از از GUID قبلی تولید شده در یک کامپیوتر مشخص بزرگتر باشد. با این حساب براحتی می توانین با تابع max آخرین GUID تولید شده (درج شده در جدول) را بدست آورین.
بطور مثال می تونین از این کد الگو بگیرین:
declare @t table
(i uniqueidentifier default NEWSEQUENTIALID(), j int primary key)
insert into @t values (default,1)
insert into @t values (default,2)
insert into @t values (default,3)
select * from @t
select * from @t
order by i
/*
i j
------------------------------------ -----------
C64F2B59-2505-DF11-9CB9-00241D05D1A0 1
C74F2B59-2505-DF11-9CB9-00241D05D1A0 2
C84F2B59-2505-DF11-9CB9-00241D05D1A0 3
i j
------------------------------------ -----------
C64F2B59-2505-DF11-9CB9-00241D05D1A0 1
C74F2B59-2505-DF11-9CB9-00241D05D1A0 2
C84F2B59-2505-DF11-9CB9-00241D05D1A0 3
*/
عزیز با نهایت احترام بخاطر جوابتون ولی ماهمون فیلدمون که uid است همون pk نیز هست به همین دلیل ازفرمایش شما نمیشه استفاده کرد واز طرفی نمیتونیم روی ستونی که از نوع uid است تابع max رااستفاده کنیم
ممنون میشم دوباره لطف کنید جواب بدید
محمد سلیم آبادی
شنبه 26 دی 1388, 22:14 عصر
عزیز با نهایت احترام بخاطر جوابتون ولی ماهمون فیلدمون که uid است همون pk نیز هست به همین دلیل ازفرمایش شما نمیشه استفاده کرد واز طرفی نمیتونیم روی ستونی که از نوع uid است تابع max رااستفاده کنیم
ممنون میشم دوباره لطف کنید جواب بدید
ستون مورد نظر با pk مشکلی ندارد، می تونین کد زیر رو اجرا کنین.
راجب تابع max می توانین از روش های جایگزین آن استفاده کنین که روشی که در ادامه قرار دادم روش مورد علاقه ی من است.
set nocount on
declare @t table
(i uniqueidentifier
default NEWSEQUENTIALID()
primary key,
j int)
insert into @t values (default,1)
insert into @t values (default,2)
insert into @t values (default,3)
select * from @t as t1
where not exists
(select *
from @t as t2
where t2.i > t1.i)
/*
i j
------------------------------------ -----------
94E56851-2905-DF11-9CB9-00241D05D1A0 3
*/
مرتضی حمزه ئی
شنبه 26 دی 1388, 22:41 عصر
با سلام خدمت تمام اساتید بالاخص آقای ثباتی عزیز
ازراهنماییتون ممنون آقای ثباتی با ساختن یک جدول بنام table_1 وقراردادن تنها یک فیلد داخل اون واستفاده از دستور زیر تونستم uid تولید شده رابدست بیارم
INSERT INTO dbo.Table_1
OUTPUT INSERTED.t1
values(NEWID() )
وجواب خروجی هم بصورت زیر بود
38676486-0A14-493C-944D-484D0DEC7736
بینهایت ممنونم آقای ثباتی
مرتضی حمزه ئی
شنبه 26 دی 1388, 22:58 عصر
ستون مورد نظر با pk مشکلی ندارد، می تونین کد زیر رو اجرا کنین.
راجب تابع max می توانین از روش های جایگزین آن استفاده کنین که روشی که در ادامه قرار دادم روش مورد علاقه ی من است.
set nocount on
declare @t table
(i uniqueidentifier
default NEWSEQUENTIALID()
primary key,
j int)
insert into @t values (default,1)
insert into @t values (default,2)
insert into @t values (default,3)
select * from @t as t1
where not exists
(select *
from @t as t2
where t2.i > t1.i)
/*
i j
------------------------------------ -----------
94E56851-2905-DF11-9CB9-00241D05D1A0 3
*/
مرسی دوست عزیز ازجوابتون
بالاخص واسه من اون حلقه ای که واسه پیداکردن ماکزیمم استفاده کردی خیلی جالب بودوکلی استفاده کردم
فقط محض اطلاع بقیه دوستان میگم که تابع NEWSEQUENTIALID() فقط برای حالتی میشه استفاده کرد که فیلد ماحتما یک default واسه اش تعریف شده باشه میشه استفاده کرد وگرنه توی حالت عادی واسه ایجاد uid از تابع NEWID() استفاده میکنیم
از اینکه دوتا ازبهترینهای سایت جواب دادند بینهایت ممنونم
AminSobati
دوشنبه 28 دی 1388, 18:53 عصر
پروفسور (به معنای استاد) جان فکر نمی کنم هیچ بایدی وجود داشته باشه...
دوست عزیزم یک راه این است که یک قید پیشفرض (default constraint) روی ستون مورد نظر قرار بدین که از تابع newsequentialid استفاده شده باشد. با استفاده از این تابع شما یک GUID تولید می کنید که از از GUID قبلی تولید شده در یک کامپیوتر مشخص بزرگتر باشد. با این حساب براحتی می توانین با تابع max آخرین GUID تولید شده (درج شده در جدول) را بدست آورین.
تا زمانی که شما یک نفر کاربر این سیستم هستید هیچ مشکلی پیش نمیاد و میتونین با دیتابیسی که تولید کردین اوقات خوشی رو سپری کنید. اما در محیط چندکاربره، این احتمال وجود داره که شخص دیگری هم زمان با شما Insert انجام بده و Query شما GUID تولید شده توسط اون کاربر رو برگردونه. تصور نکنید مثال من از احتمالاتی هست که هر 300 سال یکبار رخ میده! اگر در سیستمهای OLTP حضور پیدا کرده باشید به وفور دیده میشه.
این دقیقا مشکلی هست که برای تولید Identity بصورت Manual وجود داره و راه حل های خودش رو میطلبه.
اگر در نسخه 2000 هستید، ناچارا یا باید GUID رو قبل از Insert تولید کنین، یا قبل از Insert یک Transaction باز و کل جدول رو Lock کنید تا مطمئن باشید تا زمانی که Max گرفتن به پایان نرسیده، کسی امکان Insert نداره.
این یعنی همزمانی ضعیف! با افزایش تعداد کاربران سیستم، کارآیی به طور محسوسی افت میکنه
محمد سلیم آبادی
سه شنبه 29 دی 1388, 02:16 صبح
روشی را که نام بردم چیزی را گارانتی نمی کند. عملکرد تابع newsequentialid به این شکل است که تنها ترتیب مقادیر در یک سیستم خاص بصورت افزایشی خواهد بود و در محیط های چند کاربره چیزی گارانتی نخواهد شد.
بیشتر ماجرا بر می گردد به کلمه ی "باید"، در اینجا به روشی اشاره می کنم که نیازی به نسخه ی 2005 هم ندارد. یعنی استفاده از trigger به جای ماده ی output. نقطه ی مشترک این دو، جدول مجازی inserted است.
بازم تکرار می کنم این روشها فقط نوعی راه حل هستند نه چیز دیگری
create trigger trg_name
on your_table_name
after insert
as
select uniqueidentifier_column_name
from inserted
AminSobati
سه شنبه 29 دی 1388, 12:28 عصر
خاصیت جدول مجازی Inserted در Output و Trigger شاید در ظاهر اشتراک بین این دو محسوب بشه اما تفاوت مهمی هست به این شکل که اجرا کننده دستور INSERT نمیتونه خروجی رو به راحتی از Trigger دریافت کنه. اگر فرضا در یک SP شما نیاز دارین Insert انجام بدین و GUID بدست بیارین، مشکل وجود خواهد داشت. ولی OUTPUT برای همین منظور طراحی شده
محمد سلیم آبادی
سه شنبه 29 دی 1388, 12:50 عصر
بهترین کار assign کردن یک متغیر با تابع newid قبل از درج است (که در اولین پست شما به آن اشاره کردین). البته خواستم syntax زیر را امتحان کنم ولی ساپرت نشد:
insert into table_name select @id = newid()
محمد سلیم آبادی
سه شنبه 29 دی 1388, 13:16 عصر
اگر یک ستون دیگر به نام insert_date از نوع datetime و با مقدار پیشفرض getdate داشته باشن می توان داده ها را بر اساس زمان درج بصورت سریالی sort کنند در نتیجه max آخرین GUID را بدست آورند.
شما که استاد نقد کردن هستید نقد این روشم زحمتشو بکشین (: البته به غیر از اینکه نیاز به یک tran دارد...
AminSobati
سه شنبه 29 دی 1388, 17:10 عصر
باز هم مشکل همزمانی! وقتی یک سرور داری چند پردازنده باشه، این احتمال وجود داره (و دیده شده) که دو رکورد تا هزارم ثانیه هنگام درج با هم یکسان باشند
محمد سلیم آبادی
سه شنبه 29 دی 1388, 17:50 عصر
امین خان اینگار قصد دارین مو رو از ماست بکشین. احتمال اینکه در یک میلیونوم ثانیه دو مقدار درج شوند چقدر است؟ بازم مقدار قابل قبولی است.
AminSobati
سه شنبه 29 دی 1388, 18:33 عصر
جنس DateTime نهایتا تا 3 هزارم ثانیه دقت داره پس در SQL Server 2000 و 2005 نمیشه دقت میلیونیوم ثانیه رو در دیتابیس ذخیره کرد:
declare @x datetime
declare @y datetime
set @x ='2000-1-1 14:45:50.998'
set @y ='2000-1-1 14:45:50.997'
select @x, @y
از نسخه 2008 جنس DateTime2 تا 100 نانو ثانیه دقت داره (1 ده میلیونیوم ثانیه). ولی در 2008 با وجود Output نیازی به اون روش نداریم!
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.