2011年6月30日 星期四

辨識SQL SERVER版本

我不清楚連的SQL Server版本
所以我在SSMS上
選擇連線的Server
按右鍵選擇屬性
出現了下圖的伺服器屬性畫面










上圖看到版本的屬性
其值是9.00.4035.00
阿咧~這是三小朋友
本來預期會看到SQL Server 2005 SP3這樣的東西
結果看到這一串數字
反而覺得更疑惑??????

搜尋到微軟的這一篇文章
哈哈~所有問題都解決啦!!

以INSERT INTO方式匯出資料

看同事寄的文稿裡面
有一個.sql檔案
裡面以INSERT INTO TABLE VALUES
的方式把TABLE備分起來
這引起了我的興趣
因為據我所知
SQL SERVER 2008 Management Studio並沒有這樣功能
他頂多只能匯出該TABLE的SCHEMA, 如下圖














然後目前我知道最新版的SQL SERVER是2008 R2
據說是2010.04開始開放下載Express版本
SQL SERVER 2005, SQL SERVER 2008, SQL SERVER 2008 R2 都有Express版本
然後Express版本還可以分為 Express with Tools 與 Express Advanced Services版本
所謂Express(快捷版)就是不用錢
with Tools就是把SSMS(SQL Server Management Studio)也包在裡面
Advanced Services又比with Tools包含一些報告的功能??
據我所知2008和2008 R2才有出with Tools版本

Express版本讓一般程式學習使用者
或者想先試試產品功能的人
能夠免費取得並試用產品
其內容跟正式版大致一樣
不過功能少了一些
對於機器的支援也較有限制
比如支援CPU有幾顆
記憶體多大等....
唉呀參考一下維基百科吧!

題外話扯多了
今天要講DB備份的方式
對於SQL Server而言
以前都是用SQL Server匯入和匯出精靈
來幫我從.txt檔(以適當的delimiter(定義符號)分開欄位, 如逗號或空白字元)
匯入資料到TABLE
或從TABLE匯出資料到.txt檔
所以看到這樣用INSERT語法完成的備份檔
覺得很新奇也很好用

搜尋了一下
主要有三種方式可以達成以INSERT句子
完成備份資料表的資料

1.Toad for SQL Server
2.一個外國人寫好的神奇SP(預存程序)
3.一個小小的軟體SQL Server Dumper 參考點2

我是利用SQL Server Dumper做的
該軟體所佔空間很小
畫面又相當直覺
算是相當好上手的軟體!!

2011年6月29日 星期三

INSERT多筆資料

INSERT INTO SAMPLE_TABLE
VALUES('AMY','TAIPEI'),('JOHN','NEW YORK')

上面的語法可以新增多筆資料
之前公司用IBM DB2可以執行無誤
可是在SQL SERVER 2005上始終都無法執行
查了資料1資料2
原來要一直到SQL SERVER 2008才有支援......

圖 MSDN文件庫中, SQL SERVER 2005與2008的INSERT語法差異

所以
如果無法用最上面的語法
新增多筆資料
那麼你有兩種選擇:
1.用INSERT新增一筆, 然後好幾次
2.用INSERT INTO SELECT FROM UNION SELECT FROM UNION....方法
詳情請參考這裡

Oracle SQL Loader

有個需求要把Excel裡的東西
匯到Oracle裡面的資料表

以前在操作IBM DB2時
要先把.xls轉換成.csv或.txt
然後下import指令
詳細內容忘記了
大概是: import from 'unit_contrast.txt' of del replace into UNIT_CONTRAST
這樣一行就可以搞定

可是換到Oracle
變得稍為複雜的一些
必須將命令寫近文稿裡
然後執行此文稿

unit_contrast.ctl :
load data
infile "unit_contrast.txt"
badfile "bad.log"
discardfile "discard.log"
into table unit_contrast
fields terminated by ',' optionally enclosed by '"'
trailing nullcols
( unit_id ,
unit_name
)

然後用TOAD的SQL Loader Wizard選擇此控制檔
或者在命令列底下執行:
sqlldr 帳號/密碼 control=unit_contrast.ctl

