PDA

View Full Version : حرفه ای: کوئری برای رزرو کردن جا



mahdi87_gh
یک شنبه 18 بهمن 1388, 12:56 عصر
سلام من چند تا جدول دارم و میخوام الگوریتمی برای رزرو کردن جا درست کنم.در دو روز باید در چند مدرسه (هر مدرسه چند ساعت و هر ساعت 10 نفر رزرو کنه)

جداول days(dayid,dayname)
times(timeid,time)
schools(schoolid,school)
azmon(schoolid,timeid,personalcode,dayid)

من کد زیر رو نوشتم ولی یه مشکلی داره. اونم اینه که اگه ی نفر توی ی مدرسه با کد بزرگتر ثبت بشه، مدرسه های قبل از اون خالی میمونه!! میخوام دقیقا بتونه بگه جای خالی بعدی کجاست؟حتی اگه مدرسه های جلوتر هم جا رزرو شده باشه
خیلی فوریه لطفا کمک برسونید


DECLARE @s int;
DECLARE @d int;
DECLARE @t int;
DECLARE @mt int;
DECLARE @kt int;
declare @ks int;
SELECT @kt=(SELECT COUNT(*) FROM times);
select @ks=(SELECT COUNT(*) FROM schools);

select @d=(select coalesce(max(dayid),1) as dayid from azmon)
SELECT @s=(SELECT coalesce(max(schoolid),1) AS schoolid FROM azmon where dayid=@d)
SELECT @mt=(SELECT coalesce(max(timeid),1) FROM azmon WHERE schoolid=@s and dayid=@d)
SELECT @t=(SELECT count(timeid) FROM azmon WHERE schoolid=@s and timeid=@mt and dayid=@d)

SELECT @t=@t+1;
IF @t>10
BEGIN
SELECT @mt=@mt+1;
END

IF @mt>@kt
BEGIN
SELECT @mt=1;
SELECT @s=@s+1;
END

if @s>@ks
begin
select @d=@d+1;
Select @mt=1;
select @s=1;
end
INSERT INTO azmon VALUES(@s,@personalid,@mt,@d);

محمد سلیم آبادی
یک شنبه 18 بهمن 1388, 14:38 عصر
سلام،
شما برای Business Rules این کار را می خواهین انجام بدین؟ از Trigger استفاده کردین؟

DDL جداول لازمه (همراه با تمام قیود) و اگر راهنمایی و کمک نیاز دارین بایستی توضیحات مفصل و کاملی ارائه بدین. یک مثال هم بزنین.

mahdi87_gh
یک شنبه 18 بهمن 1388, 15:42 عصر
نه من کدهای فوق رو داخل ی stored procedure نوشتم (البته بعلاوه مدهای دیگه ای ک فعلا لازم نیست)
این قسمت از کد کارش پیدا کردن جای خالی بعدی هستش. به ترتییب از روز اول مدرسه اول ساعت اول؛ 10 نفر رو میزراه بعد روز اول مدرسه اول ساعت دوم 10 نفر بعدی
چون من داخل موئری از max استفاده کردم اگه اشتباها( از این پراسجور استفاده نشه یا یک نفر که قبلا جا رزرو کرده پاک بشه) و در دستور insert کد مدرسه بزرگتری استفاده بشه، اونوقت سایر جاهای خالی مدرسه های با کد کوچیکتر دیگه پر نمیشه و خالی میمونه!!!
همین اتفاق در مورد ساعت ها هم میفته(چون max نوشتم)
جداول هم همونایی که نوشتم فکر می کنم چون کلیدهای اصلی و خارجی توشون مشخصه، سایر فیلدها لازم نباشه
ممنون آقای maslim

محمد سلیم آبادی
یک شنبه 18 بهمن 1388, 16:17 عصر
همیشه برای خوانایی کد هم که شده از یک دستور DECLARE برای تعریف چند متغیر استفاده کنید. حتی در SQL Server 2008 شما همزمان می توانید مقدار دهی اولیه هم داشته باشید.

وقتی از دستور SELECT برای Assignment کردن استفاده می کنید دیگر نیازی نیست که دوباره از Subquery استفاده کنید مثلا به جای عبارت زیر
SELECT @kt = (SELECT COUNT(*) FROM times) --t

این عبارت را بنویسید:
SELECT @kt=Count(*) From times

این طریقه ی استفاده از عبارت SELECT معروف به Assignment SELECT است.

و زمانی که از SELECT برای مقدار دهی به متغیر ها استفاده می کنید می توانید چند متغیر را با یک دستور مقدار دهی کنید دقیقا شبیه به DECLARE.

تورفتگی ها و ستونی نوشتن را در query حفظ کنید. مثلا به جای عبارت زیر
select * from table_name where table_id = @param

این عبارت را بنویسید:


