อยากทราบเกี่ยวกับการใช้คำสั่งวนลูปค่ะ
กระทู้เก่าบอร์ด อ.Yeadram

 6,235   14
URL.หัวข้อ / URL
อยากทราบเกี่ยวกับการใช้คำสั่งวนลูปค่ะ

อยากทราบว่าถ้าต้องการเขียนคำสั่งวนลูปต้องทำอย่างไรค่ะ
ความต้องการนะค่ะ

1. เราเลือกวันที่ที่จะแสดงรายงาน เช่น 01/08/2010 - 23/08/2010
2. กดปุ่มแสดงรายงาน
3. หน้ารายงานเช็ควันที่ที่เรียกดูรายงานว่าวันที่ 01/08/2010 - 23/08/2010 มีอยู่ในฐานข้อมูลหรือยัง
4. ถ้าวันที่ 01/08/2010 -10/08/2010 มีข้อมูลอยู่ในฐานข้อมูล แต่ 11/08/2010 -23/08/2010 ไ่ม่มีข้อมูลอยู่ในฐานข้อมูล
5. ให้ระบบทำการเรียกใช้ Query Design ที่เขียนไว้สำหรับ Insert ข้อมูล โดย insert ข้อมูลตั้งแต่วันที่ 11/08/2010 - 23/08/2010 ลงไปยังฐานข้อมูล
6. จากนั้นให้รายงานเรียกใช้ข้อมูลจากตารางที่ทำการ insert ข้อมูลลงไปเรียบร้อยแล้วค่ะ

อยากทราบว่า ข้อ 3 - 6 นี่ต้องใช้หลักการหรือวิธีอย่างไรบ้างคะ รบกวนด้วยค่ะ

* อันนี้คือ Query Design ที่ใช้สำหรับ Insert ค่ะ
INSERT INTO TBLALL ( Billdate, Detail,Price, Net)
SELECT a.billdate,b.detail,c.price,c.net FROM (Service AS a LEFT JOIN SR AS b ON a. billdate =b. billdate) LEFT JOIN Branch AS c ON a. billdate =c. billdate
GROUP BY a.billdate,b.detail,c.price,c.net
HAVING (((a. billdate)>=[Forms]![Reports Dialog]![FromDate] And (a. billdate)<=[Forms]![ Reports Dialog]![ToDate]));

จริงๆมีเยอะกว่านี้แต่ตัดมาเพื่อให้เข้าใจง่ายค่ะ ปัญหาส่วนของ Query Design คือมันจะดึงวันที่จากฟอร์มตอนที่เราเลือกข้อที่ 1 ค่ะ เลยอยากทราบวิธีทำ ตอนนี้คิดได้ว่าน่าจะใช้วิธีเอาข้อมูลที่ได้จากการเช็คข้อที่ 3 แล้วเก็บวันที่ที่ยังไม่มีข้อมูลลง session ดีมั้ยคะ ใครทราบอย่างไรแนะนำด้วยนะค่ะ

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

1 @R06455
ผมคิดว่าเราสามารถที่จะปรับปรุง Append Query ที่ให้มาเพื่อให้รองรับความต้องการข้อ 3-5 ได้เลยในขั้นตอนเดียว
ผมว่าส่วนที่เป็น HAVING clause นั้น น่าจะเปลี่ยนเป็น WHERE clause เสียมากกว่า
และเพิ่ม sub query ในส่วนสีเขียวที่เช็คว่า billdate ที่จะเลือกมานั้นต้องมากกว่า
billdate สุดท้ายที่มีอยู่แล้วในช่วงวันที่ที่ต้องการ
อีกอย่างเปลี่ยนไปใช้ Operator Between ก็จะทำให้สั้นและอ่านได้ง่ายขึ้นด้วยครับ

การเรียกใช้ Action Query นี้ทำได้ด้วยคำสั่ง
DoCmd.RunSQL "ชื่อคิวรี่"

การเปิดรายงานทำได้ด้วยคำสั่ง
DoCmd.OpenReport "ชื่อรายงาน"


INSERT INTO TBLALL ( Billdate, Detail,Price, Net)

