2024年4月9日 星期二

Oracle的預儲程序參數與資料表名稱相同時的異常

Oracle的預儲程序參數與資料表名稱相同時的異常

最近踩了一個坑,主要是一個預儲程序利用給定的參數來做查詢,再將查詢到的資料寫入變數,原本都還很正常,但是突然失效,偏偏單獨的查詢都很正常,遍尋不著,後來同事協助之後終於脫坑。

create or replace procedure test_proc(p_a varchar2) is
begin
	select column into v_column from table where column_a = p_a;	
end

上面是一個示意的範例,test_proc這個預儲程序在得到p_a之後就會去資料表查詢,然後將資料寫入v_column,但不知道什麼時候,資料表中被加入一個同名欄位,也就是p_a,這導致了參數中的p_a就失效了。

這可能就代表著在oracle的預儲程序中,整個上下文還是會以查詢資料表為主,查詢資料表沒有對應欄位名稱的時候才會以變數做為條件?

這很頭痛的是,這是無聲異常,而且還可能造成大量異常,不得不防,以後預儲函數的參數必需要設置的非常怪異,才不會有機會跟未來人命名欄位名稱相同。

2024年3月26日 星期二

Roland F701開箱

ROLAND F701(白色)電鋼琴

自從搬出老家之後,喵小姐一直心心唸唸著想要一台電鋼琴,終於在今年的年初,也就是過年的時候,趁著活動帶著她去一趟竹北鴻韻,雖然這已經是第n次去了。

原本預算是20k,打算買台基本的能在家過過乾癮就好,不過實際到現場按壓幾次之後,喵小姐還是決定把預算突破天際,就買了F701,常言道,捏一下就上去了,這一捏簡直是蛋破小鳥死。但是為了喵小姐的夢想我還是捏上去了。

其實最一開始是希望老泡先生可以學鋼琴,但是他從小就愛敲敲打打,所以最後選擇學習爵士鼓。現在多了一個安咕咕先生,希望他會愛上鋼琴。

購買的時候因為是要安置在三樓,多了樓層費,來的師父在安裝上也非常熟門熟路的,很辛苦,到我家已經是晚上八點多,離開的時候說他還有另外兩家要送,看來在台灣熱愛學習音樂的人真的不少。

F701在DEMO的時候有特別提到可以搭配APP,算是蠻方便的,壓下去的聲音也會隨著手指的力度而有所不同,這是當初喵小姐捨棄初階機的最主要原因。搭配耳機就可以在不擾人清夢的情況下好好練習。而且架子本身也提供一個吊掛耳機的地方,非常方便。

總之,好機,白色更是美的西哩花拉的,搭配活動送了一個升降椅,值得入手。



2024年2月27日 星期二

利用tailwind css設計一個簡易側導覽

最近在嚐試利用前端搭配flask寫網頁,幾個小功能,但是需要一個連結給使用者,所以就想要做一個側導覽功能,初始結構是20美元小助理給的,自己微調一下,符合使用比較重要,大致就是拆成html跟javascript,css的部份直接採用tailwind套版,直觀又快速。

首先是html,版面的部份要切出左側一個區域來給側導覽,然後一個按鈕,側導覽的初始狀態是整個隱藏,經過按鈕點擊來做顯示與隱藏的切換:

<div id="sidebar" class="fixed top-0 left-0 h-full bg-gray-800 transition-transform duration-300 ease-in-out -translate-x-full z-10">  
 <div class="mt-16">  
 <ul class="text-white">  
 <li class="p-4 hover:bg-gray-700"><a href="{{ url_for('Router1') }}">Router1</a></li>  
 <li class="p-4 hover:bg-gray-700"><a href="{{ url_for('Router2') }}">Router2</a></li>  
 <li class="p-4 hover:bg-gray-700"><a href="{{ url_for('Router3') }}">Router3</a></li>  
 <li class="p-4 hover:bg-gray-700"><a href="{{ url_for('Router4') }}">Router4</a></li>  
 </ul> </div></div>  
<button id="toggleNav" class="fixed top-0 left-0 mt-10 p-2 text-white bg-blue-500 rounded z-20 transition-transform duration-300 ease-in-out">  
  MenuBar  
</button>

接著在按扭地方加入一個監聽器,主要是偵測到點擊的時候就做sidebar屬性-translate-x-full的切換,然後按鈕的屬性再隨著sidebar的屬性做變化的判斷

document.addEventListener('DOMContentLoaded', function() {  
    const toggleNavButton = document.getElementById('toggleNav');  
  toggleNavButton.addEventListener('click', function() {  
        const sidebar = document.getElementById('sidebar');  
  sidebar.classList.toggle('-translate-x-full');  
  
 if(sidebar.classList.contains('-translate-x-full')){  
            toggleNavButton.style.transform = 'translateX(0px)';  
  } else {  
            toggleNavButton.style.transform = `translateX(${sidebar.offsetWidth}px)`;  
  }  
    });  
});

2024年1月30日 星期二

Graph disconnected: cannot obtain value for tensor KerasTensor

Graph disconnected: cannot obtain value for tensor KerasTensor

TensorFlow版本:2.4.0

最近在嚐試寫PGGAN,參考來源程式碼在過程中做了轉型:

input_img = tf.keras.layers.Input(shape=(4, 4, 3))
input_img = tf.cast(input_img, tf.float32)
x1 = tf.keras.layers.AveragePooling2D()(input_img)

這種情況下每次都會跳出異常訊息:

Graph disconnected: cannot obtain value for tensor KerasTensor

搞了三天三夜,不管怎麼改變寫法,改成lambda、或是tf.dtypes.cast都不行:

input_img = tf.dtypes.cast(input_img, tf.float32)

結果我就很生氣的把變數名稱改了…

input_img = tf.keras.layers.Input(shape=(4, 4, 3))
input_img2 = tf.cast(input_img, tf.float32)
x1 = tf.keras.layers.AveragePooling2D()(input_img2)

就好了,對,沒錯,就好了。恭喜我自己,怪了,那他是怎麼訓練完成的。

2024年1月25日 星期四

PyGWalker

Python Tool: PyGWalker

python pygwalker data visualization

機器學習的一個重要過程就是資料分析,在做資料分析的時候最需要的就是一個方便的資料可視化軟體,AI總是需要有BI的伴隨。BI工具著名的有QLIK、Tableau、PowerBI,如果是Python的可視化套件就更是百家爭鳴。

不過最近看到一個讓我驚豔的套件,那就是PyGWalker,簡單幾段程式就讓我擁有類似於Tableau的界面,這讓我在資料分析上多了不少便利性。

官方Github連結

安裝

這次的測試是在conda,所以記得先建立一個虛擬環境:

conda create --name PyGWalkers

確定一下環境有沒有建立:

conda env list

然後轉入虛擬環境:

activate PyGWalkers

安裝:

conda install -c conda-forge pygwalker

安裝ipykernel:

conda install ipykernel

註冊kernel(要記得註冊,不然在執行中就無法選擇對應的kernel):

python -m ipykernel install --user --name PyGWalkers --display-name "Python (PyGWalkers)"

安裝確認:

conda list

啟動:

jupyter notebook

實作測試

從官方範例來看,就是簡單的兩步:

  1. 載入資料(csv -> dataframe)
  2. 執行
# 載入需求套件
import pandas as pd
import pygwalker as pyg
# 指定資料來源路徑
file_path = r'your file path'
# 載入dataframe
df = pd.read_csv(file_path)
# 確認資料是否確實載入
df.head()
# johnnie walker
pyg.walk(df)

image for PyGWalker

執行之後就會進入一個互動式的UI介面,是不是很讓人驚豔?剩下的就只是拖拖拉拉來觀察資料之間的關聯性了,這對小眾資料處理人員來說是非常便利的工具。

2023年8月23日 星期三

Python + SAPGUI Script = 自動化重覆性事務性作業

Python + SAPGUI Script = 自動化重覆性事務性作業

reference

今天因為其他部門的資訊作業上的問題導致我這邊必需協助刪除庫存批屬性,雖然才八十幾筆,但也是讓我感到憤怒,憤怒可以提升技術力,所以我決定找方法自動化處理。

兩年前的今天,k-weiming寫下這個,真的是緣份,我的環境是python 3.11,需要的工具就是pywin32:

pip install pywin32

sap的設置也要確認,不過這取決於公司的管理策略,如果剛好沒被管控的話那就可以使用:

  1. Enable scripting:啟用scripting
  2. Notify when a script attaches to SAP GUI:對接上的時候是不是會跳出訊息,另一個也是一樣的設置

準備工作完成,再來就是要先取得執行的GUI的session:

import win32com.client def get_client(): #: 從com服務器中取得SAPGUI的物件 sap_gui_auto = win32com.client.GetObject('SAPGUI') if not type(sap_gui_auto) == win32com.client.CDispatch: print("SAPGUI is not running") return #: 取得SAPGUI的腳本引擎,所以接上的時候GUI會出現警示訊息 #: 這可以從gui設罝上取消 application = sap_gui_auto.GetScriptingEngine if not type(application) == win32com.client.CDispatch: print("SAPGUI is not running") return #: 這邊取得的是實際啟動的SAPGUI的物件 #: 以實際登入的使用者為條件 for conn in range(application.Children.Count): connection = application.Children(conn) #: 這邊取得的是登入的帳號所開啟的視窗(session) for sess in range(connection.Children.Count): session = connection.Children(sess) if session.Info.Transaction == "SESSION_MANAGER": return session

