PDA

View Full Version : دسته بندی اطلاعات



Rasool-GH
چهارشنبه 28 مهر 1395, 13:21 عصر
سلام دوستان نیاز دارم در یک برنامه کوئری با شرایط زیر به دست بیاد
به طور مثال در فرم مشخص کنم که 500 نفر در گروههای 10 نفره تقسیم بشوند و 2 روز در هفته به هر گروه یک روز اختصاص پیدا کنه
یعنی خروجی کوئری به این شکل باشه که :

نفر اول | روز اول | هفته اول
.
.
.
نفر دهم | روز اول | هفته اول
نفر یازده | روز دوم | هفته اول
.
.
.
نفر بیست | روز دوم |هفته اول
نفر بیست و یکم | روز اول | هفته دوم
.
.
.

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

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

روش 1 :

روز1 -- دستگاه 1
روز1 -- دستگاه 2
روز1 -- دستگاه 3
.
.
روز2 -- دستگاه 4
روز2 -- دستگاه 5
روز2 -- دستگاه 6
.
.

روش 2 :

روز1 -- دستگاه 1 و دستگاه 2 و دستگاه 3
روز2 -- دستگاه 4 و دستگاه 5 و دستگاه 6
.
.
.

در این مورد روش اول مورد نظر بنده است

Rasool-GH
جمعه 30 مهر 1395, 14:41 عصر
سلام مجدد
سوال رو به این شکل هم میشه مطرح کرد
چه کدی باید نوشته بشه که یک ستون ردیف به کوئری اضافه کنه با این شرایط که دو عدد از کاربر دریافت کنه با عنوان تعداد روز و گام مثلا 3 و 6
و خروجی به این شرح باشه که به هر 3 ردیف یک عدد اختصاص بده و فاصله عدد بعدی هم 6 رقم باشه
مثال :

ردیف | سایر اطلاعات
1
1
1
7
7
7
13
13
13
.
.
.

من یک کد در vb نوشتم و از متغیرهای عمومی استفاده کردم که مقادیر در هر مراجعه حفظ بشه ولی مشکل اینجاست که با هر بار اجرا شدن کوئری یک بار به تابع Vb مراجعه میکنه و برای همه ردیفها یک شماره واحد رو میزنه و سری دوم که کوئری اجرا میشه شماره جدید زده میشه .

ariayekta
جمعه 30 مهر 1395, 22:54 عصر
سلام با کراس کویری میتونی اینو بدست بیاری نتونستی نمونت رو تکمیل کن انجام بدم

Rasool-GH
شنبه 01 آبان 1395, 03:11 صبح
سلام متاسفانه با نحوه کار کراس کوئری اشنا نیستم .
ممنون میشم اگر صرفا یک نمونه کوئری که خروجی پست 2 رو ارائه کنه در اختیارم قرار بدید

mazoolagh
یک شنبه 02 آبان 1395, 15:08 عصر
اگر جدول شمل فیلد ID بعنوان کلید داره که از یک شروع میشه و مطمئن هستین که هیچ رکورد حذفی نداره و در آینده هم نخواهد داشت میتونین از کوئری زیر استفاده کنین:

PARAMETERS GS SHORT,WD SHORT;
SELECT ID , (ID-1)\(GS*WD)+1 AS WEEK_GROUP , ((ID-1) Mod (GS*WD))\GS+1 AS DAY_GROUP
FROM "TblName"



ولی اگر فیلد کلید ID ندارین یا اینکه اگر این فیلد هست ممکن هست رکورد حذفی داشته باشین ، باید این دو فیلد رو به جدول اضافه کنین: یکی برای گروه بندی هفته WEEK_GROUP و یکی هم برای گروه بندی روز هفته DAY_GROUP

حالا خیلی ساده و فقط با یک پیمایش در رکوردست میتونین اطلاعات این فیلدها رو محاسبه کنین:

DIM RS AS RECORDSET
SET RS=CURRENTDB.OPENRECORDSET("TblName", DBOPENDYNASET)
DIM GS AS INTEGER ' GROUP SIZE
GS=10
DIM DW AS INTEGER ' DAYS PER WEEK
DW=2
DIM P AS INTEGER ' RECORD POSITION IN TABLE
DO WHILE NOT RS.EOF
P=RS.ABSOLUTEPOSITION
RS.EDIT
RS!WEEK_GROUP=(P\(GS*DW))+1
RS!DAY_GROUP=(P MOD (GS*DW))\GS+1
RS.UPDATE
RS.MOVENEXT
LOOP
RS.CLOSE
SET RS=NOTHING

Rasool-GH
دوشنبه 03 آبان 1395, 18:31 عصر
سلام
بسیار لطف کردید و عجب ریاضیاتی .
:لبخند:
لطفا در خصوص نحوه عملکرد Mod توضیح کوتاهی بدید.
:متفکر:
جسارتا خواسته دیگه ای هم دارم . در صورتی که بخوایم روزهای هفته را مشخص کنیم چه راهی وجود داره ؟

مثلا :
مطابق نمونه مشاهده میکنید که روز جمعه هم در دسته بندی لحاظ میشه در صورتی که با چک باکس بخوام جمعه در نظر گرفته نشه یا روزهای مشخصی محاسبه بشه چکار میتونم انجام بدم ؟
به بیان ساده تر بجای اینکه داخل تکس باکس مشخص کنم چند روز در هفته مورد نظر هست به وسیله چک باکس هم تعداد روزها و هم روزهای مد نظر رو مشخص میکنم

mazoolagh
سه شنبه 04 آبان 1395, 11:33 صبح
سلام


در خصوص نحوه عملکرد Mod توضیح کوتاهی بدید.
اپراتور MOD برای بدست آوردن باقیمانده تقسیم صحیح بکار میره:
7 MOD 5
میشه 2



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

فرض کنین که سه روز در هفته قرار هست باشه. یعنی پارامتر WD میشه سه.
جواب مستقل از این هست که این سه روز شنبه-یکشنبه-پنجشنبه است و یا جمعه-دوشنبه-چهارشنبه. روش یکسانه.

یک فیلد جدید به نام DAY_OF_WEEK به جدول اضافه کنین که مقادیر 1 تا 7 متناظر با شنبه تا جمعه رو قرار هست بگیره.
با همین لاجیک فیلدهای WEEK_GROUP و DAY_GROUP رو حساب کنین.
فرض کنید که سه روز انتخاب کردین: یکشنبه - سه شنبه - جمعه.
معنیش این هست که بازای مقدار 1 (اولین روز انتخابی) در فیلد DAY_GROUP مقدار DAY_OF_WEEK باید بشه 2 (یکشنبه)
و بازای مقدار2 باید بشه 4
و بازای مقدار 3 (سومین روز) باید بشه 7 (جمعه)
تنها کاری که انجام باید بدین پیاده کردن لاجیک برای ساختن کد زیر در فرم هست:
DOCMD.RUNSQL "UPDATE TblName SET DAY_OF_WEEK=2 WHERE DAY_GROUP=1"
DOCMD.RUNSQL "UPDATE TblName SET DAY_OF_WEEK=4 WHERE DAY_GROUP=2"
DOCMD.RUNSQL "UPDATE TblName SET DAY_OF_WEEK=7 WHERE DAY_GROUP=3"

که با یک حلقه قابل ساخت هست.

Rasool-GH
سه شنبه 04 آبان 1395, 14:21 عصر
سلام بسیار بسیار ممنون
این هم روشی که خودم داشتم طراحی میکردم

mazoolagh
یک شنبه 09 آبان 1395, 14:04 عصر
برنامه رو ندیدم

به نتیجه رسیدین؟

Rasool-GH
یک شنبه 09 آبان 1395, 17:36 عصر
سلام همچنان در حال کار هستم یک قسمت از کار به نتیجه رسیده ولی هنوز نتیجه نهایی حاصل نشده . اگر امکان داره برای رفع این مشکل هم بنده رو راهنمایی کنید .

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

