ออกแบบตารางรับฝากเงิน
กระทู้เก่าบอร์ด อ.Yeadram

 6,725   32
URL.หัวข้อ / URL
ออกแบบตารางรับฝากเงิน

ใครมีประสบการในการออกแบบตารางรับฝากเงินมั่งครับ
ผมคิดได้ 2 แบบ แต่ไม่แน่ใจว่ามันจะดีไม่ดีต่างกันแบบไหน ใครมีประสบการช่วยแนะนำหน่อยครับ
วิธีแรกก็คือ ช่องจำนวนเงินเป็นฟิลด์เดียวทั้งรับฝากและถอน
วิธีที่ 2 แยกเป็นฟิลด์ฝาก กับฟิลด์ถอน
นั่งคิดอยู่พักหนึ่ง มีข้อดีข้อเสียต่างกัน แต่ ยาวๆ แล้วไม่รู้ว่าอะไรดีกว่าอะไร
ใครมีประสบการณ์ แนะนำกันหน่อยครับ

32 Reply in this Topic. Dispaly 2 pages and you are on page number 1

1 @R07641
โดยส่วนตัวเห็นว่าควรแยกครับ เพราะถ้าไม่แยก ยังไงคุณก็ต้องมีอีกฟิลด์หรือใช้ค่าบวกค่าลบเป็นตัวบ่งบอกว่าเป็นฝากหรือถอน เมื่อทำอย่างนั้นแล้ว เวลาต้องการหาว่าเป็นเงินฝากหรือถอน ก็ต้องมานั่งทำ if หรือ iif อีก ซึ่งมันก็ไม่ได้ลดงานอะไรลงไปเลย
2 @R07680
ผมใช้แบบที่ อาจารย์แนะนำครับ ตอนนี้มาติดให้คิดตรงเงินคงเหลือครับ
รู้สึกใน Report จะรวมค่าในแต่ละเรคคอร์ดได้ แต่ผมกำลังทำใน ฟอร์ม
ไม่ทราบว่ามันรวมได้มั้ยครับ
วันที่      ฝาก    ถอน    คงเหลือ
1/1/2554          500                                   500
2/1/2554          500                                1,000
3/1/2554                            200                 800

ตรงคงเหลือ ทำอย่างไรครับ อาจารย์ และเพื่อนๆ แนะนำด้วยครับ
3 @R07681
ฟอร์มไม่เหมือนรายงาน ไม่สามารถทำอย่างนั้นได้ วิธีที่ใช้คือ สร้างเทเบิลชั่วคราวขึ้นมาเพื่อเก็บข้อมูลที่เราต้องการแสดง ในเทเิบิลนี้ให้มีฟิลด์คงเหลือเพิ่มขึ้นมาอีกฟิลด์ แล้วเราก็คำนวนหายอดคงเหลือในแต่ละบรรทัดใส่เข้าไป จากนั้นจึงค่อยเอามาแสดงในฟอร์มครับ
4 @R07682
ขอบคุณครับ เดี๋ยวลองทำแปปนึงครับ
5 @R07684
อ.สันติสุขครับ ผมเพิ่มฟิลด์คงเหลือ แล้ว
และสร้าง Query ขึ้นมาเลือกฟิลด์รหัสสมาชิก ฟิลด์ฝาก ฟิลด์ถอน
เลือกGroupbyรหัสสมาชิก Sumฟิลด์ฝาก Sumฟิลด์ถอน แล้วเพิ่มฟิลด์ Sumฟิลด์ฝาก + Sumฟิลด์ถอน
แล้วในฟอร์ม ผมก็ใช้กล่องข้อความ Dlookup ฟิลด์Sumฟิลด์ฝาก + Sumฟิลด์ถอน โดย มีเงื่อนไขที่รหัสสมาชิก
ในฟอร์มตรงกล่องข้อความ ฝาก และถอน ผมใช้Event AfterUpdate
ฟิลด์คงเหลือ = me.ฟิลด์ที่Dlookup +ฟิลด์ฝาก-ฟิลด์ถอน

ค่าที่ได้ออกมาตรงตามต้องการครับ ไม่แน่ใจว่าทำแบบนี้จะมีผลกระทบอะไรบ้างครับ เพราะมันเป็นเรื่องเงิน จะผิดพลาดไม่ได้ แต่ผมก็ยังคิดไม่ถึงว่ามันจะมีเหตุการอะไร ทำให้ผิดพลาดบ้าง