參考網站:
網站1
網站2
網站3

2011年6月28日 星期二

java的數字

一.
System.out.println(1-0.8);

上一句的輸出是:

0.19999999999999996

前公司業務跟錢有關
所以在處理小數有關的東西
一律都是用BigDecimal類別

System.out.println((new BigDecimal("1").subtract(new BigDecimal("0.8"))));

上一句的輸出是:

0.2

二.
System.out.println(365*(1+1000000000000000));

上一句的輸出是:

integer number too large: 1000000000000000

要解決這個問題很簡單
只要加個L就解決了
System.out.println(365*(1+1000000000000000L));

這其中的奧妙
就在於JAVA
作四則運算時
會把運算子旁邊的兩個運算元
都提升到較大運算元的型別後
再開始計算
這個叫作Promotion
(
註:Promotion指由小型別換到大型別
這會自動發生
Cast則指由大型別換到小型別
這就要由程式員特別指定


還有
JAVA基本型別的大小
可以參這篇文章
byte<short<int<long<float<double
浮點數型別的double和float都比整數型別的long還要大
這是因為這float和double
主要用來儲存小數數值,也可以用來儲存範圍更大的整數 
)

以本例而言
1+1000000000000000L
在JAVA中所有整數都預設為int
而所有小數都預設為double
但是加了個L
就把該整數提升為long型別

所以
1000000000000000先變成了long
->1+1000000000000000L = int + long = long + long = long
接著365*long = int * long = long * long = long = 365000000000000365
轉成long型別後就能裝下 365000000000000365 這麼大的數字了

2011年6月27日 星期一

2011年6月23日 星期四

心得:測試時, 還是選同樣的Web Container測試吧

有中文亂碼問題
在Tomcat上測試可以的程式碼
佈署到WebSphere就是不行....

為什麼不行?
答:我也不知道...

可能原因很多
跟web container如何實作有關
或者跟server所用的作業系統也有關...

目的是要能在最終機台上正常顯示
所以要測試時
請盡可能找和最終機台環境最相似的測試環境
進行測試
才能確保測試結果萬無一失!

sql server 2005 management studio express沒有匯出匯入精靈

sql server 2005 management studio express沒有匯出匯入精靈
sql server 2008 management studio express才有
如下圖
在資料庫按右鍵->工作->匯入資料/匯出資料


java io的flush

舉凡使用java做io時
必須要使用flush()
才能將資料輸出到輸出裝置
輸出裝置可能是: 螢幕或檔案等...

以下這個範例
FileWriter要寫出一個String
但是十秒後才會flush
所以執行時
你會看到先建立sample.txt
但是打開一看
裡面空無一物
過了十秒後
再次打開sample.txt
會發現裡面多了一行Today is a good day

import java.io.*;
import java.util.*;

public class Test_IO{

 public static void main(String args[]){
  try{
   String content= "Today is a good day.";
   FileWriter fo = new FileWriter("sample.txt");     
   fo.write(content);

   long curr = System.currentTimeMillis();
   while(true){
   long result = System.currentTimeMillis()-curr;
    if(result/10000 == 1){
     //10秒後flush
     fo.flush();
     System.out.println("Flushed!");    
     break;
    }
   }
   fo.close();  
  }catch(Exception e){
   e.printStackTrace();
  }
 }//end main
}//end class


你或許會問
常常用的System.out.println()
也是個io輸出
為什麼不用打System.out.flush()
就可以直接看到結果

這是因為有些io類可以設定auto flush(自動)
System的out是個PrintStrem物件
在api說明中有寫道:

Optionally, a PrintStream can be created so as to flush automatically; this means that the flush method is automatically invoked after a byte array is written, one of the println methods is invoked, or a newline character or byte ('\n') is written.

所以上完廁所
如果沒有自動沖水裝置
別忘了要自己手動沖水(flush!)

2011年6月22日 星期三

測試時的怪事

利用ECLIPSE當IDE
TOMCAT當WEB CONTAINER

