บทความ

เมื่อ VFP Table พัง

สมัยก่อนผมใช้ VFP ไปแล้ว Table ใหญ่ๆ มี Memo Field ด้วย และมีกระแสไฟตกบ่อยๆ ก็มักเจอดีเหตุการณ์ไฟล์เสียเข้ามาเยือน ซ่อมได้ด้วยเทคนิคต่างๆที่ไม่เป็นทางการ แล้วก็น่าแปลกที่ VFP ไม่ทำโปรแกรมซ่อมโดยเฉพาะออกมา วิธีการที่ว่านั้นก็มีทั้งเล่นเป็นชุด เปิดไฟล์ขึ้นมา+เพิ่มเรคอร์ดใหม่+ลบออก+PACK+ปิดไฟล์ แล้วเปิดใช้อีกที , หรือไม่ก็ใช้ซอฟต์แวร์ซ่อม dbf ของผู้ใช้งานทำกันออกมาเอง ที่มีให้ดาว์นโหลดฟรีและเสียกะตังค์ แบบเล่นเป็นชุดที่ว่า...คุณ Anuwat (ขออภัยท่านนี้ผมยังไม่เคยทัก) ในกลุ่ม Line แนะนำมาว่า SET TABLEVALIDATE TO 0 USE table1 EXCLUSIVE APPEND BLANK DELETE PACK USE แบบนี้ครับ ส่วนคุณ Joe นักพัฒนาซอฟต์แวร์ที่เชี่ยวชาญและมีน้ำใจคอยช่วยตอบปัญหาให้เพื่อนๆชาว Fox มาตลอดได้แนะนำในกลุ่ม Line เดียวกันดังข้างล่างนี้ครับ *เรียกใช้ If FixMemoFile('c:\front\font.scx') *** Success. File is Fixed Else *** Fail. File is not fixed Endif *ฟังก์ชั่น Function FixMemoFile(tcFile as string) If vartype(tcFile) = 'C' and not Empty(tcFile) and File(tcFile) Local lnOldSelec...

VFP SQL UPDATE ปรับปรุงค่าในฟิลด์ด้วยค่าจากตารางอื่น

ก่อนนี้ผมใช้ VFP มาแบบโบราณ เวลาเปลี่ยนค่าใน Field ก็ใช้ DO WHILE ร่วมกับ REPLACE ก็รอดมาได้ แต่ต่อมามาใช้ SQL ก็ดูเหมือนว่าชีวิตจะสะดวกสบายขึ้น โดยเฉพาะการปรับปรุงค่าในฟิลด์ของ Tabel_1 ด้วยค่าในฟิลด์ของ Table_2 ง่ายกว่าการใช้ DO WHILE ร่วมกับ REPLACE แบบเดิมๆมากมายมหาศาลเชียวล่ะ อยากรู้ก็อ่านต่อไปครับว่าทำได้ยังไง เค้าว่าตัวอย่างที่ดีมีค่ากว่าคำสอน ดังนั้น...เอาตัวอย่างไปครับ * เปิด table USE old_value IN 0 USE new_value IN 0 * สั่ง update field_name ใน old_value ด้วย field_name จาก new_value UPDATE old_value ; FROM  new_value  ; WHERE  old_value   .keyfield  =  new_value   .keyfield ; SET  old_value   .field_name =  new_value   .field_name * สังเกตผล SELECT old_value BROWSE จากตัวอย่างที่เห็นข้างต้นนี้ เราเปลี่ยนค่าในฟิลด์ที่ชื่อว่า field_name ของตาราง old_value ด้วยค่าใน field_name ของตาราง new_value ซึ่งแน่นอนว่าต้องระบุลงไปให้ชัดเจนใน SQL Command ด้วยว่าจะให้ฟิลด์ใดเป็นตัวอ้างอิงระหว่างกัน โดยระบุลงไปในคำสั่ง ...

ALEN นับความยาว Array ง่ายๆ