select *
from table_name
where table_id = @param


هنگامی که کد به این شکل نوشته شود چشم راحتتر می تواند کد ها و خطوط را پیمایش کند دقیقا شبیه به حل یک مساله ی ریاضی. یا متن های ریز یک مجله.

قوانین نام گذاری ISO-11179 را چرا نقض کردین؟

mahdi87_gh
یک شنبه 18 بهمن 1388, 17:29 عصر
ممنون بابت راهنماییهاتون
من از 2005 استفاده می کنم

قوانین نام گذاری هم نمیدونم چین!!!!!
اگه توضیح بدین ممنون میشم اما چیزی که الان برام ضروری هستش اصلاح کردن این کد هستش
بازم ممنونم

محمد سلیم آبادی
یک شنبه 18 بهمن 1388, 23:06 عصر
اینجا را یه نگاهی کنید:
http://barnamenevis.org/forum/showthread.php?t=176437

در گوگل در مورد ISO-11179 naming rules جستجو کرده و به لینک Wiki بروید.

لطفا یک نموده از داده ها و یک نمونه از نتیجه ی (result) مورد نظر ارسال کنید، مثلا به صورت زیر:


/* Cities Table
|----------------------------|
|city_id city_name |
|----------- ----------------|
|1 Tehran |
|2 Qom |
|3 Mashhad |
|----------------------------|

Trips Table
|------------------------------------------------|
|trip_nbr start_city_id end_city_id start_time|
|----------- ------------- ----------- ----------|
|1 1 2 2010-02-10|
|2 1 3 2010-02-10|
|3 2 1 2010-02-10|
|------------------------------------------------|

The Result
|---------------------------------------------------------------------------------|
|trip_nbr start_city_id end_city_id start_time start_city_name end_city_name |
|----------- ------------- ----------- ---------- --------------- ----------------|
|1 1 2 2010-02-10 Tehran Qom |
|2 1 3 2010-02-10 Tehran Mashhad |
|3 2 1 2010-02-10 Qom Tehran |
|---------------------------------------------------------------------------------|
*/

mahdi87_gh
دوشنبه 19 بهمن 1388, 22:32 عصر
|dayid dayname |

|----------- ----------------|

|1 جمعه 21/11 |

|2 جمعه 28/11 |



|----------------------------|

|schoolidid schoolname |

|----------- ----------------|

|1 مدرسه 1 |

|2 مدرسه2 |

|3 مدرسه3

|----------------------------|



|------------------|

|timeid time |

|----------- ------|

|1 9-10 |

|2 10-11 |

|3 11-12 |

|4 14-15 |


|5 15-16 |

|6 16-17 |



اگر ظرفیت هر ساعت را 3 نفر فرض کنیم ( که در اصل 10 می باشد) باید اطلاعات در جدول آزمون بصورت زیر ذخیره شود:

یعنی در روز اول مدرسه اول تایم اول به اندازه ظرفیت پر شود. سپس برای روز اول مدرسه اول تایم دوم به اندازه ظرفیت پر شود. تا همه تایم های مدرسه اول تکمیل شود. حالا نوبت به مدرسه دوم میرسد که باز هم از تایم اول شروع کرده به اندازه ظرفیت ثبت نام میکنیم. آنقدر ادامه می یابد تا در روز اول همه تایمهای همه مدارس پر شود، حالا همه این کارها را از نو، برای روز دوم باید انجام شود.

اگر ثبت نام به ترتیب انجام بشه، همین الگوریتمی که من نوشتم به ترتیب نوبت دهی میکنه .اما همون مشکلی که در پست های بالا توضیح دادم توی این الگوریتم وجود داره که امیدوارم با کمک شما حل بشه.

مرسی


|dayid schoolid timeid personalid|


| 1 1 1 111 |

| 1 1 1 112 |

| 1 1 1 113 |

| 1 1 2 114 |

| 1 1 2 115 |

| 1 1 2 116 |

| …

| 1 1 6 ... |

| 1 1 6 ... |

| 1 1 6 ... |

|…

| 1 3 6 ... |

| 1 3 6 ... |

| 1 3 6 ... |

|…

| 2 1 1 ... |

| 2 1 1 ... |

| 2 1 1 ... |

|…

| 2 3 6 ... |

| 2 3 6 ... |

| 2 3 6 ... |

محمد سلیم آبادی
دوشنبه 19 بهمن 1388, 23:46 عصر
ببینید این دقیقا همون چیزیست که دنبالشید:



--INSERT INTO Azmon (dayid, schoolid, timeid, personalid)
SELECT dayid, schoolid, timeid,
ROW_NUMBER() OVER(ORDER BY dayid, schoolid, timeid, i) + 110 AS personalid
FROM days
CROSS JOIN schools
CROSS JOIN times
CROSS JOIN (SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9 UNION ALL
SELECT 10) AS d(i)
ORDER BY dayid, schoolid, timeid, personalid;


