PDA

View Full Version : شیفت دادن اطلاعات یک ستون عددی



Felony
شنبه 28 مرداد 1391, 11:56 صبح
سلام ؛

در برنامه ای نیاز به طراحی جدول نوبت دهی هست که باید بشه نوبت ها رو جا به جا کرد ( پارتی بازی ! ) ، حالا برای اینکه بشه نوبت ها رو جا به جا کرد من یک فیلد با نام Priority در نظر گرفتم که اولویت هر سطر رو معلوم میکنه و در آخر رو جدول بر اساس این فیلد یک Order By زدم تا نوبت ها بر اساس شماره Priority مرتب بشه .

حالا فرض کنید در جدول 5 تا رکورد با اولویت زیر داریم :

Priority - ID
1 - 1
2 - 4
3 - 2
4 - 3

حالا کاربر نرم افزار میاد و یخواد نوبت فردی که چهارم هست رو بکنه دوم ؛ با این شرایط فیلد Priority باید به صورت زیر مقدار دهی جدید بشه :

Priority - ID
1 - 1
2 - 2
3 - 3
4 - 4

یعنی فرد مورد نظر نوبت مورد نظر رو بگیره و باقی شماره ها به ترتیب شیفت بخورن ، نه اینکه 2 تا نوبت رو با هم جا به جا کنیم .

میخوایم یک SP داشته باشیم که 2 تا ورودی بگیره ، یکی Current Priority که مقدار فعلی فیلد Priority هست و دیگری New Priority که مقدار دجدید فیلد اولویت هست و SP باید هر رکوردی که فیلد Priority با Current Priority یکی بود رو با New Priority مقدار دهی کنه و باقی رکوردها رو شیفت بده ، این مورد حتما باید سمت سرور پیاده بشه .

حالا کسی راه حل کم هزینه ای سراغ داره ؟

روی کاغذ یه شبه کد نوشتم ولی چیز جالبی از آب در نیومد ، امروز از اون روزهایی که حال کار کردن نیست ؛ خدا به خیر کنه ... :لبخند:

Mahmoud.Afrad
شنبه 28 مرداد 1391, 17:21 عصر
یک نظر. priority نمیتونه از نوع float باشه؟؟؟!!. اینجوری نیاز به شیفت دادن بقیه نیست و کافیه مقداری که قراره بین دو مقدار دیگه قرار بگیره یک عدد float بین اون دو priority بهش نسبت داد(مثلا میانگین دو مقدار). برای نمایش دادن بعد از مرتب سازی میشه در سکلت، نوبت را به صورت عدد صحیح(شماره ردیف مثلا) درآورد.
before
Priority - ID
1 - 1
3 - 2
4 - 3
2 - 4

after
Priority - ID
1 - 1
4- 1.5
3 - 2
2 - 4

در اینجا من برجسب اولویت مرتب کردم متوجه بشید.(طبق مثال خودتون)

Felony
شنبه 28 مرداد 1391, 19:18 عصر
خودم همین فکر رو کرده بودم ولی مشکل این هست که با پیاده سازی این شیوه ، فقط میشه 9 تا رکورد رو بین هر دو عدد شیف داد ، یعنی مثلا 1.1 تا 1.9
بعدش هم نمیتونم به کاربر بگم اولویت رو ممیزی وارد کن ، البته این رو میشه خودم کنترل کنم و وقتی کاربر عدد تکراری زد اولین عدد خالی بین اون و عدد بعدش رو درج کنم ولی همونطور که گفتم فقط میشه 9 تا رکورد بین 2 عدد درج کرد .
البته احتمال اینکه یکی بخواد 9 تا نوبت رو بین دو نوبت بیاره خیلی خیلی کمه ولی در هر صورت ممکنه .

Reza_Yarahmadi
یک شنبه 29 مرداد 1391, 13:22 عصر
خب میتونید 2 تا آپدیت پشت سرهم بنویسید
Declare @OldPriority int
Select @OldPriority = Priority From MyTable Where ID = @ID