SELECT a.billdate,b.detail,c.price,c.net
     FROM (Service AS a LEFT JOIN SR AS b ON a. billdate =b. billdate)
     LEFT JOIN Branch AS c ON a. billdate =c. billdate

     WHERE (a.billdate > (select max(aa.billdate)
               from service as aa
               where aa. billdate between [Forms]![Reports Dialog]![FromDate]
                    and [Forms]![ Reports Dialog]![ToDate]))

          AND (a. billdate between [Forms]![Reports Dialog]![FromDate]
               and [Forms]![ Reports Dialog]![ToDate])

     GROUP BY a.billdate,b.detail,c.price,c.net

2 @R06456
จริงๆการ insert เข้าไปใหม่เนี่ย สามารถ insert ข้อมูล billdate ที่มีน้อยกว่าในฐานข้อมูลได้ด้วยนะค่ะ แบบถ้าเลือกวันที่ 01/08/2010 - 23/08/2010 พอเช็คในฐานข้อมูลเจอวันที่ 10/08/2010 - 15/08/2010
ก็ให้ insert 01/08/2010 - 09/08/2010 และก็ insert 16/08/2010 - 23/08/2010 ค่ะ
เลยคิดว่าอาจจะต้องวนลูปเช็คเอา แต่ไม่ทราบว่าต้องทำอย่างไร รบกวนด้วยค่ะ
3 @R06460
เปลี่ยนเป็น

WHERE (not exists (select t.billdate
               from TBLALL as t
               where t. billdate = a.billdate ) )

          AND (a. billdate between [Forms]![Reports Dialog]![FromDate] and [Forms]![ Reports Dialog]![ToDate])

อย่างไรก็ให้เช็คอีกทีจากเทเบิล TBLALL ว่าการ insert ได้ทำอย่างถูกต้องไม่ขาดไม่เกินนะครับ
4 @R06462
ขอบคุณมากเลยค่ะ เดี๋ยวจะไปลองเขียนดูค่ะ ได้ไม่ได้อย่างไรจะมารายงานให้ทราบนะค่ะ
5 @R06464
เอ่อ คือในส่วนของการ insert data เข้าไปไม่มีปัญหาค่ะ
แต่ติดตรงที่ว่าอยากให้รายงานตัวนึงสามารถทำได้แบบนี้ค่ะ
ตอนนี้ลองเขียนในส่วนของ VBA ซึ่งมันยังเน่าๆอยู่ เลยอยากขอคำแนะนำหน่อยค่ะ

Dim i
For i = [Forms]![Reports Dialog]![FromDate] To [Forms]![ Reports Dialog]![ToDate]
อยากได้ประมาณ
If i = “Select * from TblALL where billdate =" & i & " " Then
สั่งให้ Query Design ชื่อ “Query_ALL”(เป็นแบบสอบถามใน Access ซึ่งจะเขียน insert แบบที่คุณสันติสุขแนะนำอะค่ะ)
ซึ่งถ้าเข้ามาทำงานใน if แล้วให้หยุดการวนลูปเลยค่ะ
End if
Next
ให้รายงานแสดงหน้าจอตามปกติค่ะ

และอีกอย่างนึงคือรายงานตัวนี้ใช้ Query Builder ใน Access ดึงข้อมูลจากตารางที่อยู่ใน MYSQL นะค่ะ เลยไม่แน่ใจว่าจะสามารถเขียนคำสั่งทั้งในส่วนของ VBA และใน Query Builder ของ Access ได้รึเปล่า
รบกวนด้วยค่ะ
6 @R06465
พอดีลองเขียนเองแล้วมันก็สามารถทำงานได้นะค่ะแต่รู้สึกเหมือนมันจะเข้า คำสั่ง if ตลอดเลยค่ะ เพราะดูจากการ debug อะค่ะ ทั้งๆที่เรียกวันที่ที่มีอยู่ในฐานข้อมูลแล้วนะค่ะ เขียนประมาณนี้ค่ะ ผิดตรงไหนบ้างคะ แนะนำหน่อยค่ะ