要在本機測試一個JSP網頁是否正常
用FIRE FOX去連
怎樣就是會出錯
而且我有再該JSP裡插旗子
照理說旗子應該會顯示
可就是沒有

然後改用IE去連
好一點會出現旗子了
可是還是無法正常登入

然後我沒有做任何事
再用IE連一次
就正常
接著用FIRE FOX連
也是正常

WHY?
我什麼事都沒做
就自己好了??
這樣的例子我遇過四, 五次了
明明看起來就對
可是出來結果就不是這樣
最後一樣沒做任何事
他就自己好了....

怪事
我想這應該是
在ECLIPSE裡
去建立一個WEB CONTAINER執行環境
才會碰到的問題

2011年6月21日 星期二

base64

什麼是base64 <-我一直很疑惑
今天上網查了一下
有以下幾點

1.是一種編碼方式. 將輸入的字串或位元, 以3個bytes換成4個6bits方式編碼.
編譯成純文字的碼. 會叫base64, 是因為編碼結果只會有a-z, A-Z, 0-9外加兩個字元.
編譯出的每一個代碼, 只會在這64個字元裡面,  故名base64.(以上是我猜的...)
編碼詳情可以上google或維基百科查詢.
例如:I am a good man.
以base64編碼方式加以編碼後的結果:SSBhbSBhIGdvb2QgbWFuLg==
2.因為是一種編碼方式, 所以多少有加密的功能. 可是這種加密不安全, 只能防君子. 因為不是很安全地加密, 所以編碼速度很快.
3.為什麼會有base64的出生?..........是因為有些網路傳輸協定, 只允許以ASCII當做內文, 來傳遞資料. 如果你有個檔案, 比如說美女照片, 想要用電子郵件寄給別人, 那就是走SMTP協定, 此協定只能用ASCII來傳遞, 所以必須先將該照片的位元組, 例如010101010100101010101....編碼成純文字, 變成:AAaGBdGHE130.....這是舉例. 才能用SMTP傳出去.
4.網路上有提供base64編碼與解碼的網站
5.那麼HTTP也是純文字傳遞嗎? 我以前都認為是, 可後來看到這篇文章, 才知道原來HTTP也可直接傳位元組哩~所以在http上傳檔, 不一定非得先將二進位檔進行base64編碼才行. 但如果情況是, 你利用http傳給別人一份xml文件, 且想要在該份xml文件中, "夾帶"檔案, 就非得先將檔案以base64編碼後, 再將編碼後的結果, 貼到xml文件裡. 比如以下xml文件:
<傳送資料>
    <檔案內容>
    PGgxPrS/pHCzvaxPpGqr0630sNUhPC9oMT4=
    </檔案內容>
</傳送資料>

6.經過base64編碼後, 輸出的東西會比輸入的東西大上35%, 約莫三分之一左右. 這也是為什麼, 你要記東西給別人, 上傳6MB但上傳完卻顯示為8MB. 會稍微大一點.

總結:base64是一種編碼方式, 可以將二進位或文字資料, 轉變成文字的資料.(你或許會疑惑, 將文字資料轉成文字資料? 沒有錯, 看看維基百科的例子, Man編碼後, 會變成TWFu. 他本來就是文字, 本來就可以用SMTP等協定傳輸, 編碼後只是變成另一個文字. 答:可以做點不是很安全的加密功能囉, 例如這個網站舉例你要傳情書的話...起碼被情敵攔截會看不懂..). base64的編碼原理不複雜, 所以編碼速度快, 安全性低. base64的誕生是為了在純文字協定(如SMTP)下, 仍能傳輸檔案(如一個美女照片, 就說是Hebe好了, 如何?)

在html中顯示xml

最近有個需求
需要在html中顯示xml的標籤
例如<element></element>

可是瀏覽器會自動把.html裡面
所有<>都解釋為標籤
然後會因為看不懂該標籤函意
而什麼都不顯示

有幾種方法
1.跳脫字元:將<換成&lt, >換成&gt.
範例:按右鍵看看本頁面的原始檔, 就是利用跳脫字元顯示<.
2.用innerText屬性.
例如:
<body>
<span id="abc">
</span>
</body>
<script>
var abc = document.getElementById("abc");
abc.innerText="<element>Hello!</element>";
</script>
innerText屬性值將不會被看瀏覽器解譯