نتیجه ی اجرای کد فوق:




/*
dayid schoolid timeid personalid
----------- ----------- ----------- --------------------
1 1 1 111
1 1 1 112
1 1 1 113
1 1 1 114
1 1 1 115
1 1 1 116
1 1 1 117
1 1 1 118
1 1 1 119
1 1 1 120
1 1 2 121
1 1 2 122
1 1 2 123
1 1 2 124
1 1 2 125
1 1 2 126
1 1 2 127
1 1 2 128
1 1 2 129
1 1 2 130
...
...
2 3 5 455
2 3 5 456
2 3 5 457
2 3 5 458
2 3 5 459
2 3 5 460
2 3 6 461
2 3 6 462
2 3 6 463
2 3 6 464
2 3 6 465
2 3 6 466
2 3 6 467
2 3 6 468
2 3 6 469
2 3 6 470
...
...
2 3 5 455
2 3 5 456
2 3 5 457
2 3 5 458
2 3 5 459
2 3 5 460
2 3 6 461
2 3 6 462
2 3 6 463
2 3 6 464
2 3 6 465
2 3 6 466
2 3 6 467
2 3 6 468
2 3 6 469
2 3 6 470
*/

mahdi87_gh
سه شنبه 20 بهمن 1388, 16:59 عصر
من الان وقت کردم به الگوریتم شما نگاه کنم.خیلی ممنون از توجه شما آقای msalim. من قبلا هم از کمکهای مفید شما استفاده کردم.
الگوریتمی که شما نوشته اید میاد دقیقا به همون ترتیبی که من گفته بودم رکوردها رو insert میکنه ولی منظور من این نبودش!!! همه جاها که قرار نیست توی 5 ثانیه پربشه!!!(قراره هر کس وارد سایت بشه و ثبت نام کنه؛ عین سایت سازمان سنجش و من باید برای هر کسی که ثبت نام می کنه بلافاصله بعد از ثبت کردن کارت ورود به جلسه صادر کنم که بدون کدوم روز کدوم مدرسه کدوم ساعت بره و امتحان بده!)
بنابراین من نیاز به الگوریتمی دارم که موقع ثبت این فرد به من بگه جای خالی بعدی کجاست؟؟!!
در توضیح باید اینو اضافه کنم که persoanlid کد پرسنلی افراد هستش و نیازی نیستش که به ترتیب از 111 شروع بشه و بره بالا. بلکه کد پرسنلی و dayid و schoolid و timeid باهم بعنوان کلید اصلی جدول آزمون هستن تا هر کد پرسنلی فقط یکبار بتونه ثبت نام کنه
امیدوارم ببخشید که خوب نمی تونم منظورم رو برسونم
مرسی

محمد سلیم آبادی
سه شنبه 20 بهمن 1388, 17:31 عصر
بنابراین من نیاز به الگوریتمی دارم که موقع ثبت این فرد به من بگه جای خالی بعدی کجاست؟؟!!


اگر درست متوجه شدم (که البته به من حق بده) میاییم این کار رو می کنیم:
یه Counter برای سیستم در نظر می گیریم که برای ثبت نام نفر اول این Counter عدد 1 را نشون می ده و همین طور تا آخر. سپس برای درج در جدول Azmon و دادن اطلاعات با متقاضی/داوطلب کافیه سطری از جدول (جدولی که ایجاد کردم شامل 360 سطر است) را بدست میاریم که id آن برابر با Counter باشه.

کد به این شکل در میاد:
البته بهتره این داده ها را داخل یک جدول از قبل ذخیره کنید تا دائما داده ها تولید نشن.


CREATE PROCEDURE Azmon_Insert
@Counter INT,
@Personal_ID INT
AS
INSERT INTO Azmon (dayid, schoolid, timeid, personalid)
SELECT dayid, schoolid, timeid, @Personal_ID
FROM (SELECT *,
ROW_NUMBER() OVER(ORDER BY dayid, schoolid, timeid, i) AS id
FROM days
CROSS JOIN schools
CROSS JOIN times
CROSS JOIN(SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9 UNION ALL
SELECT 10) AS d(i))d
WHERE d.id = @Counter;

mahdi87_gh
سه شنبه 20 بهمن 1388, 19:44 عصر
مرسی از توجهتون آقای msalim
من که این نظریه شما رو خوندم گفتم آخجون مسئله با کمک مهندس msalim حل شد:تشویق:

یه Counter برای سیستم در نظر می گیریم که برای ثبت نام نفر اول این Counter عدد 1 را نشون می ده و همین طور تا آخر. سپس برای درج در جدول Azmon و دادن اطلاعات با متقاضی/داوطلب کافیه سطری از جدول (جدولی که ایجاد کردم شامل 360 سطر است) را بدست میاریم که id آن برابر با Counter باشه.