mazoolagh
سه شنبه 11 آبان 1395, 14:00 عصر
الان برنامه رو دیدم
خواسته ها تغییر کرده
باید دقیقتر نگاه کنم
...
...
...
Time

mazoolagh
شنبه 15 آبان 1395, 08:54 صبح
در واقع الان با سه مسئله روبرو هستیم:
1- دسته بندی رکوردها در دو گروه (که تمام شد)
2- انتساب هر یک از اعضای دسته کوچک به یک روز هفته
3- تطبیق نتایج با یک جدول ترتیبی (تقویم)


برای راحتی بخش یک رو که قبلا حل شد در یک سابروتین گذاشتیم:
Sub CALC_GROUPS(GroupSize As Integer, Days As Integer)
Dim RS As Recordset
Set RS = CurrentDb.OpenRecordset("Items", dbOpenDynaset)
Do While Not RS.EOF
RS.Edit
RS!WEEK_GROUP = (RS.AbsolutePosition \ (GroupSize * Days)) + 1
RS!DAY_GROUP = (RS.AbsolutePosition Mod (GroupSize * Days)) \ GroupSize + 1
RS.Update
RS.MoveNext
Loop
RS.Close
Set RS = Nothing
End Sub


با فرض اینکه هفت چک باکس برای روزهای هفته در فرم داریم (WD1 تا WD7) کد بخش 2 یک چیزی شبیه کد زیر میشه:
Dim i, Days As Integer
Dim WDS() As Integer
Dim CTL As Control
Days = 0
For i = 1 To 7
Set CTL = Me.Controls("WD" + Trim(i))
If CTL.Value Then
Days = Days + 1
ReDim Preserve WDS(Days)
WDS(Days) = i
End If
Next
Call CALC_GROUPS(Me.GROUP_SIZE, Days)
For i = 1 To Days
DoCmd.RunSQL ("UPDATE Items SET DAY_OF_WEEK=" & WDS(i) & " WHERE DAY_GROUP=" & i)
Next
آرایه WDS روزهای انتخاب شده رو در خودش نگه میداره
و متغیر Days هم تعداد روزهای انتخاب شده


بخش سه یک کم پیچیده تر هست.
اینجا از یک جدول Calendar برای نگهداری روزهای تقویم فارسی استفاده میکنیم که سه فیلد داره:
تاریخ میلادی Ldate (اینجا نیازی بهش نداریم)
تاریخ خورشیدی Pdate
و DayOfWeek که مشخص میکنه چند شنبه هست

روش کار:
رکوردها رو به ترتیب دسته بندی میخونیم
از جدول Calendar اولین تاریخ رو براساس اینکه رکورد موردنظر به چندشنبه منتسب شده پیدا میکنیم:
Dim LastDate As Long
LastDate = Me.START_DATE
Dim WG, DOW As Integer
Dim Xdate As Long
Dim RS As Recordset
Set RS = CurrentDb.OpenRecordset("SELECT * FROM Items ORDER BY WEEK_GROUP,DAY_GROUP")
Do While Not RS.EOF
DOW = RS!DAY_OF_WEEK
Xdate = DMin("Pdate", "Calendar", "Pdate>=" & LastDate & " AND DayOfWeek=" & DOW)
LastDate = Xdate
RS.Edit
RS!Pdate = Xdate
RS.Update
RS.MoveNext
Loop
RS.Close
Set RS = Nothing

تمام!

برای راحتی دیتابیس نمونه رو پیوست کردم

ممکنه آلگوریتم بهتر و کد تمیزتر هم باشه که میذارم بعهده خودتون

Rasool-GH
شنبه 15 آبان 1395, 11:33 صبح
خیلی لطف کردید زمان صرف کردین . متشکر .
صرفا جهت بررسی عرض میکنم که وقتی یک روز در هفته انتخاب میشه تاریخها یکی میشه و تغییر نمیکنه و زمانی که دو روز در هفته انتخاب میشه تاریخ سال بعد محاسبه میشه .
از کدها ایده برداری میکنم و بعد از تکمیل همینجا قرار میدم برای استفاده سایرین