接下來的動作我們可以先利用錄製的方式來取得腳本,畢竟欄位框那麼多,即使看著官方的文件也很難一個一個找出來,最好的方法就是讓系統幫我們找出來。

開啟錄製程式:

錄製程式開啟之後如下:

中間那個圓點就是腳本錄製,腳本的保存地方則是根據你的『Save To』而定。

錄製完成之後在指定資料夾就會有vbstxt檔,打開txt檔,裡面會有你的腳本資訊:

紅框處的部份就是操作過程的相關物件的定位資訊以及操作的動作,像是按下去或是選擇某個分頁之類的。

以我自己的作業目標為例,我是想要自動化刪除很多庫存批屬性資料,所以就可以這麼做:

if __name__ == '__main__': #: reference #: https://k-weiming.github.io/2021-08-23-sap-connection-python/ session = get_client() #: 到SAP的交易代碼輸入欄位輸入MSC2N session.findById("wnd[0]/tbar[0]/okcd").text = "/nMSC2N" #: 按下Enter session.findById("wnd[0]").sendVKey(0) #: 輸入物料編號 session.findById("wnd[0]/usr/subSUBSCR_BATCH_MASTER:SAPLCHRG:1111/subSUBSCR_HEADER:SAPLCHRG:1500/ctxtDFBATCH-MATNR").text = "CA09B2002-1Z01" #: 輸入工廠 session.findById("wnd[0]/usr/subSUBSCR_BATCH_MASTER:SAPLCHRG:1111/subSUBSCR_HEADER:SAPLCHRG:1500/ctxtDFBATCH-WERKS").text = "A101" #: 輸入批號 session.findById("wnd[0]/usr/subSUBSCR_BATCH_MASTER:SAPLCHRG:1111/subSUBSCR_HEADER:SAPLCHRG:1500/ctxtDFBATCH-CHARG").text = "A120069722" #: 按下Enter session.findById("wnd[0]").sendVKey(0) #: 選擇批屬性分頁 session.findById("wnd[0]/usr/subSUBSCR_BATCH_MASTER:SAPLCHRG:1111/subSUBSCR_TABSTRIP:SAPLCHRG:2000/tabsTS_BODY/tabpCLAS").select() #: 按下刪除 session.findById("wnd[0]/usr/subSUBSCR_BATCH_MASTER:SAPLCHRG:1111/subSUBSCR_TABSTRIP:SAPLCHRG:2000/tabsTS_BODY/tabpCLAS/ssubSUBSCR_BODY:SAPLCHRG:2300/btnCLASS_DEL").press()

我的範例中少了按下保存的動作,因為只是測試,所以就沒有錄保存的動作。

這接口很方便,因為我不需要去寫abap來做錄製,不過這種作法應該是比較適用於重覆性的事務性作業,又或者剛好沒有BAPI、RFC可以使用,那就可以用這種方式來搜集資料。

2023年4月14日 星期五

新冠感染記實

最近我也終於感染新冠,在病毒的挑選之下,我真正成為一個新人類,我是約翰康納,如果你聽到....不是,我是說,我記錄一下我的狀況:

1. 發燒來的又快又急,晚上洗好澡之後就瞬間牙起來,體溫馬上升到38.2

2. 體溫開始無限制向上來到39.7

3. 全身發寒,發熱,大概跟張無忌一樣的情況,會冷到不自覺的發抖

4. 因為吃普拿疼,晚上睡覺大量出汗,床單跟棉被都溼

上面這個部份是四天內的循環,基本上吃了普拿疼之後的兩小時藥效生效之後就會降到37.9~38.5的溫度。我在第三天的時候喉嚨痛的症頭出現,連吞口水都覺得生不如死,所以喝楊桃汁跟吃喉糖,大概第五天之後喉嚨痛的症頭就消失了。

每天洗澡的時候我會讓自己用力一咳,因為一整天的痰都不知不覺得卡在喉嚨深處,只要你咳就會發現有一口濃濃的痰,超級噁心,一定要咳掉。

偶爾會出現鼻塞的情況,但不嚴重,然後咳的頻率還好,基本還可以忍住,喝了五天的清冠一號,水煎藥,甘甜可口,入口回甘。

不過最糟的是我發現我的味覺出現嚴重問題,我一直覺得鼻子的某個地方好像被什麼東西覆蓋住,導致我的味覺中有一個關鍵味道嚐不出來,這造成我喝咖啡變的超級噁心。

短短的五天基本上對我來說非常漫長,一人中獎多人累攤,還要擔心同住家人也受感染。只是個人生記錄,希望不要再有下次了,累。