6 @R07690
ตกลงว่าต้องการแสดงอย่างเดียวเหมือนในรายงาน หรือสามารถป้อนแล้วหาค่าคงเหลือให้ได้ด้วย ถ้าเป็นอย่างหลัง ผมว่าจะมีปัญหาครับ เช่น คุณป้อนไป 5 บรรทัดแล้วกลับมาแก้ไขบรรทัดที่ 3 รับรองว่าคงเหลือในบรรทัดที่ 3 ผิดแน่นอน หรือแม้แต่ป้อนบรรทัดที่ 5 แล้วกลับมาแก้ช่องฝาก หรือถอนของบรรทัดที่ 5 เองก็น่าจะได้ค่าคงเหลือที่ผิดนะครับ

การคำนวนควรต้องเกิดขึ้นใน Form_AfterUpdate event ของแต่ละบรรทัด (เรคอร์ด) ครับ ไม่ใช่ที่ของช่องฝากหรือช่องถอน และการคำนวนไม่ใช่เป็นการหา Sum ของทั้งหมดทุกบรรทัด แต่ต้องเป็นการทำไล่มาทีละบรรทัดจากวันที่น้อยไปวันที่มาก ซึ่งต้องเขียนเป็นโปรแกรมครับ ให้โปรแกรมอ่าน RecordSet ของสมาชิกคนนี้ โดยมีเงื่อนไขว่า เอาเฉพาะเรคอร์ดที่เริ่มตั้งแต่วันที่กำลังแก้ไขไปจนหมด แล้วคำนวนยอดคงเหลือทีละบรรทัด ซึ่งเท่ากับ ยอดคงเหลือของบรรทัดที่แล้ว (ควรเก็บไว้ในตัวแปร) แล้วบวกด้วยเงินฝากของบรรทัดนี้ ลบกับเงินถอนของบรรทัดนี้ครับ ทำอย่างนี้ไปจนครบทุกเรคอร์ดครับ เสร็จแล้วก็สั่ง Me.Refresh เพื่อดึงข้อมูลที่คำนวนใหม่ให้มาแสดงครับ
7 @R07698
อาจารย์ครับผมเขียน โมดูลไม่เป็นครับ เอามาประยุกต์ หรือแปลงจากที่คนอื่นคิดพอทำได้ครับ เลยคิดออกมาแบบนั้น แล้วที่อาจารย์แนะนำมันก็ถูกต้องเลยครับ อาจารย์พอมีตัวอย่างให้ทำมั้ยครับ
8 @R07699
ไว้ตอนค่ำๆผมจะมาดูให้ครับ
9 @R07700
ขอบพระคุณอาจารย์มากครับ
10 @R07709
แต่เดิมคิดว่าการคำนวนทำเฉพาะจากบรรทัดที่แก้ไขเป็นต้นไปก็น่าจะได้ แต่จะเกิดปัญหาเมื่อข้อมูลบนหน้าจอไม่ได้เรียงตามวัน และ/หรือมีการป้อนข้อมูลย้อนหลัง จึงต้องให้คำนวนตั้งแต่เริ่มต้นวันแรกของการฝาก-ถอนจนถึงวันสุดท้าย และยังมีข้อกำหนดว่าตัวเลือก Record Changes ต้องถูกทำเครื่องหมายไว้ด้วย (จากเมนู Tools - Option - Edit/Find) เพราะถ้าไม่ทำเครื่องหมายไว้ Form_AfterDelConfirm event จะไม่ทำงาน และจะทำให้โปรแกรมไม่คำนวนใหม่เมื่อมีการลบบรรทัดใดบรรทัดหนึ่งไป

สมมุติว่าฟอร์มที่ป้อนข้อมูลสร้างจากเทเบิลที่ใช้ชื่อว่า tbDep ซึ่งมีฟิลด์ต่อไปนี้
- DepDate วันที่ฝาก-ถอน
- DepAmt จำนวนฝาก
- WithAmt จำนวนถอน
- BalAmt จำนวนคงเหลือ

Private Sub Form_AfterDelConfirm(Status As Integer)
' ทำการคำนวนเมื่อมีการลบรายการ
    If Status = acDeleteOK Then Call GenBalAmt
End Sub

Private Sub Form_AfterUpdate()
' ทำการคำนวนเมื่อมีการเพิ่ม/แก้ไขรายการ
    Call GenBalAmt
End Sub

Private Sub GenBalAmt()
' ฟังก์ชั่นที่ทำการคำนวน
    Dim DB                  As DAO.Database
    Dim RS                  As DAO.Recordset
    Dim RSClone             As DAO.Recordset
    Dim InTransaction       As Boolean
    Dim LastBalAmt          As Variant
    