Rasool-GH
چهارشنبه 26 آبان 1395, 15:28 عصر
سلام خدمت دوست غزیز
mazoolagh (http://barnamenevis.org/member.php?9893-mazoolagh)
بابت زحمتی که کشیدید بسیاد متشکر هستم . از کد شما استفاده کردم و کلا برنامه را تغییر دادم . خواسته بنده کاملا براورده شد .
لطفا بفرمایید در صورتی که بخوام همزمان در 2 سلول از جدول مقادیری رو قرار بدم کد چه تغییری میکنه ؟


CurrentDb.Execute "INSERT INTO tbltarikh (tarikh) VALUES(" + Trim(FinalT) + ")"

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

mazoolagh
پنج شنبه 27 آبان 1395, 10:08 صبح
در صورتی که بخوام همزمان در 2 سلول از جدول مقادیری رو قرار بدم کد چه تغییری میکنه ؟
فیلدها و مقادیر رو با کاما از هم جدا کنین:

INSERT INTO TblName (fld1,fld2,...) VALUES (vlu1,vlu2,..)



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

PUBLIC FUNCTION RMS(A AS DOUBLE , B AS DOUBLE) AS DOUBLE
RMS=SQR(A ^ 2 + B ^ 2)
END FUNCTION

SELECT A , B , RMS([A],[B]) AS XRMS FROM ...

Rasool-GH
دوشنبه 01 آذر 1395, 11:14 صبح
سلام . ممنون بابت کمک خوبتون


CurrentDb.Execute "INSERT INTO tbltarikh (tarikh) VALUES(" + Trim(FinalT) + ")"

جسارتا در این کد چرا از trim استفاده شده ؟ چرا وقتی Trim رو حذف میکنم کد اجرا نمیشه ؟

لطف میکنید بفرمایید برای پر کردن ستون ردیف در یک جدول که اطلاعاتش موجود هست از چه کدی استفاده کنم . به عبارت میخوام اطلاعات داخل یک یا چند سلول از یک جدول رو به روزرسانی کنم .

mazoolagh
سه شنبه 02 آذر 1395, 12:45 عصر
برای خوانا بودن کدها لطفا از تگ هایی گه در ادیتور هست استفاده کنین: SQL,VB, ...


در این کد چرا از trim استفاده شده ؟ چرا وقتی Trim رو حذف میکنم کد اجرا نمیشه ؟


اونچه که به currentdb.execute ارسال میشه باید از نوع string باشه.
وقتی از اپراتور + برای اتصال مقادیر استفاده میکنین همه مقادیر بیاد از یک جنس باشن: یا string یا عدد
اپراتور + بصورت خودکار تبدیل انجام نمیده

ولی اگر از اپراتور & برای اتصال مقادیر استفاده کنین بصورت خودکار مقادیر عددی رو به string تبدیل میکنه.

بنابراین عبارتهای
"aaa" + trim(3+5)
"aaa" & (3+5)
هر دو درسته و میشه aaa8

ولی عبارت
"aaa" + (3+5)
از نظر مفسر VBA نادرست هست

در کد شما مقدار FinalT عدد هست و چون از + استفاده کردین باید به راهی تبدیل به string بشه که یکی از این راه ها تابع trim هست.
در غیر اینصورت باید بجای + از & استفاده کنین.

mazoolagh
سه شنبه 02 آذر 1395, 12:50 عصر
برای پر کردن ستون ردیف در یک جدول که اطلاعاتش موجود هست از چه کدی استفاده کنم . به عبارت میخوام اطلاعات داخل یک یا چند سلول از یک جدول رو به روزرسانی کنم .

اینو دقیق متوجه نشدم. یک جدول هست که دیتا داره و میخواین یک فیلد شمارنده بهش اضافه کنین؟
در محاسبات بکار میره یا در گزارش (چون در گزارش برای داشتن شماره ردیف نیازی به بودن این فیلد در جدول نیست)

بیشتر باز کنین پرسش رو شاید اصلا نیازی نباشه.

در مورد update هم فکر کنم در همین تاپیک نمونه کد بود: هم کد sql و هم از طریق recordset

Rasool-GH
سه شنبه 02 آذر 1395, 23:55 عصر
سلام از اطلاعاتی که در اختیار بنده قرار دادید متشکرم

لطفا نمونه رو بررسی کنید . با اینکه متغیر از نوع رشته است و از اپراتور & هم استفاده کردم ولی باز هم در حالتی که قصد دارم تاریخ به همراه "/" ذخیره بشه مشکل دارم و مقدار متغییر به عدد اعشاری تبدیل میشه (حتی با استفاده از Trim).

سوال دوم بنده هم که مفهوم نبود در خصوص اپدیت همین جدول هست که با یک تابع ستون تاریخ رو تکمیل میکنم و با تابع دیگری قصد دارم ستون ردیف رو جهت ایجاد ارتباط با جداول دیگه بر مبنای ردیف تکمیل کنم .

mazoolagh
یک شنبه 07 آذر 1395, 11:07 صبح
چند تا نکته:


همیشه در کدنویسی از indent (همون tab) برای فرمت بلوک ها استفاده کنین تا برنامه خواناتر باشه
مقادیر string همیشه باید داخل کوتیشین (' یا ") باشن
برای ردیف از شمارنده استفاده کنین (اینجا j هست)
میتونستین تاریخ رو به شکل عدد استفاده کنین و بجاش براش فرمت تعریف میکردین (مطلقا بهتر از تاریخ از نوع استرینگ هست بخصوص در محاسبات) ولی چون خواسته تون این نیست از تابع format استفاده کنین


Private Sub Command7_Click()
Dim I As Integer
Dim Ii As Integer
Dim DayNo As Integer
Dim PreDay As Integer
Dim DaySum As Integer
Dim FinalT As String
Dim j As Integer ' Declare Counter
CurrentDb.Execute "DELETE FROM tbltarikh"
DayNo = DayWeekNo(Me.Tarikh)
DaySum = 0
PreDay = 0
j = 0 ' Initialize Counter
For I = 1 To Me.totalno
Select Case DayNo
Case 0
If CBool(Ch0) Then
DaySum = DaySum + 1
End If
Case 1
If CBool(Ch1) Then
DaySum = DaySum + 1
End If
Case 2
If CBool(Ch2) Then
DaySum = DaySum + 1
End If
Case 3
If CBool(Ch3) Then
DaySum = DaySum + 1
End If
Case 4
If CBool(Ch4) Then
DaySum = DaySum + 1
End If
Case 5
If CBool(Ch5) Then
DaySum = DaySum + 1
End If
Case 6
If CBool(Ch6) Then
DaySum = DaySum + 1
End If
End Select

If DaySum > PreDay Then
PreDay = DaySum
If Me.fr1 = 1 Then
FinalT = AddDay(Me.Tarikh, I - 1)
Else
FinalT = Slash(AddDay(Me.Tarikh, I - 1))
End If
For Ii = 1 To Me.hajm
j = j + 1 ' Update Counter
CurrentDb.Execute "INSERT INTO tbltarikh (tarikh, radif) VALUES('" & Format(FinalT, "####/##/##") & "'," & j & ")"
Next
End If

DayNo = DayNo + 1
If DayNo = 7 Then
DayNo = 0
End If
Next
DoCmd.OpenTable "tbltarikh"
End Sub

Rasool-GH
دوشنبه 08 آذر 1395, 19:40 عصر
خیلی خیلی ممنون . واقعا راهنمایی های خوبتون قابل تقدیره

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

mazoolagh
شنبه 13 آذر 1395, 13:24 عصر
کد آپدیت جدول هست که
فیلد radif رو براتون اضافه کردم

در هر صورت روش همینهاست که اشاره شد