Dim i
        Dim db As DAO.Database
        Dim rst As DAO.Recordset
        For i = [Forms]![Reports Dialog]![FromDate] To [Forms]![Reports Dialog]![ToDate]
        Set db = CurrentDb
        Set rst = db.OpenRecordset("Select billdate from tblAll where billdate=" & i & "")
            If rst.EOF Then
               DoCmd.OpenQuery "Query_ALL"
               rst.Close
               Set rst = Nothing
               i = [Forms]![Reports Dialog]![ToDate]
               i = i + 1
               Debug.Print i
            End If
        Next
              DoCmd.OpenReport "CC-WklyReport", acViewPreview
7 @R06466
คุณเล่นทยอยค่อยๆบอกรายละเอียดทีละนิดๆ ผมตอบครั้งนึง คุณก็เพิ่มรายละเอียดทีนึง แล้วอย่างนี้เมื่อไหร่จะจบหล่ะครับ ! รายละเอียดที่ต่างไปนิดนึง ก็อาจทำให้โปรแกรมต้องเปลี่ยนไปแล้ว อย่างคุณเรียกใช้ข้อมูลจาก MySQL ซึ่งเข้าใจว่าจะทำเป็น ODBC-Linked-Table เข้ามา ถ้าเป็นอย่างนั้น การทำ sub query อย่างที่ผมแนะนำไป มันอาจจะทำงานได้ช้ามากๆๆๆๆๆ มันน่าจะใช้ไม่ได้แล้วหล่ะครับ แล้วที่คุณเขียน If I = ... มันหมายถึงอะไรครับ อ่านไม่เข้าใจ ไม่เข้าใจความต้องการครับ และที่บอกว่า "เขียนคำสั่งทั้งในส่วนของ VBA และใน Query Builder ของ Access ได้รึเปล่า" หมายถึงอย่างไรครับ อันนี้ผมก็ไม่เข้าใจ

สองวันนี้ผมคงไม่ว่างมาตอบให้แล้วนะครับ หรือถ้า อ.ท่านใดว่างที่จะตอบก่อน ก็เชิญครับ
8 @R06467
เห็นที่คุณเขียนแล้ว งงจริงๆ

1) อย่างแรก INSERT statement ที่ผมให้ไปนั้นมันไม่ต้องเขียน VBA เพื่อวนลูปครับ เพราะ statement มีการกำหนดเงื่อนไข between วันที่จาก [FromDate] ถึง [ToDate] ให้อยู่แล้ว ... แต่ว่า ...

2) เพราะถ้ามันเป็น ODBC-Linked-Table มาจาก MySQL การใช้ sub query น่าจะทำงานช้ามาก ยกเว้นจะเขียน PassThru Query แต่ถ้าจะลองก็ได้ครับ ถ้ามันทำงานได้ปกติดี ก็เรียกว่าโชคดีไป แต่อย่างไรก็ตามโปรแกรมก็น่าจะต้องแก้ เพราะ ...

3) คุณเขียนคำสั่ง เหมือนคุณไม่เข้าใจว่า คำัสั่งนั้นทำงานอะไร เหมือนเอาจากที่ไหนมาปะติดปะต่อกัน ซึ่งแทบจะผิดบรรทัดเว้นบรรทัดเลย
9 @R06468
ตอบของ R06466
จริงๆรายละเอียดทั้งหมดมันก็มี 6 ข้อตามที่ตั้งกระทู้ไว้แหละค่ะ แต่อาจจะยังไม่ได้บอกว่าใช้ mysql และก็ใช้ ODBC-Linked-Table ด้วยค่ะ
ส่วน IF i ก็คือเช็คว่ามีข้อมูล billdate ตรงกับค่า i หรือไม่ จะอยู่ในส่วนของข้อที่ 3 ค่ะ