Update MyTable Set Priority = Priority + 1 Where Priority >= @NewPriority AND Priority < @OldPriority
Update MyTable Set Priority = @NewPriority Where ID = @ID

ID@ آی دی رکوردی است که قراره تغییر کنه. NewPriorit@ اولویت جدید رکورد مورد نظر.

Mahmoud.Afrad
یک شنبه 29 مرداد 1391, 15:37 عصر
خوب نیاز نیست که حتما قسمت اعشار یک رقمی باشه که، میتونه چند رقمی باشه مثلا بین 1.1 و 1.2 میتونه 1.15 و .... قرار بگیره. کاربر هم نیاز نیست اعشاری وارد کنه. برای نمایش به کاربر میتونید به صورت عدد صحیح نشون بدید مثلا شماره ردیف.

Felony
یک شنبه 29 مرداد 1391, 17:54 عصر
خب میتونید 2 تا آپدیت پشت سرهم بنویسید
Declare @OldPriority int
Select @OldPriority = Priority From MyTable Where ID = @ID

Update MyTable Set Priority = Priority + 1 Where Priority >= @NewPriority AND Priority < @OldPriority
Update MyTable Set Priority = @NewPriority Where ID = @ID

ID@ آی دی رکوردی است که قراره تغییر کنه. NewPriorit@ اولویت جدید رکورد مورد نظر.
کدت بدون تست رد هست ، الان فرض کن جدولی به صورت زیر داریم :

Priority-ID
1-1
2-2
3-3
4-4

حالا تو کد شما ID@ رو با 4 مقداردهی میکنیم و @NewPriority رو با 1 ؛ یعنی میخوایم رکورد شماره 4 که اولویتش 4 هست رو اولویتش رو بکنیم 1 ؛ خوب تا اینجا کد شما درست کار میکنه و حاصل میشه :

Priority-ID
2-1
3-2
4-3
1-4

حالا میخوایم رکورد 2 که Priority ش 3 هست رو اولویتش رو به 4 تغییر بدیم یعنی تو کد شما ID@ رو با 2 و @NewPriority رو با 4 مقدار دهی میکنیم و نتیجه میشه :

Priority-ID
1-1
4-2
4-3
2-4

خوب ؟!

ASKaffash
سه شنبه 31 مرداد 1391, 07:13 صبح
سلام
شبیه ایده Node یک درخت را استفاده کنید هر نفر فقط بداند ID نوبت قبلی کیست و اولین نفر ID قبلی آن صفر است حالا میتوانید با CTE مقدار نوبت دهی ها را بدست آورید در این روش شما فقط یک Row را Update می کنید و نیازی به شیفت کردن کلیه افراد ندارید

Reza_Yarahmadi
سه شنبه 31 مرداد 1391, 18:20 عصر
کدت بدون تست رد هست ، الان فرض کن جدولی به صورت زیر داریم :
خب با یه دستکاری ساده ریاضی میشه این مشکل رو هم برطرف کرد.
Declare @MyTable Table(ID int Identity(1, 1), Priority int)

Insert Into @MyTable Values (1)
Insert Into @MyTable Values (2)
Insert Into @MyTable Values (3)
Insert Into @MyTable Values (4)
Insert Into @MyTable Values (5)
Insert Into @MyTable Values (6)

Declare @NewPriority int, @ID int
Set @ID = 2
Set @NewPriority = 6

Declare @OldPriority int, @Margin int
Select @OldPriority = Priority From @MyTable Where ID = @ID

Set @Margin = (@OldPriority - @NewPriority) / ABS(@OldPriority - @NewPriority)

Update @MyTable Set Priority = Priority + @Margin
Where
(@Margin = 1
AND
Priority >= @NewPriority
AND
Priority < @OldPriority)
OR
(Priority <= @NewPriority
AND
Priority > @OldPriority)

Update @MyTable Set Priority = @NewPriority Where ID = @ID