(另一個innerHTML就會被瀏覽器解譯)
3.表單的文字輸入方框<textarea></textarea>之中的文字, 也不會被瀏覽器解譯.

2011年6月13日 星期一

js的onSumbit事件

我很少用到onSumbit事件
一般來說, 表單按下送出按鈕後
會引發onClick事件,
然後把事情都在這處理完

如果說有需要用到onSumbit事件
那事件發生順序如何呢?
用以下jsp測試:

<html>
<body>
<%
if(request.getParameter("name")!=null && !request.getParameter("name").equals("")){
%>
<script>
alert("The form has been submitted!");
</script>
<%
}
%>
<script>
function doIt(){
 alert("Sumbit!");
}
</script>
<form method="post" onSubmit="doIt()">
<input type="submit" onClick="alert('Click!')" value="Test">
<input type="hidden" value="abc" name="name">
</form>
</body>
</html>


結果如下:
Click!
Sumbit!
The form has been submitted!

2011年6月10日 星期五

Tomcat中欲更動webapps目錄底下的war檔時, 請先停止Tomcat

Tomcat安裝目錄\webapps
是Web Application放置的地方
你可以放war檔(其實就是zip檔)在這,
Tomcat啟動時,
會自動解壓縮成一個資料夾,
此資料夾名稱, 就是war檔的檔名
或者
也可以直接在webapps底下放沒有壓縮的整個資料夾
兩種方式都可以在Tomcat安裝你的Web Application

當Tomcat啟動時
你可以更動Web Application資料夾底下的檔案
比如jsp,
結果會馬上反映出來
因為Web Container在使用者要求此一jsp時
會發現該檔已被更新過
從頭開始把jsp轉成servlet->編譯->載入->初始->開始服務
但是如果是web.xml等設定檔
你一定要重啟Tomcat才會有動作
這點在Apache Tomcat的Document裡有提到

那如果是war檔呢
要更動war檔前
最好先停止Tomcat
看看這篇

2011年6月9日 星期四

eclipse: 一個case就一個工作區

今天想到
如果手上有兩個以上的case在做
最好一個case就一個工作區
(一個case底下可能會有一至多個web application)

將不同case都放在同一個工作區
除了會造成資料混亂外
還有就是啟動Tomcat時
會多載入其它不必要的web application
造成啟動速度緩慢...

2011年6月8日 星期三

java的Package觀念

以前讀過某本java教科書上說
package觀念對於初學者而言不容易懂
今天想試試看以下例子:

有兩個class, Flight和Boeing:

package Test123;
public class Flight{
 public static void main(String[] args){
  Boeing b = new Boeing();
 }
}


package Test123;
class Boeing{
}


這兩個class都位於Test123這個package底下.
目錄結構如下:
c:\jpractice\Test123\
以下測試各種情況, 看如何能順利編譯:

a.在c:\jpractice\Test123\執行javac Flight.java
結果:失敗..
Flight.java:5: cannot find symbol
symbol  : class Boeing
location: class Test123.Flight
                Boeing b = new Boeing();
                ^
Flight.java:5: cannot find symbol
symbol  : class Boeing
location: class Test123.Flight
                Boeing b = new Boeing();
                               ^
2 errors

出現以上錯誤訊息
這是因為在class Flight中,
沒有特別指定要import任何其它package
所以預設就是跟Flight一樣的package->Test123!
但此時因為javac的執行起始點是在c:\jpractice\Test123\
所以javac會嘗試從當前目錄
再一次尋找Test123
但是這個目錄c:\jpractice\Test123\Test123並不存在
所以丟出找不到class Boeing的錯誤

b.在c:\jpractice 執行javac ./Test123/Flight.java
結果: 成功!
把javac的執行目錄往上提了一層
所以會從c:\jpracitce開始去尋找 Test123.Boeing
c:\jpractice\Test123\Boeing.java <-真的有這個檔

總結:
1.尋找class的方式, 預設從本支程式的package開始找, 再從import宣告處的package由上往下找. 所以如果需要用到的其它類別, 跟目前程式在同一package, 可以偷懶不加import.
2.預設的尋找起點, 是從javac的執行目錄開始.

Report problems as you type

eclipse這類IDE編輯器
好處在於你一邊打程式碼
一邊它就會幫你檢查對不對
這是超級方便的功能
讓你可以隨時做修正
下圖就是它的作用
類別System誤寫成system
不用編譯
IDE會自己抓出錯誤







要不然用一般的文字編輯器的話
可能你一股腦兒地寫了1000行的程式
你自信滿滿認為一定不會錯
最後很高興要用javac指令去編譯
結果卻令人沮喪地出現了一堆錯誤

這個"邊打邊檢查"的功能, 就叫它: Report problems as you type 吧!
在eclipse中預設為開啟
如果你想把它關掉
或者哪天發現怎麼不會自己檢查
請按照下面兩張圖
去把它關閉或開啟

















2011年6月6日 星期一

Oracle資料庫的ROW_ID欄位

Oracle資料庫
和Microsoft SQL Server資料庫
或IBM DB2資料庫
在資料表上多了一個預設的欄位
叫作ROWID

在TOAD for Oracle的產品中
預設是看不到這個欄位
必須要勾選開啟, 如下圖的紅框標示處所示

















據某本Oracle參考書上說,
這是為了方便管理資料
可是他沒有講實際方便管理的例子

ROWID長得像是這樣
AAA9soAAJAAABc4AAA
每新增一筆資料
就自動獲得一個惟一的ROWID

我在目前維護的程式中
看到有人是將ROWID當作刪除或更新的主鍵
這樣真的還滿方便
它的作法是查詢資料時一併查詢ROWID
然後將ROWID寫進HTML中
送出表單時只要送出ROWID
則Server端就知道要砍哪一筆資料

要不就必須送出該資料的全部主鍵
然後Server端再一個個加以設定
在單筆資料情況下還好, 就直接取表單的值
如果是多筆資料的情況
還多了 一個動作:
判別欲異動的資料是第幾筆
接著在表單參數的陣列中
取出該筆資料的值
例如:
String[] names = request.getParameterValues();
String name = names[欲異動資料的index];

而如果有了ROWID幫忙
在多筆資料情況下
也是只要送出ROWID即可解決問題

由以上例子可以看出
ROWID可以方便資料的存取

但是我會想打這篇文章
是因為有一次為了測試
我砍了Oracle資料庫中的一筆資料
然後同事說不能這樣做
因為它有ROWID
可能會影響到其它資料??

真的會嗎?

於是我去看目前維護的程式中
資料庫裡, 沒有人用ROWID當做外鍵
程式中, 也沒有人把ROWID的值寫死在程式裡
也沒有這樣的SQL句子: SELECT * FROM EXAMPLE_TABLE WHERE ROWID = ?

所以我砍了一筆資料
並不會害資料表的關聯性消失
也不會造成查不到資料的情況
可以安心刪除, 再新增回來
就好像什麼事都沒發生過一樣

總結:
1.ROWID可以方便資料表存取, 即當作UPDATE或DELETE句子的條件
2.ROWID不可以用來當做外鍵, 亦不可寫死在程式中. 因為你總不能期待資料永遠會在同個位置等你, 它可能會被刪除, 然後再新增.
3.ROWID還是可以當作SELECT句子的條件, 只要你是先用其它主鍵查過一遍, 想要再查一次比較詳細的資料時, 因為你懶不想打太多主鍵, 就可以用ROWID. 我以為這不是好的作法, 因為可能你在前一次查詢後, 資料表做了某些異動, 資料還是在, 可是ROWID卻換了一個. 接著第二次查詢就會失敗.

總結後的總結:
1.請把ROWID只拿來當作UPDATE或DELETE句子的條件.
2.不要將ROWID寫死在任何地方, 比如其他資料表, 或者程式裡面. ROWID應該永遠是取用來自SELECT查詢所得的結果.