اما چند ثانیه بعد دیدم بازم اینجا یه مشکلی وجود داره:متفکر::اشتباه:
اون مشکل اینه:
فرض می کنیم که در هر بار اضافه کردن یک رکورد به جدول آزمون به counter هم یکی اضافه میشه(که میتونیم اصلا counter نذاریم چون با یه دستور select count(*) می تونیم تعداد رو بدست بیاریم) و در هر بار که رکوردی delete میشه counter یکی کم میشه (که بازم نتیجش باهمون دستور select برابره).مشکل اینه:
فرض می کنیم که تابحال 22 نفر در آزمون ثبت نام کرده اند،بنابراین نتیجه میگیریم که ظرفیت 10 نفری تایم اول و دوم از مدسه اول از روز اول پرشده و 2 نفر در تایم سوم از مدرسه اول از روز اول قرار گرفته اند و برای همشون کارت صادر شده!!! حالا مدیر سایت تصمیم میگیره که 5 نفر از نفراتی که داخل تایم اول قراردارند رو بنابه دلایلی حذف بکنه(که مشکلات منم از این حذف کردنه شروع شد!!!)
بعد از حذف این 5 نفر، شمارنده ما برابر با 15 خواهد بود. پس برنامه ما نفر بعدی ای که ثبت نام می کنه داخل تایم دوم از مدرسه اول قرار میده. اما مشکل اینجاست که اون تایم کاملا ظرفیتش پره!!! و این تایم اول ماست که چند نفر ازش حذف شدن و جای خالی داره!!!
امیدوارم تونسته باشم منظورم رو برسونم
بازم مرسی

محمد سلیم آبادی
سه شنبه 20 بهمن 1388, 22:15 عصر
راه حل پیشنهادی من:

یک ستون به جدول تولید شده به نام Flag از نوع Bit اضافه می کنیم که مشخص می کنه سطر انتخاب شده یا برای انتخاب کاندید است.

هر موقع که کاربری در خواست داد اولین سطری که Flag اش برابر با 1 است برای او انتخاب می شود. و این مقدار به 0 ویرایش (update) میشه تا دیگه کسی نتونه این سطر را انتخاب کنه.

برای نفر بعدی دوباره اولین سطری که مقدار فیلد Flag آن برابر با 1 است انتخاب می شه. به همین سادگی.

mahdi87_gh
چهارشنبه 21 بهمن 1388, 19:40 عصر
حالا اگه بیایم و صورت سوال رو عوض کنیم و به جدول مدارس فیلد ظرفیت رو اضافه کنیم چی؟
:متفکر:

محمد سلیم آبادی
چهارشنبه 21 بهمن 1388, 21:04 عصر
قاعدتا" بنظر میرسه بشه این مشکل رو رفع کرد (شاید با APPLY) ولی سوال اصلی اینست که ممکنه در زمان کار این مقدار update بشه و تغییر کنه؟ برای مدارسی که ثبت نامشان تکمیل شده شاید بشه ظرفیت رو افزایش داد ولی کم نمیشه کرد. چرا کمم میشه کرد فقط باید ثبت نام اضافیا شیفت بشن به مدارس دیگه. با این تفاسیر به نظر میرسه کار بسیار دشوار بشه.

اگر علاقه داری کمکتون کنم باید جزئیات را با دقت در اختیارم بزارین.
بقول معروف، قبل از ارائه راه حل برای مساله باید صورت مساله به چالش بیوفته.

mahdi87_gh
چهارشنبه 28 بهمن 1388, 18:43 عصر
با سلام خدمت شما مدیر گرانقدر
از وقفه ای که پیش اومد عذر میخوام
من با همون جواب قبلی کارم راه افتاد.خیلی مممنون از شما.اینو دیگه جهت آینده می پرسم!!
مسئله هنوز همون مسئله قبلیه با این تفاوت: به جای اینکه فرض کنیم هر مدرسه در هر تایم 10 نفر ظرفیت دراه، برای جدول مدارس فیلدی به عنوان ظرفیت درنظر گرفته بشه.
بیایم درمورد تغییر ظرفیت مدارس اینطوری عمل کنیم: حق کم کردن ظرفیت وجود نداره،به شرطی که کسی در اون مدرسه کسی ثبت نام نکرده باشه. می توان ظرفیت مدارس را افزایش داد. حالا برای هر کدوم از تغییرات باید جدولی که اولین جای خالی رو به ما نشون میداد تغییر بکنه اما نباید در رکوردهای قبلی که مقدار flag ما 1 شده، تغییری به وحود بیاد!
مرسی از همفکری شما:تشویق: