กระทู้เก่าบอร์ด อ.Yeadram
2,714 8
URL.หัวข้อ /
URL
ขอหลักการ และ ความเข้าใจที่ถูกต้อง ครับ
1.คำว่า Me.CurrentRecord คลุมถึง Me.NewRecord ด้วยหรือไม่
หมายความว่า Me.NewRecord เป็น SUB SET ของ Me.CurrentRecord
ใช่หรือไม่ เช่น ขณะเพิ่ม RECORD ใหม่(newrecord) ซึ่งขณะนี้ก็เป็น
current record ด้วยถูกไหมครับ ดังนั้นใช้ ME.CurrentRecode ก้ได้ ?
เพราะตอนนี้ ผมสับสน ในการอ้าง เวลาเขียนโปรแกรมมากครับ
2.เวลาผมทำ FORM แบบ DATASHEET ในส่วนของ DETAIL ถ้าผม
วาง CONTROL เปล่า ที่เก็บค่าจากการคำนวนฯซักอย่าง
เช่น =CONTROL A *CONTROL B CONTROL เปล่าตัวนี้จะคำนวณ ทุก RECORD SET ใน FORM ที่ถูก LOAD ขึ้นมา ถูกหรือไม่
แต่ถ้าผมย้าย CONTROL เปล่าตัวนี้ไปไว้ที่ ส่วนท้ายของ form มันจะคำนวณ
เฉพาะ RECORD ปัจจุบันที่เราไปในส่วน Detail ถูกหรือไม่
ตอนนี้ข้อมูลผมเริ่มเยอะ ผมสังเกตว่า การวาง CONTROL ทั้ง 2 แบบ มีผล
ต่อความเร็วที่ต่างกัน ถ้าข้อมูลไม่มากไม่ต่าง แต่ถ้า 20000- 30000 record
จะเริ่มเห็น แต่โดยหลักการเป้นเช่นไรแน่ ผมไม่ทราบเลย
เพราะที่ผ่านมา ก็เรียกว่าครูพักลักจำทั้งนั้น ขอบคุณทุกท่านครับ
หมายความว่า Me.NewRecord เป็น SUB SET ของ Me.CurrentRecord
ใช่หรือไม่ เช่น ขณะเพิ่ม RECORD ใหม่(newrecord) ซึ่งขณะนี้ก็เป็น
current record ด้วยถูกไหมครับ ดังนั้นใช้ ME.CurrentRecode ก้ได้ ?
เพราะตอนนี้ ผมสับสน ในการอ้าง เวลาเขียนโปรแกรมมากครับ
2.เวลาผมทำ FORM แบบ DATASHEET ในส่วนของ DETAIL ถ้าผม
วาง CONTROL เปล่า ที่เก็บค่าจากการคำนวนฯซักอย่าง
เช่น =CONTROL A *CONTROL B CONTROL เปล่าตัวนี้จะคำนวณ ทุก RECORD SET ใน FORM ที่ถูก LOAD ขึ้นมา ถูกหรือไม่
แต่ถ้าผมย้าย CONTROL เปล่าตัวนี้ไปไว้ที่ ส่วนท้ายของ form มันจะคำนวณ
เฉพาะ RECORD ปัจจุบันที่เราไปในส่วน Detail ถูกหรือไม่
ตอนนี้ข้อมูลผมเริ่มเยอะ ผมสังเกตว่า การวาง CONTROL ทั้ง 2 แบบ มีผล
ต่อความเร็วที่ต่างกัน ถ้าข้อมูลไม่มากไม่ต่าง แต่ถ้า 20000- 30000 record
จะเริ่มเห็น แต่โดยหลักการเป้นเช่นไรแน่ ผมไม่ทราบเลย
เพราะที่ผ่านมา ก็เรียกว่าครูพักลักจำทั้งนั้น ขอบคุณทุกท่านครับ
8 Reply in this Topic. Dispaly 1 pages and you are on page number 1
2 @R01526
เข้าใจแล้วครับ อาจารย์
แต่ที่มาที่ไปเป็นอย่างนี้ครับ ตอนนี้ผมมี RECORD การเบิก 28326 REC
การลงรับ 5155 REC ในการลงเบิกทุกครั้ง ผมจะตรวจสอบจำนวนที่เหลือทุกครั้งว่า ของเหลือเท่าไร นอกจากนี่ยังตรวจสอบด้วยว่า แต่ละ LOT เหลือเท่าไร
เพื่อไม่ให้ USER เบิกของเกินจำนวนที่มี และรู้ว่า ของมีเท่าไร และ LOT ที่เลือกมาเหลือเท่าไร โดยเปิด Recordset DAO เช่น
Function lotLor(IdDr) As Single 'ตรวจสอบ LOT เหลือ
Dim PLUS As Single
PLUS = 0
Dim Rs As DAO.Recordset
Set Rs = DBEngine(0)(0).OpenRecordset("orderd_detial")
Rs.MoveFirst
Do Until Rs.EOF
If Rs!id = IdDr Then
PLUS = PLUS + (Rs!amoute * Rs!pack_size)
End If
Rs.MoveNext
Loop
Rs.Close
Set Rs = Nothing
Dim MINUS As Single
MINUS = 0
Dim Rst As DAO.Recordset
Set Rst = DBEngine(0)(0).OpenRecordset("QBBForPLusMinus")
Rst.MoveFirst
Do Until Rst.EOF
If Rst!id_drug = IdDr Then
MINUS = MINUS + (Rst!amoute5 * Rst!pack_size5)
End If
Rst.MoveNext
Loop
Rst.Close
Set Rst = Nothing
lotLor = PLUS - MINUS
End Function
เป็นการหา คงเหลือของ LOT นี้ จากนั้นวาง TEXTBOX เปล่า แล้วส่งค่าให้
FUNCTION นี้ เพื่อคำนวณ LOT คงเหลือใน Continuous Form มันก็คำนวณไปใน FORM เบิกของ ทุก RECORDSET ก็คำนวณหมด ปัญหาของผมคือ
มันช้า กว่าจะคำนวณหมด ผมก็เลยพยายามหาว่า อะไรที่ทำให้การคำนวณล่าช้า
(ความจริงผมต้องการให้มัน คำนวณเฉพาะ รายการของที่จะเบิกใหม่ ADDNEW)
1.ข้อมูลมากไป
2.การเปิด RECORDSET ไม่เหมาะสม หรือปิด Recordset ไม่ถูกต้อง
3.การวาง CONTROL ไม่เหมาะสม (ไม่รู้เกี่ยวหรือเปล่า)
4.Process ในการคำนวณ ไม่เหมาะ เช่น น่าจะพักข้อมูลที่ได้รวมไว้บางส่วน เป็น รายปี ใน TABLE ชั่วคราว ไม่ต้องนับ 1 ตั้งแต่เริ่มเบิกของก็ได้
4.อยู่ใน EVENT ที่ ไม่เหมาะ
ตอนนี้ผมลองวาง EVENT นี้ ความเร็วดีขึ้นประมาณ 80 %
อย่างน้อยก็ตอน LOAD FORM ไม่ต้องรอ และก็ตรงตามวัตถุประสงค์
Private Sub Combo24_AfterUpdate()
If Me.NewRecord Then
Me.LOR = DrLor([id_DR])
Me.LORLOT = lotLor([id_drug])
End If
If Me.LORLOT = 0 Then
MsgBox ("Lot¹ÕéËÁ´áÅéǤÃѺ ¡ÃسÒàÅ×è͹àºÔ¡ Lot ãËÁè")
End If
End Sub
ส่วนอ.สันติ หรือ ใครมีวิธีการอย่างไรในการจัดการข้อมูลมากๆ หรือมีประสบการณ์ในการเบิกจ่าย เล่าสู่กันฟังบ้างนะครับ
รวมทั้ง วิธีคิด วิธีเปิด RECORDSET ของผม ถูกไม่ถูกอย่างไร ช่วยวิจารย์ให้ด้วยครับ
แต่ที่มาที่ไปเป็นอย่างนี้ครับ ตอนนี้ผมมี RECORD การเบิก 28326 REC
การลงรับ 5155 REC ในการลงเบิกทุกครั้ง ผมจะตรวจสอบจำนวนที่เหลือทุกครั้งว่า ของเหลือเท่าไร นอกจากนี่ยังตรวจสอบด้วยว่า แต่ละ LOT เหลือเท่าไร
เพื่อไม่ให้ USER เบิกของเกินจำนวนที่มี และรู้ว่า ของมีเท่าไร และ LOT ที่เลือกมาเหลือเท่าไร โดยเปิด Recordset DAO เช่น
Function lotLor(IdDr) As Single 'ตรวจสอบ LOT เหลือ
Dim PLUS As Single
PLUS = 0
Dim Rs As DAO.Recordset
Set Rs = DBEngine(0)(0).OpenRecordset("orderd_detial")
Rs.MoveFirst
Do Until Rs.EOF
If Rs!id = IdDr Then
PLUS = PLUS + (Rs!amoute * Rs!pack_size)
End If
Rs.MoveNext
Loop
Rs.Close
Set Rs = Nothing
Dim MINUS As Single
MINUS = 0
Dim Rst As DAO.Recordset
Set Rst = DBEngine(0)(0).OpenRecordset("QBBForPLusMinus")
Rst.MoveFirst
Do Until Rst.EOF
If Rst!id_drug = IdDr Then
MINUS = MINUS + (Rst!amoute5 * Rst!pack_size5)
End If
Rst.MoveNext
Loop
Rst.Close
Set Rst = Nothing
lotLor = PLUS - MINUS
End Function
เป็นการหา คงเหลือของ LOT นี้ จากนั้นวาง TEXTBOX เปล่า แล้วส่งค่าให้
FUNCTION นี้ เพื่อคำนวณ LOT คงเหลือใน Continuous Form มันก็คำนวณไปใน FORM เบิกของ ทุก RECORDSET ก็คำนวณหมด ปัญหาของผมคือ
มันช้า กว่าจะคำนวณหมด ผมก็เลยพยายามหาว่า อะไรที่ทำให้การคำนวณล่าช้า
(ความจริงผมต้องการให้มัน คำนวณเฉพาะ รายการของที่จะเบิกใหม่ ADDNEW)
1.ข้อมูลมากไป
2.การเปิด RECORDSET ไม่เหมาะสม หรือปิด Recordset ไม่ถูกต้อง
3.การวาง CONTROL ไม่เหมาะสม (ไม่รู้เกี่ยวหรือเปล่า)
4.Process ในการคำนวณ ไม่เหมาะ เช่น น่าจะพักข้อมูลที่ได้รวมไว้บางส่วน เป็น รายปี ใน TABLE ชั่วคราว ไม่ต้องนับ 1 ตั้งแต่เริ่มเบิกของก็ได้
4.อยู่ใน EVENT ที่ ไม่เหมาะ
ตอนนี้ผมลองวาง EVENT นี้ ความเร็วดีขึ้นประมาณ 80 %
อย่างน้อยก็ตอน LOAD FORM ไม่ต้องรอ และก็ตรงตามวัตถุประสงค์
Private Sub Combo24_AfterUpdate()
If Me.NewRecord Then
Me.LOR = DrLor([id_DR])
Me.LORLOT = lotLor([id_drug])
End If
If Me.LORLOT = 0 Then
MsgBox ("Lot¹ÕéËÁ´áÅéǤÃѺ ¡ÃسÒàÅ×è͹àºÔ¡ Lot ãËÁè")
End If
End Sub
ส่วนอ.สันติ หรือ ใครมีวิธีการอย่างไรในการจัดการข้อมูลมากๆ หรือมีประสบการณ์ในการเบิกจ่าย เล่าสู่กันฟังบ้างนะครับ
รวมทั้ง วิธีคิด วิธีเปิด RECORDSET ของผม ถูกไม่ถูกอย่างไร ช่วยวิจารย์ให้ด้วยครับ
3 @R01528
เท่าที่ดู คุณต้องทำสิ่งต่อไปนี้เพื่อปรับ performance ให้ดีขึ้น
1) Rs.MoveFirst ไม่จำเป็นครับ ทำให้เสียเวลาเปล่าๆ ตัดออกไปได้ เพราะเมื่อเปิด Recordset ขึ้นมา มันจะไปอยู??ที่เรคอร์ดแรกโดยอัตโนมัติอยู่แล้ว
2) คุณตรวจสอบด้วย If ... = ldDr ในลูป มันย่อมช้าแน่นอน คุณน่าจะสร้าง SQL Select statement ใน routine โดยมีเงื่อนไข Where clause ที่รวมเอา ldDr เป็นหนึ่งในเงื่อนไขนั้นเลย การให้ Jet Engine แบกรับการตรวจสอบเงื่อนไขนั้น เร็วกว่าเรามานั่งเช็คด้วย If .... Then มากมายนัก
3) การบวกทบๆไปด้วย Plus = Plus + (Rs!amoute * Rs!pack_size) คุณก็จับมันใส่ใน SQL Select statement ในข้อ 2) ได้เช่นกัน ดังนั้นจะไม่มี Do loop และ Rs.MoveNext อีกต่อไป
4) การเขียน DBEngine(0)(0) แบบนี้ ไม่จำเป็นแล้ว ให้ใช้ CurrentDB แทนได้เลย
ผลก็จะออกมาเป็นลักษณะนี้
Dim SQL As String
SQL = "select sum(amoute * pack_size) as SumPlus ... from ... where (id = ldDr)"
Set Rs = CurrentDB.OpenRecordset(SQL)
PLUS = Nz(Rs!SumPlus,0) ' จำเป็นต้องคร่อมด้วย Nz( ) เพราะถ้าไม่มีผลของ SumPlus ค่าที่ได้จะเป็น Null
Rs.Close
Set Rs = Nothing
ส่วนของ MINUS ก็ทำลักษณะเดียวกันครับ
5) คุณสร้าง index ให้แก่ฟิลด์ Id (ฟิลด์นี้เข้าใจว่าจะเป็น PrimaryKey ซึ่งถ้าใช่ ก็ไม่ต้องสร้าง index เพิ่มนะครับ) และ IdDrug เพื่อว่าการค้นหาด้วยเงื่อนไข Where (id = ldDr) หรือ Where (idDrug = ldDr) นั้น ตัวจัดการฐานข้อมูลจะได้ค้นตาม index ไม่ต้องไปค้นทุกเรคอร์ดอีกต่อไป
1) Rs.MoveFirst ไม่จำเป็นครับ ทำให้เสียเวลาเปล่าๆ ตัดออกไปได้ เพราะเมื่อเปิด Recordset ขึ้นมา มันจะไปอยู??ที่เรคอร์ดแรกโดยอัตโนมัติอยู่แล้ว
2) คุณตรวจสอบด้วย If ... = ldDr ในลูป มันย่อมช้าแน่นอน คุณน่าจะสร้าง SQL Select statement ใน routine โดยมีเงื่อนไข Where clause ที่รวมเอา ldDr เป็นหนึ่งในเงื่อนไขนั้นเลย การให้ Jet Engine แบกรับการตรวจสอบเงื่อนไขนั้น เร็วกว่าเรามานั่งเช็คด้วย If .... Then มากมายนัก
3) การบวกทบๆไปด้วย Plus = Plus + (Rs!amoute * Rs!pack_size) คุณก็จับมันใส่ใน SQL Select statement ในข้อ 2) ได้เช่นกัน ดังนั้นจะไม่มี Do loop และ Rs.MoveNext อีกต่อไป
4) การเขียน DBEngine(0)(0) แบบนี้ ไม่จำเป็นแล้ว ให้ใช้ CurrentDB แทนได้เลย
ผลก็จะออกมาเป็นลักษณะนี้
Dim SQL As String
SQL = "select sum(amoute * pack_size) as SumPlus ... from ... where (id = ldDr)"
Set Rs = CurrentDB.OpenRecordset(SQL)
PLUS = Nz(Rs!SumPlus,0) ' จำเป็นต้องคร่อมด้วย Nz( ) เพราะถ้าไม่มีผลของ SumPlus ค่าที่ได้จะเป็น Null
Rs.Close
Set Rs = Nothing
ส่วนของ MINUS ก็ทำลักษณะเดียวกันครับ
5) คุณสร้าง index ให้แก่ฟิลด์ Id (ฟิลด์นี้เข้าใจว่าจะเป็น PrimaryKey ซึ่งถ้าใช่ ก็ไม่ต้องสร้าง index เพิ่มนะครับ) และ IdDrug เพื่อว่าการค้นหาด้วยเงื่อนไข Where (id = ldDr) หรือ Where (idDrug = ldDr) นั้น ตัวจัดการฐานข้อมูลจะได้ค้นตาม index ไม่ต้องไปค้นทุกเรคอร์ดอีกต่อไป
4 @R01529
แก้ไข
SQL = "select sum(amoute * pack_size) as SumPlus ... from ... where (id = " & cstr(ldDr) & ")" ถ้า IdDr เป็น numeric
หรือ
SQL = "select sum(amoute * pack_size) as SumPlus ... from ... where (id = '" & cstr(ldDr) & "')" ถ้า IdDr เป็น string
SQL = "select sum(amoute * pack_size) as SumPlus ... from ... where (id = " & cstr(ldDr) & ")" ถ้า IdDr เป็น numeric
หรือ
SQL = "select sum(amoute * pack_size) as SumPlus ... from ... where (id = '" & cstr(ldDr) & "')" ถ้า IdDr เป็น string
5 @R01530
ขอบคุณครับ
เดี่ยวจะลองดูครับ
เดี่ยวจะลองดูครับ
6 @R01531
เร็วกว่า จริงๆ ครับ
ผมคิดว่ายังงัยเป็น INDEX อยู่แล้วน่าจะเร็วเหมือนกัน
หมายความว่าถ้าเป็น SQL STRING JET ENGINE ไม่ต้องทำงานในการตรวจสอบเงื่อนไขมากใช่ไหมครับ เพราะการเปิด RST โดยใช้เงือ่นไขที่เหมาะสม
ทำให้ Engine ทำงานง่ายใช่ไหมครับ
เมื่อก่อน ผมไม่กล้า เขียน SQL ตรงๆ กลัวเขียนผิด ใช้ QUERY แทน
เมื่อคืนลองเขียนดู เออ พอเขียนได้แหะ แต่ก็เล่นเอาเหนื่อย
ขอบคุณครับ
อาจารย์ครับ performance แปลว่าอะไรครับ
ผมคิดว่ายังงัยเป็น INDEX อยู่แล้วน่าจะเร็วเหมือนกัน
หมายความว่าถ้าเป็น SQL STRING JET ENGINE ไม่ต้องทำงานในการตรวจสอบเงื่อนไขมากใช่ไหมครับ เพราะการเปิด RST โดยใช้เงือ่นไขที่เหมาะสม
ทำให้ Engine ทำงานง่ายใช่ไหมครับ
เมื่อก่อน ผมไม่กล้า เขียน SQL ตรงๆ กลัวเขียนผิด ใช้ QUERY แทน
เมื่อคืนลองเขียนดู เออ พอเขียนได้แหะ แต่ก็เล่นเอาเหนื่อย
ขอบคุณครับ
อาจารย์ครับ performance แปลว่าอะไรครับ
7 @R01532
- การที่เราส่งเป็นคำสั่ง SQL ไป พอตัว Jet Engine แปลแล้วมันก็จะทำการประมวลผล แน่นอนที่ย่อมเร็วกว่าการทำงานภายใต้ภาษา VBA, VB, VB.NET,... จริงๆแล้วการตรวจเช็คเงื่อนไขของ Jet Engine ทำงานเยอะกว่า VBA ที่เราเขียนมากกว่ามากครับ แต่เพราะมัน(คงจะ)เขียนด้วย C++ (หรืออย่างแย่ก็คงเป็นแค่ภาษา C) จึงทำงานได้เร็วกว่า
- คิวรี่ที่มีการ join กันเยอะๆ ผมก็ไม่เขียนเอง ผมทำใน Query Design View นั่นแหละ แล้วก็สวิทช์ไปดูใน SQL View แล้วก็อปเอามาอีกทีจะแน่นอนกว่า ไม่ผิด syntax ไม่เสียเวลามาแก้บั๊กด้วยครับ ยกเว้นว่าคิวรี่ประเภทใช้ sub query นี่แหล่ะที่มักเขียนเอง ดังนั้นไม่ต้องไปซีเรียสกับ SQL ครับ ขอเพียงให้รู้ว่า SQL มันมีคำสั่งให้ทำอะไรได้บ้างก็พอ ไม่ต้องไปนั่งจำครับ จะใช้ทีก็เปิด Help ทีก็ไม่ผิดกฏอะไร
- performance ก็ไม่มีอะไรครับ ผมชินกับการทับศัพท์คำนี้มากกว่าเรียกว่า "ความเร็ว" ครับ มันเท่ห์ดีพูดไทยคำอังกฤษคำ
- คิวรี่ที่มีการ join กันเยอะๆ ผมก็ไม่เขียนเอง ผมทำใน Query Design View นั่นแหละ แล้วก็สวิทช์ไปดูใน SQL View แล้วก็อปเอามาอีกทีจะแน่นอนกว่า ไม่ผิด syntax ไม่เสียเวลามาแก้บั๊กด้วยครับ ยกเว้นว่าคิวรี่ประเภทใช้ sub query นี่แหล่ะที่มักเขียนเอง ดังนั้นไม่ต้องไปซีเรียสกับ SQL ครับ ขอเพียงให้รู้ว่า SQL มันมีคำสั่งให้ทำอะไรได้บ้างก็พอ ไม่ต้องไปนั่งจำครับ จะใช้ทีก็เปิด Help ทีก็ไม่ผิดกฏอะไร
- performance ก็ไม่มีอะไรครับ ผมชินกับการทับศัพท์คำนี้มากกว่าเรียกว่า "ความเร็ว" ครับ มันเท่ห์ดีพูดไทยคำอังกฤษคำ
8 @R06759
"การที่เราส่งเป็นคำสั่ง SQL ไป พอตัว Jet Engine แปลแล้วมันก็จะทำการประมวลผล แน่นอนที่ย่อมเร็วกว่าการทำงานภายใต้ภาษา VBA, VB, VB.NET,... จริงๆแล้วการตรวจเช็คเงื่อนไขของ Jet Engine ทำงานเยอะกว่า VBA ที่เราเขียนมากกว่ามากครับ แต่เพราะมัน(คงจะ)เขียนด้วย C++ (หรืออย่างแย่ก็คงเป็นแค่ภาษา C) จึงทำงานได้เร็วกว่า "
ขอบคุณครับ กำลังหาว่าจะเอาผลมารวมเอง หรือสั่งรวมใน SQL ไปเลย
ขอบคุณครับ กำลังหาว่าจะเอาผลมารวมเอง หรือสั่งรวมใน SQL ไปเลย
Time: 0.2555s
DataSheet Form ไม่มี header หรือ footer นะครับ ดังนั้นเข้าใจว่าคุณน่าหมายถึง Continuous Form ซะมากกว่า ... ค่าที่แสดงใน unbound textbox นั้นขึ้นกับว่ากำหนดวิธีการใส่ค่าให้มันด้วยวิธีไหน ถ้าคุณระบุใน ControlSource property ไปเลยว่า = ControlA * ControlB ... ค่าที่แสดงก็จะถูกต้อง จะเป็นค่าที่เกิดจาก ControlA คูณ ControlB จากแต่ละเรคอร์ดนั่นเอง ... แต่ถ้าไปกำหนดให้ me.Textbox = me.ControlA * me.ControlB จากใน Form_Current event แล้วหล่ะก็ textbox ทุกบรรทัดจะได้จาก ControlA และ ControlB ของเรคอร์ดสุดท้ายที่ Access มันประมวลผลครับ เนื่องจาก Access ไม่มีวิธีการในการระบุ textbox (หรือ control ใดๆก็ตาม) เฉพาะเจาะจงในแต่ละบรรทัด การระบุ textbox ใดๆก็ตามใน continuous form จะมีผลกับทุกๆบรรทัดครับ ... ส่วนจะวางไว้ใน Detail Section หรือ Footer Section ก็ถ้าเป็นข้อมูลสำหรับแต่ละเรคอร์ด ก็ควรแสดงใน Detail Section ส่วนถ้าเป็นผลรวมของหลายๆเรคอร์ดก็ต้องวางไว้ที่ Footer Section การได้มาของข้อมูลมันเป็นตัวกำหนดตำแหน่งที่จะวางบนฟอร์มเอาไว้อยู่แล้วนะครับ