ตอบของ R06467
1) ที่ให้วนลูป เพราะต้องเช็คตอนเลือกวันที่ก่อนค่ะ เช็คในดาต้าเบสว่ามีข้อมูลของวันนี้อยู่หรือยัง ถ้ายังไม่มีก็ให้เรียกใช้แบบสอบถามที่เป็นตัว insert data จริงๆถ้าไปเปิดแบบสอบถามอันนั้นเลยมันก็ไม่ต้องมานั่งวนลูปหรอกค่ะ แต่ว่าดิฉันต้องสั่งจากตอนที่กดปุ่มแสดงรายงาน ในข้อที่ 2 ค่ะ เลยต้องเช็คก่อน เพราะถ้ามันมีข้อมูลอยู่แล้วจะได้ไม่ต้องไป insert data ทับลงไปอีกค่ะ

2) เพราะอะไรหรอคะ และ ส่วน PassThru Query ขอไปทำความเข้าใจก่อนนะค่ะ

3) จริงๆไม่เคยเขียนโปรแกรมโดยใช้ Access by vba เลยค่ะ อันนี้เป็นงานแรกเลย แบบเอามาพัฒนาต่อ ก็ไม่เข้าใจจริงๆแหละค่ะ เอาโค๊ตเก่าเขามารวมๆกันจริงๆ ซึ่งที่ผิดบรรทัดเว้นบรรทัดนี่มันยังไงคะ ไม่เข้าใจเลยค่ะ
10 @R06469
1) ก็ในเมื่อ INSERT statement ทำงานได้สมบูรณ์สำหรับช่วงวันที่นั้นๆอยู่แล้ว แล้วทำไมจะต้องเช็คก่อนหล่ะครับ ? พอสั่ง INSERT statement ที่ว่าเพียงครั้งเดียว เขาก็หาข้อมูลในช่วง [FromDate] ถึง [ToDate] ที่ยังไม่มีในเทเบิล tblALL มาใส่เพิ่มให้เลย (ตรง WHERE not exists... ในคำตอบ R06460 นั่นแหล่ะที่ทำหน้าที่นี้) ดังนั้นโปรแกรมก็น่าจะมีแค่

DoCmd.RunSQL "Query_ALL"
DoCmd.OpenReport "CC-WklyReport", acViewPreview

ก็เท่านั้นเอง

2) ODBC พยายามทำการแปลงคำสั่ง SQL ไปอยู่ในรูปแบบที่เหมาะสมสำหรับฐานข้อมูลแต่ละยี่ห้อ เท่าที่ทราบ ODBC มันจะไม่ฉลาดนักในเรื่อง sub query แต่ก็อย่างที่ผมว่า ต้องลองครับ   ส่วน PassThru Query คือ คิวรี่ที่มีคำสั่ง SQL ที่ต้องอยู่ใน syntax ของฐานข้อมูลยี่ห้อนั้นๆ ถูกส่งไปทำงานที่ database server โดยตรงเลย แล้วข้อมูลผลลัพธ์จะส่งกลับมา(ถ้ามี) มายัง Access วิธีนี้จะเร็วกว่าทำงานผ่านการเรียกใช้ ODBC-Linked-Table เพราะ ODBC จะไม่มาสนใจหรือแปลงอะไีีรให้ทั้งสิ้น ส่งอะไรมาให้ ก็จะส่งต่อไปยัง database server ให้เลย แล้วรอรับเฉพาะคำตอบเท่านั้น

3) ผิดตรง
3.1) ใช้ OpenQuery แทนที่จะเป็น RunSQL
3.2) สั่ง rst.Close และ Set rst = Nothing ซึ่งตามลอจิกแล้ว ควรอยู่นอก If - End If แต่เนื่องจากกรณีนี้ เราจะไม่มีใช้คำสั่งเหล่านี้เลย นี่เพียงอธิบายให้เฉยๆ
3.3) i อาจมี sub data type เป็น date ผมไม่เคยใช้ให้ date data type เป็นตัวกำหนด for loop ไม่รู้ว่าใช้ได้หรือไม่ แต่ถ้าใช้ได้ ก็ไม่ต้อง กำหนด i = i + 1