On Error GoTo ErrRoutine

    InTransaction = False
    
    Set DB = CurrentDb
    
    ' อ้างถึง recordset ที่เป็นชุดเดียวกันกับที่แสดงบนหน้าฟอร์ม
    Set RSClone = Me.RecordsetClone
    
    ' ถ้า recordset ไม่มีข้อมูล (จากกรณีลบทิ้งหมดทุกรายการ) ก็ไม่ต้องคำนวน
    If RSClone.RecordCount <= 0 Then GoTo ExitRoutine
    
    ' กำหนดให้การเรียงลำดับเป็นไปตามวันที่ฝาก-ถอน (เพราะที่หน้าจออาจถูกผู้ใช้กดให้เรียงไปตามอย่างอื่นอยู่ เช่น เรียงจากจำนวนฝาก-ถอนอยู่)
    RSClone.Sort = "DepDate"

    ' สร้าง recordset ที่เรียงตามวันที่ฝาก-ถอน
    Set RS = RSClone.OpenRecordset
    
    LastBalAmt = 0
       
    DBEngine.BeginTrans: InTransaction = True
    Do Until RS.EOF
        RS.Edit
            RS!BalAmt = LastBalAmt + RS!DepAmt - RS!WithAmt
        RS.Update
        LastBalAmt = RS!BalAmt
        RS.MoveNext
    Loop
    DBEngine.CommitTrans dbForceOSFlush: InTransaction = False
    
    Me.Refresh
    
ExitRoutine:
    If InTransaction Then DBEngine.Rollback: InTransaction = False
On Error Resume Next
    RSClone.Close: Set RSClone = Nothing
    RS.Close: Set RS = Nothing
    DB.Close: Set DB = Nothing
    Exit Sub

ErrRoutine:
    MsgBox Err.Number & " : " & Err.Description
    MsgBox "เกิดผิดพลาดระหว่างการตำนวนยอดคงเหลือ ค่ายอดคงเหลือไม่สามารถเชื่อถือได้ต่อไป"
    Resume ExitRoutine
End Sub

ลองเล่นดูครับ
11 @R07713
อาจารย์ครับ event Form_AfterDelConfirm ผมไม่เคยใช้เลยครับ เลยไม่รู้มันทำงานอย่างไร แต่ก็ลองก๊อปไปทำดู มันก็รันได้ครับ แต่ผลที่ออกมายังผิดอยู่ครับ
ผิดตรงที่มันไม่แยกคำนวนเป็นคนๆ ครับ มันรวมทุกคนเลยครับ เลยกลับไปอ่านดูที่โคต สังเกตว่าไม่มีตรงไหนอ้างอิงที่สมาชิกเลยครับ คิดว่าอาจจะต้องมีการกรอง หมายเลขสมาชิกก่อน แต่ก็ไม่รู้ใส่ตรงไหนครับ ฝากอาจารย์ดูอีกทีครับ
12 @R07715
ใช่ครับ โค้ดที่ผมให้ไปไม่ได้มีอะไรเกี่ยวกับเรื่องสมาชิก เพราะก่อนการแสดงบนฟอร์ม คุณต้องมีกระบวนการเพื่อเลือกเฉพาะสมาชิกที่ต้องการมาแสดงเท่านั้น ส่วนโค้ดก็จะทำกับเรคอร์ดที่อยู่บนฟอร์ม ซึ่งก็จะทำกับสมาชิกคนนั้นไปโดยปริยาย

ทีนี้มันอยู่ที่การออกแบบของคุณว่า จะเลือกวิธีไหนในการเลือกสมาชิกที่จะมาแสดง เช่น

- มีหน้าฟอร์มอื่นอยู่แล้วที่มีรหัสสมาชิกแสดงอยู่ แล้วจากหน้าจอนั้น เมื่อกด/คลิกอะไรบางอย่าง จึงค่อยมาแสดงหน้าจอป้อนฝาก-ถอนนี้

หรือ

- ที่หัวของฟอร์มนี้มี Combobox ให้เลือกว่าต้องการป้อนข้อมูลของสมาชิกคนไหน เมื่อเลือกแล้วก็จะแสดงข้อมูลฝาก-ถอนของสมาชิกคนนี้ในฟอร์มนี้เลย

หรือ

- คุณจะให้มี Combobox อยู่ใน main form เพื่อเลือกว่าต้องการป้อนข้อมูลของสมาชิกคนไหน แล้วข้อมูลฝาก-ถอนก็จะแสดงใน sub form

หรืออื่นๆ

คุณใช้แบบไหนครับ ผมว่าทุกวิธีเคยมีการถาม-ตอบในบอร์ดนี้แล้วนะครับ ลองค้นหาดู

