MySQL 在delete cascade時,並未啟動 Trigger
解決方法:將Delete Cascade 的 Delete 改為自己做 Delete Trigger
本網誌記錄網站設計的一些內容筆記。 網站設計需要整合很多工具與概念。 我畢業自淡江電子計算機科學學系,算是科班出身。但我們那個年代(50年代,唉!LKK了!),網路還只是剛開始,相關的技術都是出社會以後陸續接觸學習。 網站的建立與設計,牽涉的範圍真的很廣泛。 網站的目地是甚麼?銷售網頁、電子購物、廣告、社群經營、互動、教學、客戶服務、網站應用程式、...... 需要整合的人才,程式設計師、資料庫管理師、網頁美編、文字編輯、多媒體製作等等。 這裡將記錄一個LKK對網站系統重新學習與複習,還有教學使用的一些資料。
2015年8月27日 星期四
2015年8月22日 星期六
ScriptCase 的 Radio option 如果直接是文字,可能有問題
如題。
我設計了一個訂單選項,A/B/C,僅能讓使用者三選一,所以,自然是使用 Radio option 來讓使用者選擇。
這可能可以兩種設計方式:一個是直接在資料庫中記錄 "A"/或"B"/或"C"的文字內容,或是另外建一個資料表,一個ID+一個選項說明的欄位 desc ,來選。
Scriptcase 的Radio 的選項資料來源 ,即 lookup method ,可以有(1) Manual 或(2)Automatic
Manual 即是自行輸入選項內容來選;而 Automatic 則是從資料表中擷取。
實驗結果發現,如果是 Manual 方式,可能會有一些問題。
顯示沒問題,使用者選擇也沒有問題,儲存鍵以後,也可以直接將該文字值存入資料庫中。然而是在於 其 Default 選項出現時會有問題。他完全不理會 Default 的設定,也不管了之前選擇儲存在資料庫中讀取出來的現有值!顯示出來的並不是資料庫儲存的值!
而如果將之改為 Automatic 另外一個資料表的時候,就完全正確了!
這應該也是一個 Scriptcase 的bug 吧!
我設計了一個訂單選項,A/B/C,僅能讓使用者三選一,所以,自然是使用 Radio option 來讓使用者選擇。
這可能可以兩種設計方式:一個是直接在資料庫中記錄 "A"/或"B"/或"C"的文字內容,或是另外建一個資料表,一個ID+一個選項說明的欄位 desc ,來選。
Scriptcase 的Radio 的選項資料來源 ,即 lookup method ,可以有(1) Manual 或(2)Automatic
Manual 即是自行輸入選項內容來選;而 Automatic 則是從資料表中擷取。
實驗結果發現,如果是 Manual 方式,可能會有一些問題。
顯示沒問題,使用者選擇也沒有問題,儲存鍵以後,也可以直接將該文字值存入資料庫中。然而是在於 其 Default 選項出現時會有問題。他完全不理會 Default 的設定,也不管了之前選擇儲存在資料庫中讀取出來的現有值!顯示出來的並不是資料庫儲存的值!
而如果將之改為 Automatic 另外一個資料表的時候,就完全正確了!
這應該也是一個 Scriptcase 的bug 吧!
2015年8月18日 星期二
Scriptcase 的 button 如何改變label?
上網找了一下Scriptcase如何程式中,改變顯現的Label。
在程式中,經常會有"鎖定/解鎖"按鈕的需求,當開放時,按鈕顯現的是"鎖定",而當鎖定以後,按鈕顯現的是"解鎖"。也就是兩個不同的狀態,可以隨著狀態不同而交替顯示按鈕名稱。
Scriptcase 裡面並沒有提供 可以直接控制物件屬性的方法,希望以後可以有,這樣可以更有彈性的滿足更多的不同需求。
可是,這會兒還沒有怎麼辦?
找了Scriptcase 的 論壇,找到一個網友提供的方法,就是製做兩個 Button,然後使用 sc_btn_display("button_name",on/off),來控制。
可以設計一個資料表中的欄位,其值只有兩個狀態:1/0。
當 1 時,顯示 button_1, on,而button_2, off
當 0 時,相反。
將這程式寫在 Events -> OnLoad 中,即可。
在程式中,經常會有"鎖定/解鎖"按鈕的需求,當開放時,按鈕顯現的是"鎖定",而當鎖定以後,按鈕顯現的是"解鎖"。也就是兩個不同的狀態,可以隨著狀態不同而交替顯示按鈕名稱。
Scriptcase 裡面並沒有提供 可以直接控制物件屬性的方法,希望以後可以有,這樣可以更有彈性的滿足更多的不同需求。
可是,這會兒還沒有怎麼辦?
找了Scriptcase 的 論壇,找到一個網友提供的方法,就是製做兩個 Button,然後使用 sc_btn_display("button_name",on/off),來控制。
可以設計一個資料表中的欄位,其值只有兩個狀態:1/0。
當 1 時,顯示 button_1, on,而button_2, off
當 0 時,相反。
將這程式寫在 Events -> OnLoad 中,即可。
2015年8月16日 星期日
Scriptcase 的 SQL ERROR!
當訪問數據庫時發生錯誤:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 3
View SQL
昨天發生了這個ERROR,查了好久,查不到!
原先一直以為是 trigger 裡面的SQL Statement 的問題,一行一行的查,每個函數也都花了時間查了!結果,找不到Error!
最後,才一直回憶,我最近一次修改了什麼?
原來,我將一個欄位設為 Disabled Field,我不希望讓使用者可以點擊那個欄位,結果就出現了這個 SQL syntax error 的問題。
將之改回 Enable ,就沒問題了!
後來,我發現有個屬性:SQL Type:Text,這個屬性我過去幾乎沒有去管他,也沒有發生過什麼錯誤。這次,因為這個欄位的型態應該是 Number,而不是 Text,所以,我將之改為 Number,一樣設 Disabled Field,結果就OK了!
原來問題發生在這裡:SQL Type不符合上面!
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 3
View SQL
昨天發生了這個ERROR,查了好久,查不到!
原先一直以為是 trigger 裡面的SQL Statement 的問題,一行一行的查,每個函數也都花了時間查了!結果,找不到Error!
最後,才一直回憶,我最近一次修改了什麼?
原來,我將一個欄位設為 Disabled Field,我不希望讓使用者可以點擊那個欄位,結果就出現了這個 SQL syntax error 的問題。
將之改回 Enable ,就沒問題了!
後來,我發現有個屬性:SQL Type:Text,這個屬性我過去幾乎沒有去管他,也沒有發生過什麼錯誤。這次,因為這個欄位的型態應該是 Number,而不是 Text,所以,我將之改為 Number,一樣設 Disabled Field,結果就OK了!
原來問題發生在這裡:SQL Type不符合上面!
mysql trigger error handle
DELIMITER $$
DROP TRIGGER IF EXISTS before_tblinventoryexceptionreasons_delete $$
CREATE TRIGGER before_tblinventoryexceptionreasons_delete
BEFORE DELETE ON tblinventoryexceptionreasons
FOR EACH ROW BEGIN
IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblinventoryexceptionreasons = old.idtblinventoryexceptionreasons) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory exception reasons table with this item.';
END IF;
END$$
DELIMITER ;
DELIMITER $$
DROP TRIGGER IF EXISTS before_storesalesconfig_delete $$
CREATE TRIGGER before_storesalesconfig_delete
BEFORE DELETE ON tblstoresalesconfig
FOR EACH ROW BEGIN
IF (SELECT COUNT(*) FROM tblstoresales WHERE tblstoresales.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the sales table with this item.';
END IF;
IF (SELECT COUNT(*) FROM tblinventory WHERE tblinventory.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory table with this item.';
END IF;
IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory exceptions table with this item.';
END IF;
IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.';
END IF;
END$$
DELIMITER ;
DELIMITER $$
DROP TRIGGER IF EXISTS before_tblinvoice_delete $$
CREATE TRIGGER before_tblinvoice_delete
BEFORE DELETE ON tblinvoice
FOR EACH ROW BEGIN
IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblinvoice = old.idtblinvoice) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.';
END IF;
END$$
DELIMITER ;
DROP TRIGGER IF EXISTS before_tblinventoryexceptionreasons_delete $$
CREATE TRIGGER before_tblinventoryexceptionreasons_delete
BEFORE DELETE ON tblinventoryexceptionreasons
FOR EACH ROW BEGIN
IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblinventoryexceptionreasons = old.idtblinventoryexceptionreasons) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory exception reasons table with this item.';
END IF;
END$$
DELIMITER ;
DELIMITER $$
DROP TRIGGER IF EXISTS before_storesalesconfig_delete $$
CREATE TRIGGER before_storesalesconfig_delete
BEFORE DELETE ON tblstoresalesconfig
FOR EACH ROW BEGIN
IF (SELECT COUNT(*) FROM tblstoresales WHERE tblstoresales.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the sales table with this item.';
END IF;
IF (SELECT COUNT(*) FROM tblinventory WHERE tblinventory.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory table with this item.';
END IF;
IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory exceptions table with this item.';
END IF;
IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.';
END IF;
END$$
DELIMITER ;
DELIMITER $$
DROP TRIGGER IF EXISTS before_tblinvoice_delete $$
CREATE TRIGGER before_tblinvoice_delete
BEFORE DELETE ON tblinvoice
FOR EACH ROW BEGIN
IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblinvoice = old.idtblinvoice) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.';
END IF;
END$$
DELIMITER ;
2015年8月13日 星期四
Scriptcase 開發有感:Business Rule 設計在mysql
應該盡量把 Business Rule 設計在 mysql 裡面,也就是 Stored Procedure / Trigger 等
Scriptcase 只要單純的做 FORM的 IO/AUDI就好。
舉一些例子:
會員編號的產生,auto_increment 是一個自動產生數字序號的方法
如果是要產生文字的編碼,就得自己製作。這應該直接由 trigger 來做即可,不用 AP 來做。
WRITE ONCE:只能寫一次的資料。
Scriptcase 只要單純的做 FORM的 IO/AUDI就好。
舉一些例子:
會員編號的產生,auto_increment 是一個自動產生數字序號的方法
如果是要產生文字的編碼,就得自己製作。這應該直接由 trigger 來做即可,不用 AP 來做。
WRITE ONCE:只能寫一次的資料。
2015年8月12日 星期三
Scriptcase:如何設定一個欄位的初始值
當有需要在新增一筆資料時,有些欄位需要給予一個初始值。
在Scriptcase 裡面,Fields -> Initial Value (type) ->Defined Value,底下 Initial Value:可以設入一個初始值。
如果該初始值,是一個常數,如:數字、字母,那簡單,輸入就好。而如果是一個變數,就可以用 [variable] 。
那可以是函數嗎? 一個自訂函數可以嗎?
好像不行ㄟ!
只好試試看其他方法。
後來想了,將函數寫在 Form Event -> OnApplicationInit 中,將結果寫在一個變數中, 例如[v_result],然後,將此變數填在該欄位的 Initial Value裡面。
同時,記得到 Application -> Global Variable 中去找到這個變數,並將之設定為"OUT"
在Scriptcase 裡面,Fields -> Initial Value (type) ->Defined Value,底下 Initial Value:可以設入一個初始值。
如果該初始值,是一個常數,如:數字、字母,那簡單,輸入就好。而如果是一個變數,就可以用 [variable] 。
那可以是函數嗎? 一個自訂函數可以嗎?
好像不行ㄟ!
只好試試看其他方法。
後來想了,將函數寫在 Form Event -> OnApplicationInit 中,將結果寫在一個變數中, 例如[v_result],然後,將此變數填在該欄位的 Initial Value裡面。
同時,記得到 Application -> Global Variable 中去找到這個變數,並將之設定為"OUT"
2015年8月11日 星期二
2015年8月8日 星期六
Scriptcase 控制欄位鎖住/開鎖的方法
會有需要鎖單功能,也就是將表單鎖住,不讓使用者修改。
另一個應用場景是:如果希望自動執行SAVE,而不要讓使用者再按一次SAVE,就可以在程式中自己加入這段程式碼。
需要經過開鎖,才可以編修。
ScriptCase 有提供對欄位 設為 readonly, disabled 等 macro
sc_block_display (Block_Name, on/off)
sc_field_disabled ("Field_Name = True/False", "Parameter")
sc_field_display ({My_Field}, on/off)
sc_field_readonly ({Field}, on/off)
sc_form_show 'on' or 'off
以上這些 Macro,可以對 form / block / field 做各種顯示不顯示,等設定。
而對於 Master / Detail 裡的 Detail 就不能了。因為 Detail 是另一個 Application 不是一個 field 或 block!
如果設了兩個 Block,分別設為 detail ,一個有IUD功能,另一個沒有,結果還是沒有!
最後,試了一個變通的方法:
製作兩個 Detail Application,一個可以準備可以允許編輯用的;另一個準備來只准讀取 Read Only 的。幸好,使用 Scriptcase 複製 Application 還蠻方便。一下子就好了,名稱上一個叫做 xxxxxx_detail ;另一個叫做 xxxxx_detail_readonly,其內容,其實都一模一樣。
就在 Master application中,分別建立兩個 Master/Detail,一個在聯結中設定允許INSERT/UPDATE/DELETE、另一個不允許INSERT/UPDATE/DELETE,然後,分別放在兩個不同的Block中,而用 sc_block_display()來控制顯示哪一個block,就可以了!
註:2015/08/17 今天終於找到了,讓上面所講的鎖定/結鎖,能自動儲存起來,存在一個欄位中,然後,往前、往後以後,回到這一筆資料,依然是鎖定/解鎖 的狀態。
那就是:
if ({lock_field}=='1') {
{lock_field}='0';
enable_all_fields();
} else {
{lock_field}='1';
disable_all_fields();
}
sc_ajax_javascript( 'nm_atualiza', array('alterar'));
sc_block_display (Block_Name, on/off)
sc_field_disabled ("Field_Name = True/False", "Parameter")
sc_field_display ({My_Field}, on/off)
sc_field_readonly ({Field}, on/off)
sc_form_show 'on' or 'off
以上這些 Macro,可以對 form / block / field 做各種顯示不顯示,等設定。
而對於 Master / Detail 裡的 Detail 就不能了。因為 Detail 是另一個 Application 不是一個 field 或 block!
如果設了兩個 Block,分別設為 detail ,一個有IUD功能,另一個沒有,結果還是沒有!
最後,試了一個變通的方法:
製作兩個 Detail Application,一個可以準備可以允許編輯用的;另一個準備來只准讀取 Read Only 的。幸好,使用 Scriptcase 複製 Application 還蠻方便。一下子就好了,名稱上一個叫做 xxxxxx_detail ;另一個叫做 xxxxx_detail_readonly,其內容,其實都一模一樣。
就在 Master application中,分別建立兩個 Master/Detail,一個在聯結中設定允許INSERT/UPDATE/DELETE、另一個不允許INSERT/UPDATE/DELETE,然後,分別放在兩個不同的Block中,而用 sc_block_display()來控制顯示哪一個block,就可以了!
註:2015/08/17 今天終於找到了,讓上面所講的鎖定/結鎖,能自動儲存起來,存在一個欄位中,然後,往前、往後以後,回到這一筆資料,依然是鎖定/解鎖 的狀態。
那就是:
if ({lock_field}=='1') {
{lock_field}='0';
enable_all_fields();
} else {
{lock_field}='1';
disable_all_fields();
}
sc_ajax_javascript( 'nm_atualiza', array('alterar'));
註:自己另行設計一個 button,TYPE:JavaScript,可以自訂 LABEL、還有 CONFIRM Message等。
在下面的 JavaScript 裡面輸入:
nm_atualiza('alterar');
這是執行"SAVE"的意思。
另一個應用場景是:如果希望自動執行SAVE,而不要讓使用者再按一次SAVE,就可以在程式中自己加入這段程式碼。
下面這一段程式:
執行SAVE,然後等一秒鐘,然後自動下一筆(nm_move('avanca');)
nm_atualiza('alterar'); setTimeout(function() {nm_move('avanca');},1000); //you need a delay (1000 = 1s) here to wait for the update to finish, otherwise the form would lock up. You might need to adjust the time. Just try what works best for your system.
nm_atualiza('alterar'); setTimeout(function() {nm_move('avanca');},1000); //you need a delay (1000 = 1s) here to wait for the update to finish, otherwise the form would lock up. You might need to adjust the time. Just try what works best for your system.
Parameters for nm_move():
first = ‘inicio’
previous = ‘retorna’
next = ‘avanca’
last = ‘final’
first = ‘inicio’
previous = ‘retorna’
next = ‘avanca’
last = ‘final’
2015年8月7日 星期五
Scriptcase 的 pdf 轉出
在 FORM 中的 PDF Export ,如果直接是 表單內容,可以依據表單格式輸出,然而,如果內含有 Master/Detail 的細項內容,就產生錯誤了。
看了 help 教學 Video,似乎要另外用 PDF Application來做才可以。
看了 help 教學 Video,似乎要另外用 PDF Application來做才可以。
2015年8月6日 星期四
scriptcase 的 bugs
今天使用 ScriptCase 設計表單,表單日期欄位原本都是正常顯示的,但是當新增一個狀態欄位時,表單日期的顯現出現錯誤了!
原本日期顯示應該是: yyyy/mm/dd
增加一狀態欄位以後,變成: yyyy mm d
該狀態欄位為空白時,日期欄就是正常的;狀態欄位有值時,就變成錯誤格式!
將狀態欄位刪除,日期顯示格式就一切正常!
查看表單日期的資料庫內容,並沒有改變,沒有錯誤。顯示是 Scriptcase 在顯示該表單欄位資料時,由於Scriptcase內部程式的錯誤,某些變數或...相衝,導致顯示格式錯誤!
後來將狀態欄位加回去,將狀態欄位的型態改為 <select>,日期也就好了!
原本狀態欄位型態是 <integer>
註:2015/08/16 剛才又發生一次類似的錯誤。
錯誤的狀況是:一個 integer 欄位型態, 然後用 Lookup Setting 設定為另外顯示該ID的名稱值。但是這樣一來,日期欄位的格式就變了!
將該欄位型態由 Integer 改為 Select ,一樣用Lookup Setting,而 加Where 設定,這樣就只有單一值可以顯示,不會有選項可以選。這樣那個日期顯示就正常了!
原本日期顯示應該是: yyyy/mm/dd
增加一狀態欄位以後,變成: yyyy mm d
該狀態欄位為空白時,日期欄就是正常的;狀態欄位有值時,就變成錯誤格式!
將狀態欄位刪除,日期顯示格式就一切正常!
查看表單日期的資料庫內容,並沒有改變,沒有錯誤。顯示是 Scriptcase 在顯示該表單欄位資料時,由於Scriptcase內部程式的錯誤,某些變數或...相衝,導致顯示格式錯誤!
後來將狀態欄位加回去,將狀態欄位的型態改為 <select>,日期也就好了!
原本狀態欄位型態是 <integer>
註:2015/08/16 剛才又發生一次類似的錯誤。
錯誤的狀況是:一個 integer 欄位型態, 然後用 Lookup Setting 設定為另外顯示該ID的名稱值。但是這樣一來,日期欄位的格式就變了!
將該欄位型態由 Integer 改為 Select ,一樣用Lookup Setting,而 加Where 設定,這樣就只有單一值可以顯示,不會有選項可以選。這樣那個日期顯示就正常了!
2015年8月5日 星期三
ScriptCase master/detail,當Master的一個選項值改變,Detail 要跟著變動,怎麼做?
Master/Detail 是關聯式資料庫概念裡面,經常有的資料庫結構關係。例如:訂單及訂單明細。訂單是 MAster ,訂單明細是 Details
如果由於 訂單的 某個欄位(field1)改變時,而Detail 裡面的選項也要跟著改,那就使用 field1 改變時,整個Form Reload 選項,即可達成目的了。
如果反過來,是 Detail 裡面的值改變時,要更新 Master 的欄位值,則使用 sc_master_value('Object', Value)
如果由於 訂單的 某個欄位(field1)改變時,而Detail 裡面的選項也要跟著改,那就使用 field1 改變時,整個Form Reload 選項,即可達成目的了。
如果反過來,是 Detail 裡面的值改變時,要更新 Master 的欄位值,則使用 sc_master_value('Object', Value)
2015年8月1日 星期六
Scriptcase 不能編修了!
經過調查,原來是我的欄位中設了一個 radio 欄位,而其值必須由另一個table產生,只要把這個欄位改成 text 就可以了。
可見,是此欄位的問題。
看來,必需另想辦法了!
使用這種產生器的缺點,就是你最好使用他的功能就好,她畢竟不是萬事都能做的!
可見,是此欄位的問題。
看來,必需另想辦法了!
使用這種產生器的缺點,就是你最好使用他的功能就好,她畢竟不是萬事都能做的!
訂閱:
文章 (Atom)
如何判斷現在FORM是在 insert mode? 還是 update mode?
只要用 if (empty({primary_key})) 就可以知道是否為新增模式了。 如果 {promary_key} 是空白的,那麼就是在新增模式;反之,就是更新模式。 以上。
-
讓 PHP 接收 post 的 json 資料 - 8月 02, 2013 我們在串接API的時候會用到 CURL 函式 POST 資料給 JSON 接收,雖然我們是使用 POST 傳出資料。但是我們在接收的 SERVER 端使用 $_POST 卻抓不到任何資料。 原來 ...
-
Note that it's ultimately the responsibility of the server admin to ensure his system is secure. These are some basic security tips tha...
-
分享:網站上 http://shuai.be/archives/php-undefined-index/ 平時用 $_GET[ ‘ xx ’ ] 取得參數值時,如果之前不加判斷在未傳進參數時會出現這樣的警告 : PHP Notice: undefined i...