นอกจากนี้ เวลาเขียนโปรแกรมเกี่ยวกับ data type เป็น date มีเรื่องที่ต้องคำนึงถึงเยอะมากๆ โดยเฉพาะเรื่องรูปแบบและวิธีการเก็บในแต่ละส่วนของโปรแกรมว่ามันเข้ากันได้ไหม ตั้งแต่ในฐานข้อมูล, บนฟอร์ม, ในโค้ดของเรา ผมจึงให้คุณไปเช็คตามที่ผมบอกไปใน R06460 เพราะถ้ามานั่งอธิบาย คงจะยาวทีเดียว ก็ใช้เช็คผลลัพธ์ไปเลย ถ้าผลลัพธ์ไม่ถูก มันขาดหรือเกิน ก็แปลว่ามีอะไรผิดแน่นอน
11 @R06470
ขอโทษครับ ผมผิดแล้ว ใช้ DoCmd.OpenQuery "Query_ALL" ถูกต้องแล้ว

เพิ่มว่าให้ครอบคำสั่งนี้ด้วย
DoCmd.SetWarnings False ' เพื่อไม่ให้แสดงข้อความเตือนว่าจะทำการรัน Append Query และไม่ต้องถามเพื่อยืนยันว่าจะมีการเพิ่มข้อมูลกี่เรคอร์ด
DoCmd.OpenQuery "Query_ALL"
DoCmd.SetWarnings True
12 @R06473
ขอบคุณอาจารย์สันติสุขมากๆเลยค่ะ
คืออาจารย์คงหมายถึงว่าทำไมจะต้องไปนั่งเช็คให้มันเสียเวลาก็ให้คิวรี่ที่อาจารย์ให้มาเช็คเองก็ได้ แต่คือที่อยากจะเช็คเพราะว่าไม่อยากให้ไปเรียกใช้เจ้าคิวรี่นี้ตลอดเวลากลัวว่ามันจะช้ากว่าเดิมนะค่ะ ตอนนี้ได้ลองทำตามที่อาจารย์แนะนำแล้วค่ะ ง่ายกว่าเดิม 4 บรรทัดเอง
แล้วดิฉันก็ลองใช้ Pass Thru Query แล้วนะค่ะ แต่ว่า Code ของดิฉันเนี่ยมันมี IFF มากมาย แล้วก็ต้องดึงค่าจาก Form รู็สึกว่าเจ้า MYSQL มันจะรับไม่ได้
และสุดท้าย เจ้า i = i+1 คือพยายาม(แบบมึนๆ)จะให้ for หยุดทำงานเลยทำให้ค่า date มันมากกว่าค่าที่รับมาสุดท้ายนะค่ะ

ขอบคุณสำหรับคำชี้แนะดีๆนะค่ะ เดี๋ยวจะพยายามหาวิธีให้มันทำงานเร็วกว่านี้ค่ะ

13 @R06683
รบกวนผู้รู้ช่วยหน่อยนะค๊ะ ทำมาหลายวันแล้ว ยังไม่ได้เลย
คือมี Table เดียว เก็บข้อมูลดังนี้
Field
emp_id          
Barcode       
First_name
Dept
*** ความต้องการคือ **
     - เมื่อกดปุ่ม printlสติกเกอร์   อยากให้ Report พิมพ์ชื่อพนักงานคนเดิมซ้ำกัน คนละ 10 ชื่อ (จะนำไ ปทำสติกเกอร์ค๊ะ)
       จนกระทั้งหมด Table
ตัวอย่างนะค๊ะ

001 นายก
แผนกขาย

001 นายก
แผนกขาย

001 นายก
แผนกขาย
-
-
-
-
---ครบ 10 ดวง--
---พิมพ์คนถัดไ ป--    

002 นายข
แผนกบุคคล

002 นายข
แผนกบุคคล


**** รบกวนหน่อยนะค๊ะ ลองทำมาจนตาลายแล้ว เพิ่งเริ่มต้นกับ Access ช่วยชี้แนะด้วยคี***

14 @R06684
ผมจะยกไปตั้งเป็นอีกกระทู้จะดีกว่านะครับ แล้วไปอ่านคำตอบในกระทู้นั้น
@ ประกาศใช้งานเว็บบอร์ดใหม่ => บอร์ดเรียนรู้ Access สำหรับคนไทย
แล้วจะใส่ลิ้งอ้างอิงมาที่โพสต์เก่านี้หรือไม่ก็ตามสะดวกครับ
Time: 0.2908s