สอบถามเรื่อง Running Number หน่อยครับ
กระทู้เก่าบอร์ด อ.Yeadram

 3,721   13
URL.หัวข้อ / URL
สอบถามเรื่อง Running Number หน่อยครับ

Running ทีี่ต้องการจะออกมาในรูปแบบ BU & ปีจาก textbox : txtWHTSlipdate & Running 5 หลักครับ ("BU" & Year(txtWHTSlipdate) & Format(rs!DC + 1, "00000"))       
ซึ่งจากแบบเดิมที่ทำไว้เป็นเป็นการ Running ต่อครั้งที่ทำรายการคือ 1 Running ต่อทุกรายการที่ทำในครั้งนั้นครับ

##################################################################################################################################
โค้ดเก่าครับ ใช้เมื่อทำรายการ 1 ครั้งต่อ 1 Running
'Running BU
        'DoCmd.SetWarnings False
        Dim runbu As String
        Dim rs2 As DAO.Recordset, SQL4 As String
        'Check for 1st roll of BUClaim_Log (ดูว่าตารางนี้มีข้อมูลหรือยัง ถ้ายังไม่มีข้อมูลจะให้ถือเป็นรายการแรกของตาราง ให้ทำ Running เริ่มต้นเป็น "BUYYYY00001")
        SQL4 = "SELECT count(*) AS DC2 FROM [03BUClaim_Log] WHERE [BUClaim_ID] is NOT NULL " & " ;"
            Set rs2 = CurrentDb.OpenRecordset(SQL4)
        If rs2!DC2 = 0 Then
        runbu = "BU" & Year(Me.txtWHTSlipdate) & "00001"
        rs2.Close: Set rs2 = Nothing

        Else 'กรณีที่ไม่ใช่รายการแรกของตาราง

        'Check Running Year (ดูว่าปีของเอกสารเป็นปีใด เคยมีการ Running ในปีนั้นๆหรือไม่ ถ้ามีให้ Running ต่อจากที่เคย Run)
        Dim rs1 As DAO.Recordset, SQL3 As String
            SQL3 = "SELECT count(*) AS DC1 FROM [03BUClaim_Log] WHERE Mid([BUClaim_ID],3,4)= " & _
            "'" & Year(Me.txtWHTSlipdate.Value) & "'" & " ;"
            Set rs1 = CurrentDb.OpenRecordset(SQL3)
            
        If rs1!dc1 > 0 Then 'ถ้าปีของเอกสารเป็นปีที่เคยมีการบันทึกแล้วให้ Running ต่อจากเดิม
            Dim rs As DAO.Recordset, SQL2 As String
            SQL2 = "SELECT Max(Int(Mid([BUClaim_ID],7))) AS DC FROM [03BUClaim_Log] " & _
            "WHERE Year([txtWHTSlipdate]) = " & _
            "'" & Year(Me.txtWHTSlipdate.Value) & "'" & " ;"
            Set rs = CurrentDb.OpenRecordset(SQL2)
            runbu = "BU" & Year(Me.txtWHTSlipdate) & Format(rs!DC + 1, "00000")
            
            rs.Close: Set rs = Nothing


        Else 'ถ้าเป็นปีที่ไม่เคย Running มาก่อนและไม่ใช่รายการแรกของตารางให้ทำการ Running ของปีนั้นๆ ใหม่ที่ "BUYYYY00001"
            runbu = "BU" & Year(Me.txtWHTSlipdate) & "00001"
        End If
        rs1.Close: Set rs1 = Nothing
        End If



จากนั้นก็นำ runbu ไป Update ในตารางครับ
ซึ่งตอนนี้ต้องเปลี่ยนการ Running ใหม่เพราะต้องปรับการบันทึกรายการจากเดิม 1 ครั้งต่อ 1 Running Number เป็นบันทึกหลายรายการหลาย Running Number
ผมเคยอ่านเจอว่าการทำ running แบบที่เคยทำ(ตามโค้ด) ถ้าข้อมูลปริมาณเยอะจะทำให้การทำงานช้ามาก วิธีที่อ่านเจอแนะนำให้สร้างตารางเก็บค่า Max Running ไว้แล้วจึงเอาค่านั้นมาใช้ในการ Running ต่อครับ

แต่รูปแบบการ Running Number ของผมมันมีการดึงค่าปีของเอกสารมาใช้ด้วยผมเลยไม่รู้ว่าจะทำออกมาในรูปแบบไหนครับ

##################################################################################################################################

รูปแบบข้อมูลก่อนที่จะ Running นะครับ

ในตารางจะเก็บรายละเีอียดข้อมูล Field ต่างๆไว้ตามลำดับ(อาจมี 1 ไปจนถึง 100 รายการ)จากนั้นจะทำการ Running Number ลงใน Field ที่เว้นไว้ โดยที่การ Running จะต้องดูปีของเอกสารจาก Field WHTSlipdate ว่าเป็นปีใดก่อนแล้วจึง Running ต่อครับ

เช่นมีทั้งหมด 4 รายการ
1. รายการเลขที่เอกสาร JV005 วันที่เอกสาร 12/11/2013
2. รายการเลขที่เอกสาร TS87 วันที่เอกสาร 2/1/2014
3. รายการเลขที่เอกสาร 1182522 วันที่เอกสาร 27/12/2013
4. รายการเลขที่เอกสาร DD112533 วันที่เอกสาร 10/7/2013
และมี Running ในระบบของปี 2013 คือ BU201300088 และของปี 2014 คือ BU201400004
เลขที่จะได้ใน Field Running Number จะต้องเป็นแบบนี้ครับ (ตามลำดับ)
1. BU201300089
2. BU201400005
3. BU201300090
4. BU201300091

[GREEN]**ที่คิดไว้คิดว่าจะเก็บค่า Max Running Number แยกตามปีไว้ก่อนครับแล้วเวลา Running ก้ดึง Field ปีที่ตรงมาใช้(อาจมีปัญหากรณีที่ User กรอกวันที่เอกสารโดยใช้ปีผิดซึ่งอาจมีการให้ User Admin เข้ามาแก้ใน Field Running Number นี้ในภายหลังได้ครับ) แต่ผมก็ยังไม่รู้ว่าถ้าใช้ Query มา Running แทนจะทำได้โดยวิธีใดบ้างครับ รบกวนแนะนำหน่อยครับ

***เพิ่มเติมครับ Access ตัวนี้ผมเอาไปไว้ใน Drive กลางแล้วจะให้ User เข้ามาใช้งานจากหลายที่ ซึ่งตอนนี้รูปแบบปีที่ใช้ในระบบใช้ ค.ศ. ในการทำงานครับ ผมได้เขียน Label เตือน User ให้กรอกข้อมูลปีแบบ ค.ศ. แล้วครับ แต่ถ้าเป็นเรื่องวันที่ที่ให้ระบบ Gen จะมีผลกระทบบ้างมั้ยครับถ้าในเครื่อง user เป็นปี พ.ศ. (พวกField ที่เก็บวันที่ และัเวลาที่ User ทำรายการ(ใช้ now())) ผมจะต้องมีการปรับเปลี่ยนอะไรเพิ่มเติมสำหรับส่วนนี้มั้ยครับ

ขอบคุณมากครับ   

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

1 @R17836
ผมคิดว่ามี 2 วิธีที่ทำได้

1) เพิ่มฟิลด์ ปีของเอกสาร (Y) และ เลขรันนิ่ง5หลักสุดท้าย (R) ไว้เป็นฟิลด์ต่างหากอีก 2 ฟิลด์ และสร้างดัชนีจาก Y รวมกับ R   ดังนั้นใน sql ที่ค้นหาจะค้นจาก Y และ R แทน มันก็จะเร็วมากครับ   วิธีนี้มีข้อดีคือไม่ต้องเก็บ max running no. แต่ข้อเสียคือ ถ้าผู้ใช้ป้อนปีผิด คุณต้องมาแก้ทั้งเลขที่เอกสาร และ Y และ R ด้วยกันทั้งหมด

2) เก็บ max running no. ไว้ในตัวแปรอะเรย์แทน ไม่ต้องไปเก็บบันทึกลงเทเบิลต่างหาก เมื่อรันแต่ละครั้ง ก็เช็คก่อนว่าปีนั้นมีอยู่ในตัวแปรหรือยัง ถ้ายังก็เก็บลงใน element ที่เหมาะสมของตัวแปรอะเรย์ ถ้ามีแล้วก็แค่บวกเพิ่ม 1 เพิ่ม ข้อดีคือเร็วกว่า 1)   ข้อด้อยนิดๆคือ คุณต้องเขียนโปรแกรมเป็นครับ

*** ถ้าคุณใช้ now() โดยใส่ลงในฟิลด์ของเทเบิลที่มีประเภทข้อมูลเป็น Date/Time โดยตรงด้วย recordset ก็ไม่มีปัญหาอะไร เช่น RS!DateField = Now()   แต่ถ้าใช้ใน sql statement อาจมีปัญหาได้ครับ เช่น sql = "update ... set DateField = #" & now() & "# ...." คุณต้องแปลงหรือเช็คให้ดีๆก่อนว่ามันเป็น ค.ศ. นะ
2 @R17838
ขอบคุณมากครับ

สำหรับข้อ 1.ผมสามารถใช้ Query ช่วยในการทำ running เพื่อบันทึกข้อมูลลงตารางมั้ยครับเพราะจากที่ใช้ตอนนี้จะเป็นทำ running 1 ครั้ง ไม่ได้ทำทีละหลาย record พร้อมกันแบบนี้ครับ หรือถ้า Query ไม่เหมาะ ผมควรจะ

ในส่วนกรณีที่ผู้ใช้ใส่ปีผิด ที่คุยกับผู้ใช้ไว้คงจะเปิดให้เข้าแก้ไขข้อมูลฟิลนี้ได้ครับ(เฉพาะ Admin)

ข้อ 2 รบกวนขอแหล่งศึกษาจะเป็นหนังสือหรือเวปก็ได้ครับ อาจเป็นพวกคำค้น เผื่อไว้สำหรับต้องทำในครั้งต่อๆไปครับ

***ตอนนี้ที่ใช้จะเป็นแบบหลังครับคือประมาณนี้ครับ sql = "update ... set DateField = #" & now() & "# ...." พอจะมีวิธีเช็คมั้ยครับว่า User แต่ละเครื่องมีการตั้งค่าวันที่ในรูปแบบไหน (วว/ดด/ปปปป, ดด/วว/ปปปป หรือเป็น พ.ศ. หรือ ค.ศ.) เพราะส่วนใหญ่ที่เขียนตอนนี้เป็น Sql statement เก์อบทั้งหมดครับ ไม่ได้ให้ Update โดยใช้ recordset เลยครับ
3 @R17839
***หรือจะพอมีวิธีที่ปรับ now() ให้เป็น format ที่ต้องการประมาณนี้อะครับ
format(now(), "dd/mm/yyyy") โดยให้เป็นค.ศ.
4 @R17840
1) ผมไม่เข้าใจความหมายของคุณที่ว่าใช้คิวรี่ในการทำ running หมายถึงยังไง

2) ตัวแปรอะเรย์ สร้างด้วยคำสั่ง Dim X(n) as ... เช่น Dim X(10) as long ก็แปลว่าสร้างตัวแปร x(1),...,x(10) ที่เก็บค่า long integer เพราะค่ารันนิ่งคุณมี 5 หลัก เฉพาะแค่ integer เฉยๆอาจจะไม่พอเก็บ เวลาจะเรียกใช้ ก็อ้าง x(1) ก็คล้ายๆกับการอ้างชื่อตัวแปรทั่วไป เพียงแต่ต้องมีวงเล็บเพื่อบอกว่าเป็นตัวที่เท่าไหร่นั่นเอง ถ้าคุณคิดว่าระบบนี้จะอยู่สัก 10 ปี และมีการอ้างย้อนหลังได้ถึงปี 2010 ก็ให้ปี 2010 อยู่ใน x(1) , 2011 อยู่ใน x(2) , ... ใช้บวกลบเลขนิดหน่อย ก็คือ x(ปี - 2009) เวลาสร้างก็สั่ง Dim X(10) as long ครับ

***
http://thai-access.com/yeadram_view.php?topic_id=2294
5 @R17841
ขอแก้ไขข้อ 1 ครับตกหล่นเยอะเลย

จะถามว่าผมสามารถใช้ Query ในการ running เลขได้มั้ยครับ ถ้าได้จะเป็นลักษณะไหนครับ

ถ้าไม่ได้ผมจะดัดแปลงจากโค้ดเก่าซึ่งที่คิดไว้ก็น่่าจะประมาณว่า ดึงข้อมูลจากตารางเฉพาะที่ running = null มา count แล้วจึงมาใช้ for loop เพื่อใส่ running ทีละรายการแบบนี้มั้ยครับ
6 @R17844
Query ที่เป้นตัวช่วยในโปรแำกรมน่ะครับที่ไม่ใช่เขียนโค๊ดแบบ VBA

คือตอนนี้ที่กำลังสงสัยเป็นในส่วนการ Update Running เข้าไปในแต่ละบรรทัดครับว่าจะใช้วิธีใด

เช่นมีทั้งหมด 4 รายการ
1. รายการเลขที่เอกสาร JV005 วันที่เอกสาร 12/11/2013
2. รายการเลขที่เอกสาร TS87 วันที่เอกสาร 2/1/2014
3. รายการเลขที่เอกสาร 1182522 วันที่เอกสาร 27/12/2013
4. รายการเลขที่เอกสาร DD112533 วันที่เอกสาร 10/7/2013
และมี Running ในระบบของปี 2013 คือ BU201300088 และของปี 2014 คือ BU201400004
เลขที่จะได้ใน Field Running Number จะต้องเป็นแบบนี้ครับ (ตามลำดับ)
1. BU201300089
2. BU201400005
3. BU201300090
4. BU201300091

คือของเดิมที่ทำมาจะมีรายการเดียวที่ต้อง running
เช่น แค่ 1. BU201300089 รายการเดียวแล้วจบเลย เลยไม่มีปัญหาว่าต้องมาดู record ต่อไปต่อว่าจะเป็นเลขใดครับ ที่คิดไว้ตามความเห็นที่แล้ว(ที่คิดว่าจะใช้ For ... Next Loop) ผมคิดว่าถ้าข้อมูลเริ่มเยอะคงช้าแน่นอน
เพิ่มเติมหน่อยครับถ้าผมแยก Field ปีออกจาก running แล้วทำ Index ผมต้องเปลี่ยนวิธีค้นหา Running Max NO ด้วยใช่มั้ยครับซึ่งต้องแยกไปดูปีก่อน แล้วจึงมาดึง Running มาใช้ต่อ

คำอธิบายอาจอ่านแล้วงงๆ ถ้ายังไงผมจะพยายามเรียบเีรียงแล้วโพสใหม่อีกครั้งในช่วงค่ำนะครับ
7 @R17845
ถ้าคุณหมายถึงคิวรี่เดียวแล้วรันเลขให้ทีละหลายๆเรคอร์ดเลย ผมยังคิดไม่ออกว่ามันจะทำยังไงได้ในกรณีนี้ วิธีก็จะเป็นอย่างที่คุณคาดไว้ถูกแล้วครับ ต้องวนลูปทำทีละเรคอร์ดเอาครับ
8 @R17847
ขอบคุณครับอาจาร์ย ผมจะไปลองดูครับคิดว่าน่าจะออกไปในรูปแบบตามที่คิดไว้ครับ ถ้ามีประเด็นหรืออาจติดตรงไหนก็ขอรบกวนด้วยนะครับ
9 @R17856
ขอบคุณอาจารย์มากเลยครับ ตอนนี้ทำได้แล้วครับ ได้ผลมาตามที่ต้องการแต่ผมยังไม่รู้ว่าจะช้าแค่ไหนตอนใช้งานจริงครับ