DIMENSION myArray(2,3)    && create an array of 2 rows and 3 columns ? ALEN(myArray)           && returns 6 (2*3 elements) ? ALEN(myArray,1)         && returns 2 (rows) ? ALEN(myArray,2)         && returns 3 (columns) ฟังก์ชั่น ALEN ของ VFP นั้นเราสามารถใช้ได้อย่างเบ็ดเสร็จทั้งนับคอลัมน์ นับแถว และความยาวทั้งหมด ง่ายมากๆเลยใช่ไหมล่ะครับ โดยเราอาจจะประยุกต์ใช้แสดงค่า Array โดยเขียนฟังก์ชั่นได้ดังข้างล่างนี้ครับ * แสดงค่าใน Array FUNCTION func_print_r PARAMETERS print_array maxrow = ALEN(print_array,1) maxcol = ALEN(print_array,2) FOR thisrow=1 TO maxrow ?thisrow,"" FOR thiscol=1 TO maxcol ??print_array(thisrow,thiscol) ??IIF(thiscol<>maxcol,",","") && เพิ่ม Comma คั่นท้ายหากยังไม่หมดทุก column NEXT thiscol NEXT thisrow ENDFUNC โดยวิธีการเรียกใช้ก็ใส่ @ เข้าไปหน้าชื่อ Array ที่ต้องการแสดงค่าเพื่อให้ส่งไปแบบอ้างอิง Pointer นั่นเองค...

เก็บเฉพาะชื่อไฟล์ .dbf (และอื่นๆ) โดยไม่เอา path