ปล.ผมจะเข้ามาอีกทีตอนค่ำครับ
13 @R07717
ฟอร์มที่ทำอยู่ มีวันที่บันทึก แล้วให้เลือกสมาชิก แล้วค่อยเลือกว่าฝากหรือถอน จะนวนเท่าใด
พอใส่โคสที่อาจารย์ให้ไป เมื่อผมบันทึกเรียบร้อยแล้วที่ ช่องคงเหลือจะมีการคำนวน ตาโคตของอาจารย์ครับ เพียงแต่ว่า มันคำนวนทุกคนไม่ได้แยกสมาชิกครับ
จากการอ่านโคต ตามความเข้าใจของผม มันอ่านค่าฝากถอน จากตารางโดยไม่ได้ กรองสมาชิกจากตาราง หรือจาก Combo box ที่เลือกสมาชิกของผมครับ
14 @R07733
ลองใช้โค้ดนี้ดู สมมุติว่าฟิลด์รหัสสมาชิกชื่อว่า MemberCode และคอนโทรลบนฟอร์มก็ชื่อเดียวกันด้วย

Private Sub Form_AfterDelConfirm(Status As Integer)
    If Status = acDeleteOK Then Call GenBalAmt(Me.MemberCode)
End Sub

Private Sub Form_AfterUpdate()
    Call GenBalAmt(Me.MemberCode)
End Sub

Private Sub GenBalAmt(MemberCode As String)
    Dim DB                  As DAO.Database
    Dim RS                  As DAO.Recordset
    
    Dim SQL                 As String
    Dim InTransaction       As Boolean
    Dim LastBalAmt          As Variant
    
On Error GoTo ErrRoutine

    InTransaction = False
    
    Set DB = CurrentDb
    SQL = "select * from tbDEP where MemberCode = '" & MemberCode & "' order by DepDate"
    Set RS = DB.Recordsets(SQL)
    LastBalAmt = 0
    DBEngine.BeginTrans: InTransaction = True
    Do Until RS.EOF
        RS.Edit
            RS!BalAmt = LastBalAmt + RS!DepAmt - RS!WithAmt
        RS.Update
        LastBalAmt = RS!BalAmt
        RS.MoveNext
    Loop
    DBEngine.CommitTrans dbForceOSFlush: InTransaction = False
    
    Me.Refresh
    
ExitRoutine:
    If InTransaction Then DBEngine.Rollback: InTransaction = False
On Error Resume Next
    RS.Close: Set RS = Nothing
    DB.Close: Set DB = Nothing
    Exit Sub

ErrRoutine:
    MsgBox Err.Number & " : " & Err.Description
    MsgBox "เกิดผิดพลาดระหว่างการตำนวนยอดคงเหลือ ค่ายอดคงเหลือไม่สามารถเชื่อถือได้ต่อไป"
    Resume ExitRoutine
End Sub
15 @R07737
คิดไปคิดมา โค้ดในส่วน

Private Sub Form_AfterDelConfirm(Status As Integer)
    If Status = acDeleteOK Then Call GenBalAmt(Me.MemberCode)
End Sub

น่าจะใช้ไม่ได้ เพราะ event นี้เกิดหลังจากลบข้อมูลไปแล้ว ค่า MemberCode จึงอาจเป็นคนละค่ากับที่ก่อนลบครับ

ถ้าหน้าจอไม่มีการลบ ก็เอาส่วนนี้ออกไปเลยครับ
16 @R07739
อาจารย์ครับ มัน Compile Error ที่ Call GenBalAmt ครับ
17 @R07740
ผมลองเอา Me.MemberCode ออกจาก Call GenBalAmt(Me.MemberCode)
มันก็ Error อีก 3265:Item not found in this collection
18 @R07741
ผมสมมุติไว้ว่าฟิลด์รหัสสมาชิกชื่อว่า MemberCode ถ้าคุณใช้เป็นชื่ออื่น ก็เปลี่ยนชื่อไปครับ แล้วคอมไพล์ไม่ผ่านที่บรรทัดไหน รหัสอะไร บอกด้วยครับ
19 @R07742
ตั้งแต่ตรงนี้เลยครับ
Private Sub Form_AfterUpdate()
    Call GenBalAmt(Me.ID_Member )
End Sub
รหัสสมาชิกผมใช้ชื่อว่า ID_Member แต่ผมก็เปลี่ยนแล้วครับทุกตัว
20 @R07743
อาจารย์ครับผมส่งไฟล์ให้อาจารย์ดูที่ gmail น่าจะง่ายกว่าครับ อาจารย์จะได้ไม่ต้องเดาครับ ฝากดูด้วยครับ
@ ประกาศใช้งานเว็บบอร์ดใหม่ => บอร์ดเรียนรู้ Access สำหรับคนไทย
แล้วจะใส่ลิ้งอ้างอิงมาที่โพสต์เก่านี้หรือไม่ก็ตามสะดวกครับ
Time: 0.3363s