VBA Code ที่ใช้ครับ

        'Running BU
               Dim rst As DAO.Recordset
            SQL = "SELECT * FROM [03BUClaim_LogSum] Where [BUClaim_ID] is NULL or [BUClaim_ID] = '' ;"
     
     Set rst = DBEngine(0)(0).OpenRecordset(SQL)
   'Loop
    Do Until rst.EOF
        Dim runbu As String
        Dim rs2 As DAO.Recordset, SQL4 As String
        'Check for 1st roll of BUClaim_Log
        SQL4 = "SELECT count(*) AS DC2 FROM [03BUClaim_LogSum] WHERE [BUClaim_ID] is NOT NULL " & " ;"
            Set rs2 = CurrentDb.OpenRecordset(SQL4)
        If rs2!DC2 = 0 Then
        runbu = "BU" & Year(rst![WHT_Slip_Date]) & "00001"
        rs2.Close: Set rs2 = Nothing
        Else
        'Check Running Year
        Dim rs1 As DAO.Recordset, SQL3 As String
            SQL3 = " SELECT count(*) AS DC1 FROM [03BUClaim_LogSum] WHERE Mid([BUClaim_ID],3,4) = " & _
            "'" & Year(rst![WHT_Slip_Date]) & "'"
            Set rs1 = CurrentDb.OpenRecordset(SQL3)
        If rs1!dc1 > 0 Then
            SQL = "SELECT Max(Int(Mid([BUClaim_ID],7))) AS DC FROM [03BUClaim_LogSum] " & _
            "WHERE Mid([BUClaim_ID],3,4) = " & _
            "'" & Year(rst![WHT_Slip_Date]) & "'" & " ;"
            Set rs = CurrentDb.OpenRecordset(SQL)
            runbu = "BU" & Year(rst![WHT_Slip_Date]) & Format(rs!DC + 1, "00000")
            rs.Close: Set rs = Nothing
        Else
            runbu = "BU" & Year(rst![WHT_Slip_Date]) & "00001"
        End If
        rs1.Close: Set rs1 = Nothing
        End If
        'Update Running BU
        rst.Edit
            rst![BUClaim_ID] = runbu
        rst.Update
          rst.MoveNext
    Loop
    Set rst = Nothing



มีตรงไหนที่ดูแล้วไม่เหมาะสมรบกวนแนะนำนะครับจะได้เอาไปปรับใช้ในเรื่องต่อๆไป

*เพิ่มเติมครับ Set rst = CurrentDb.OpenRecordset(SQL) กับ Set rst = DBEngine(0)(0).OpenRecordset(SQL) แตกต่างกันอย่างไรครับ

ขอบคุณครับ
10 @R17858
ผมยังไม่เห็นว่าโค้ดของคุณมันจะต่างยังไงกับวิธีเดิมเลยนะครับ แค่เพิ่มลูปขึ้นมา (ซึ่งก็ต้องใช้ลูปแน่นอนอยู่แล้วเพื่ออัพเดตหลายๆเรคอร์ด) แต่วิธีการไม่ได้ช่วยในเรื่องความเร็วอะไรเลยนะครับ

สมัยก่อนไม่มี CurrentDb ครับ เลยต้องอ้างจาก DBEngine(0)(0) แทน แนะนำเขียนโดยใช้ CurrentDB ครับ
11 @R17860
จริงๆ ก็ไม่ต่างครับ แต่ตอนที่เข้ามาถามผมยังไม่รู้ว่าต้องเขียน Loop แบบไหนเลยครับ พอได้วิธี Loop เลยเอามาครอบ

ส่วนที่สร้าง Index ผมไปปรับในตารางField running ให้เป็น Yes(duplicate Ok) แล้วครับ ไม่ทราบว่าใช่ตามที่อาจารย์แนะนำมั้ยครับ

ซึ่งถ้าแยก Field เพิ่มโดยแยกปีออกมา เวลาค้นหาให้ไปเริ่มค้นหาจากปีก่อน ถ้าเจอก็ไปดูใน field running ต่อมันจะทำให้ทำงานเร็วกว่า ผมเข้าใจถูกมั้ยครับ
12 @R17864
เวลาแยกฟิลด์แล้ว เมื่อเราค้นโดยเงื่อนไข "SELECT Max(ฟิลด์รันนิ่ง) FROM เทเบิล WHERE ฟิลด์ปี = " & Year(Me.txtWHTSlipdate) จะเร็วมากครับ อย่าลืมต้องทำดัชนีที่รวมฟิลด์รันนิ่ง+ปีไว้เป็นดัชนีตัวเดียวด้วยนะครับ ไม่ใช่แยก 2 ดัชนีนะครับ
13 @R17867
ขอบคุณครับอาจารย์ ถ้าลองแล้วได้ผลยังไงจะมาบอกนะครับ
@ ประกาศใช้งานเว็บบอร์ดใหม่ => บอร์ดเรียนรู้ Access สำหรับคนไทย
แล้วจะใส่ลิ้งอ้างอิงมาที่โพสต์เก่านี้หรือไม่ก็ตามสะดวกครับ
Time: 0.3403s