ปกติเรามีคำสั่ง dbf() ที่ใช้เก็บชื่อไฟล์ dbf และมันให้ path มาด้วย  ซึ่งบางครั้งไม่ใช่สิ่งที่เราต้องการ เราจึงอยากจะแยกมันเอามาเฉพาะชื่อไฟล์ และทำได้ 2 ขั้นตอนคือ 1. หาตำแหน่งที่เป็นจุดแบ่งระหว่างสิ่งที่จะตัดออกและสิ่งที่จะเอาไว้ ซึ่งอาจใช้ฟังก็ชั่น AT หรือ RAT ก็ได้ครับ (แต่งานนี้ผมใช้ RAT) คือ - ใช้ฟังก์ชั่น AT ร่วมกับประโยค do ... while เพื่อวนหา / ตัวสุดท้าย - ใช้ฟังก์ชั่น RAT ค้นหา / ตัวสุดท้ายซะเลย ทั้ง AT และ RAT เป็นฟังก์ชั่นที่ใช้ไล่หาตัวอักษรที่เราระบุ แล้วคืนค่ากลับมาว่าเป็นตัวอักษรที่เท่าไหร่ เราจะได้ตัดมันออกได้ตรงประเด็น ซึ่งจะเห็นว่างานนี้ AT จะยุ่งยากกว่า RAT มากเพราะว่า AT มันไล่หาจากด้านซ้ายไปด้านขวาครับ ส่วน RAT นั้นจะทำสลับกัน 2. เมื่อหาเจอจุดแบ่งของสิ่งที่จะตัดออก หรือจะเอาไว้แล้วก็ใช้ฟังก์ชั่น LEFT , RIGHT หรือ SUBST ในการดึงมันออกมาครับ (ในงานนี้ผมใช้ RIGHT เพราะดึงจากด้านขวาเข้าไปโดยไม่ต้องระบุความยาว จากหลักการข้างต้นเขียนเป็นคำสั่งได้ว่า... fname = RIGHT(dbf(), LEN(dbf())-RAT("\", dbf())) สำหรับท่านที่จะเอาเฉพาะชื่อไฟล์ โดยไม่เอานามสกุล ห...

VFP ใช้ GROUP BY ได้ไหม?

VFP 8/9 ใช้หลักของ ANSI SQL (1992) จึงมีการตรวจสอบว่าอนุคำสั่ง GROUP BY  จะใช้ได้เมื่อทุกฟิลด์/คอลัมน์ไม่เป็น Aggregate Field (นัยยะหมายถึงพวกที่ต้องคำนวณหาทั้งหลาย เช่น sum(total) , max , min นั่นแหละ) ไม่เช่นนั้นจะถือว่าใช้คำสั่งผิด ซึ่งเราอาจตั้งค่าให้ไม่ต้องตรวจสอบเรื่องนี้ได้โดยใช้คำสั่ง SET ENGINEBEHAVIOR 70 โดยไว้ก่อนจะสั่งคำสั่งที่ใช้ GROUP BY ครับ ผมยังไม่มีเวลาหาข้อมูลต่อว่า เพราะอะไรเค้าถึงไม่ยอมให้ใช้ (เฉพาะ VFP นี่แหละ) ดังนั้นแนะนำว่าถ้าไม่ชัวร์ก็พยายามเลี่ยงนะครับ เพราะเค้าก็ต้องมีเหตุผลของเค้าแหละซึ่งมันอาจผิดพลาดได้ง่ายสำหรับกรณีแบบนี้ เราควรหาทางอื่นดีกว่าซึ่งทำได้เยอะแยะไป ไม่งั้นเกิดทำมึนๆใช้ๆไป ทำไปเยอะๆใช้ไปนานๆเข้าไปแล้วเจอ Runtime Error / Bug เข้าในตอนที่ลืมไปแล้วจะยุ่งและไม่คุ้มเสียครับ เว้นแต่ว่าคุณรู้ว่าคุณกำลังทำอะไร ^_^ เจอกันตอนหน้าครับ สวัสดี

การใช้ Array ร่วมกับ Function

เพื่อทดสอบการใช้ VFP ร่วมกับตัวแปรประเภท Array ผมจึงเขียนคำสั่งดังข้างล่างนี้เพื่อทดสอบการใช้งาน Array ทั้งส่งข้อมูลเข้าไปใน Function และการรับค่า Array ที่คืนจาก Function ออกมาใช้งานต่อ แยกเป็นส่วนๆได้ดังนี้ * สร้างตัวแปร myarray ให้เป็น array แล้วกำหนดค่าเป็น A,B ตามลำดับ DIMENSION myarray[2] myarray[1]="A" myarray[2]="B" * ทดลองพิมพ์ออกมาดูว่าเก็บค่าอยู่จริงมั๊ย ?"test print array value" for i=1 to alen(myarray) ?i,myarray[i] next i * ส่งค่าไปใช้ในฟังก์ชั้น do print_r with myarray * การรับค่า array คืนจากฟังก์ชั่น dime pointer[5] && ต้องประกาศตัวแปร array ที่จะเป็นตัว contrainer (ส่งค่าไปและรับค่ากลับ) ขึ้นมาก่อน pointer = returnarray(@pointer) && จากนั้นส่ง pinter ของตัวแปร array ที่จะเป็นตัว contrainer ไปยังฟังก์ชั่น * ค่าที่รับมาแบบ pointer จะเป็น array หรือไม่ก็ได้ แต่กรณีนี้เป็น array เพราะฟังก์ชั่นคืนค่า pointer ของตัวแปร array กลับมา * ทดลองพิมพ์ค่าออกมาดูว่าเก็บค่าอะไรไว้ do print_r with pointer return * ฟังก...

VFP index tag มีอยู่จริงหรือเปล่า?

ไปเจอมาจากเว็บ foxite.com   ครับ เอามาเก็บไว้ก่อน ส่วนจะใช้ได้ผลยังไงหรือไม่นั้น..แหะๆลองแล้วบอกกันมั่งนะครับ ฮี่ฮี่ฮี่ How can I check if a given file has an index available for use? * Passed the name of an index tag * returns true if it is a tag for the specified table. * Uses table in the current work area if no table name is passed. FUNCTION IsTag( tcTagName, tcTable ) LOCAL ARRAY laTags[1] LOCAL llRetVal *** Did we get a tag name? IF TYPE( 'tcTagName' ) # 'C' *** Error - must pass a Tag Name ERROR '9000: Must Pass a Tag Name when calling ISTAG()' RETURN .F. ENDIF *** How about a table alias? IF TYPE( 'tcTable' ) = 'C' AND ! EMPTY( tcTable ) *** Get all open indexes for the specified table ATagInfo( laTags, "", tcTable ) ELSE *** Get all open indexes for the current table ATagInfo( laTags, "" ) ENDIF *** Do a Case Insensitive, Exact=ON, Scan of the first column of arr...

ใช้ APPEND เพิ่มข้อมูลจากตารางที่เปิดอยู่

SELECT SomeTable  APPEND FROM DBF('cFoundHistRecs')

อยากรู้ว่า..มีฟิลด์ (Field) นี้หรือไม่?

หากคุณอยากรู้ว่ามี FIELD นั้นๆอยู่ใน TABLE หรือไม่ อาจใช้เทคนิคลับตรวจสอบเรื่องนี้ด้วยฟังก์ชั่น TYPE โดยระบุชื่อ FIELD ลงไปแบบนี้ครับ TYPE(<FIELD_NAME>) ซึ่งปกติแล้วฟังก์ชั่น TYPE จะใช้ตรวจสอบว่า VARIABLE ที่เราสนใจนั้น ประกาศ/ทำให้มีขึ้นเพื่อใช้เก็บข้อมูลชนิดอะไร แต่เนื่องจากการทำงานของมัน หากไม่พบตัวแปรที่ระบุมันจะคืนค่าเป็น U ซึ่งย่อมาจาก Unrefined และสามารถนำมาใช้กับ FIELD ได้ด้วย ดังนั้นหากอยากรู้ว่า มีฟิลด์นี้มั๊ย? ก็แบบนี้แหละครับ ? iif(type("fieldname")="U","ไม่มีหรอก","มีสิ") เรียบร้อยครับ ง่ายๆแค่นี้เอง

Find Middle Value มีสามจะเอาหนึ่ง

ในเวลาที่ผมต้องเลือก 1 ใน 3 นี้ ถ้าเป็นการเลือกสาวสวยก็คงลำบากใจเหมือนกัน เพราะอาจเหมาไว้ทั้งหมด แต่หากเป็นการเลือกค่า 1 ค่าจาก 3 ค่าล่ะก็ไม่ยากครับ โดยเฉพาะฟังก์ชั่น max และ min นั้นก็มีกันอยู่แล้ว แต่นี่เป็นฟังก์ชั่นสั้นๆที่จะหาค่าที่ไม่มากและไม่น้อยไปกว่าค่าอีกสองค่าที่เหลือ มาแนวนี้เลยต้องใช้ชื่อว่า midvalue (ค่าขนาดกลาง) ยังไงล่ะครับ ... ไปดู code กันเลย function midvalue parameter val_1,val_2,val_3 maxvalue = max(val_1,val_2,val_3) minvalue = min(val_1,val_2,val_3) returnvalue = 0 do case case val_1>=minvalue .and. val_1<maxvalue returnvalue = val_1 case val_2>=minvalue .and. val_2<maxvalue returnvalue = val_2 case val_3>=minvalue .and. val_3<maxvalue returnvalue = val_3 endcase return returnvalue endfunc วิธีเรียกใช้ก็เหมือนฟังก์ชั่นทั่วไป ให้ a,b และ c เป็นตัวแปรที่มีค่าบรรจุอยู่แล้วเรียกใช้ฟังก์ชั่นว่า ... x=minvalue(a,b,c) ค่า x จะเป็นค่าที่คืนมาจากฟังก์ชั่น ซึ่งจะเป็นค่า 1 ใน 3 ค่าที่ส่งไป และจะไม่มากและไม่น้อ...

Copy Table Structure to Cursor ลอกโครงสร้าง Table ไปเป็น Cursor

A : วันก่อนครับ B : ทำไมครับ A : เขียนโปรแกรมดึงข้อมูลจากหลาย Table มาใส่ใน Cursor เดียว วุ่นมาก โดยเฉพาะการสร้าง Cursor ต้องไป List Structure แล้วมาเขียนคำสั่งสร้าง Cursor หลายๆครั้งเข้าเลยทำเป็นโปรแกรมเลยสิ ก็เขียนอยู่นานตั้งหลายสิบบรรทัด วนรอบเช็ค Field name , Field type , Field size กันให้วุ่น เสร็จปุ๊บก็สบายละทีนี้ต่อไปไม่ต้องปวดหัวเรื่องนี้อีก ใช้มาเรื่อย ดีมากๆเลย เจ๋งเลย ภูมิใจมากๆเลย ชีวิตกูคงง่ายกว่าคนอื่นเยอะ จนวันนึงทำ Source Code ส่วนนั้นหาย เลยต้องมาเริ่มกันใหม่ แล้ว...แล้ว..เจือกจำไม่ได้ด้วยว่าเขียนยังไง!!! B : เวรล่ะครับ A : ก็เลยตั้งสติ เอาใหม่ เริ่มใหม่ ปรากฏว่าใช้คำสั่ง 3 บรรทัดออก B : เฮ้ย!! ขนาดนั้น A : จริงๆนะ บ้าที่สุดเลย หลงภูมิใจความโง่มาตั้งนาน เอ้าดูกันเลยครับ USE <table> AFIELDS(tblFields) CREATE CURSOR <cursorname> FROM ARRAY tblFields ข้อคิดดีๆที่ได้จากเรื่องนี้ - การที่เราทำเรื่องยากๆได้ ก็ใช่ว่าจะเจ๋งเสมอไป - เวลา Source Code โปรแกรมหายอย่าตกใจ!! ลองคิดใหม่ อาจมีอะไรที่เจ๋งกว่าเดิม - เขียนลง Blog เอาไว...

substr กับ utf8 แล้วเป็นสี่เหลี่ยม

วันนี้เจอปัญหา หรือจะเรียกว่าเรื่องท้าทายความคิดดี ผมจำเป็นต้องนำข้อมูลจาก dbf ไปแสดงผลในเว็บผ่านภาษา php ซึ่งมันต้องตัดข้อความที่ค้นหาให้สั้นลงด้วย function substr() ไอ้ที่ตัดน่ะมันก็ได้อยู่ครับ แต่ตัดแล้วได้ผลลัพธ์ที่อ่านออกมั่งไม่ออกมั่งเป็นสี่เหลี่ยมๆ ว้า..า แล้วทีนี้จะแก้กันยังไงลองอ่านดูครับ  จะแก้ได้ต้องหาที่มาของปัญหาก่อน เมื่อผมเขียนชุดคำสั่ง php ให้อ่านค่าฐานข้อมูลที่ encode ด้วยรหัส UTF-8 ออกมา ผลก็ปกติดี แต่เนื่องจากมันยาวเกินไป ผมเลยใช้ฟังก์ชั่น substr() ตัดแบ่ง ผลก็คือ มันเป็นรหัสภาษาที่เพี้ยนๆ บางตัวอ่านได้แต่บางตัวเป็น อักษรสี่เหลี่ยม ก็เลยค้นหาวิธีแก้และที่มาของปัญหาอยู่สักพัก แล้วก็พบว่า ปัญหานี้จะไม่เกิดหากคุณใช้การ encode บางแบบเช่น TIS620 หรือ Windows874 แต่หากใช้คุณ UTF-8 ล่ะก็คุณจะเจอปัญหาแบบที่ผมเจอเนี่ยแหละ วิธีการแก้ปัญหาก็คือ คุณต้องใช้ฟังก์ชั่น mb_substr() (โดยตัว mb_ ข้างหน้าหมายถึง multi-byte) ทดแทนการใช้ substr() ไปเลยครับ ปัญหาก็จะหมดไป จุดต่างของการใช้ mb_substr คือจะต้องประกาศรหัสที่คุณใช้ให้ฟังก์ชั่นนี้มันรู้ด้วย โดยระบุลงไปตาม syntex ของคำสั่งแ...