February 2008 - Posts

KB-SQL 2000 BULK INSERT Error

今天在一台SQL 2000上做BULK INSERT,語法是

BULK INSERT PicLibrary
FROM 'C:\Output\PicInfo.txt'
WITH
(
    BATCHSIZE = 1000,
    FIELDTERMINATOR = '\t',
    ROWTERMINATOR = '\n',
    TABLOCK
)

我之前在SQL 2005上做過同樣的事,但這回在SQL 2000上卻一直爆出錯誤:

訊息 4866,層級 16,狀態 1,行 10 大量載入失敗,資料檔案的資料行對於資料列1,資料行4而言太長。請確定已指定正確的欄位結束字元和資料列結束字元。
(英文: The bulk load failed. The column is too long in the data file for row 1, column 4. Verify that the field terminator and row terminator are specified correctly.)
訊息 7399,層級 16,狀態 1,行 10 OLEDB Provider 'MyServer'報告了錯誤。提供者並未給予任何關於錯誤的資訊。 OLEDB錯誤追蹤[OLEDB Provider 'MyServer' IRowset::GetNextRows returned 0x80004005: 提供者並未給予任何關於錯誤的資訊。]。
(英文: The OLE DB provider "BlBULK" reported an error. The provider did not give any information about the error.)

反覆嘗試,耗了好幾個小時。最後Google到這篇討論,情境跟我的很像,都是用Import Data會成功,直接在Query Analyzer BULK INSERT卻出錯,但差別在於我用的是SQL 2000,該案例則是在SQL 2005上,因此文中的Hotfix無濟於事。

又看了幾篇文章,有人提到\n .vs. \r\n的問題,我試著將欄分隔符號改為",",列分隔符號改為";",改用後就一次OK!!

我認為這是SQL 2000的Bug,不過SQL 2008都快出來了,不大想花時間跟這隻老恐龍拼命,就此打住。把我的經驗整理如下:

【情境】

  1. BULK INSERT時遇到上述錯誤
  2. 同一檔案用Import Data匯入卻無誤
  3. 使用了'\t'分欄,'\r\n'或'\n'分列

【解決方式】

將\t, \n換成其他符號。

PS: SQL 2005 User則可試試
FIX: 當您在 Microsoft SQL Server 2005 執行 BULK INSERT 陳述式錯誤訊息: " The 大量載入失敗。 資料行是針對 <n>, <n> 個資料行資料列將資料檔中的 "blah" 太長
http://support.microsoft.com/kb/942660/zh-tw

My ASP.NET AJAX Client Library Tips

講到ASP.NET AJAX,很多人想到是拉個UpdatePanel,完全不必搞懂Javascript,就可以寫出AJAX的東東。事實上,ASP.NET AJAX除了讓大家可以用懶人法寫AJAX之外,在Javascript的Support上也提供了不少強化,這點之前就曾提過

最近又重回Web開發的工作,在策略上重用ASP.NET AJAX Client Library,也陸續學會不少小技巧,以下是幾個我覺得不錯的,整理出來給大家參考:

  1. $get("elementName"):
    這是一定要的啦,可以取代document.getElementById("elementName"),省打不少字,還可避免一不留神寫出document.all("elementName")這種IE專屬語法,被FireFox User臭罵。
  2. $addHandler(elementName, "click", clickEventFunction)以及$removeHandler(elementName, eventFunction):
    不必再花時間去找FireFox掛事件的方法囉,支援同時加掛多個事件函數在同一事件上的功能。 至於eventFunction會得到一個evt參數,evt.target在相當於event.srcElement,且是跨Browser可用。以下是個簡單的例子:
    <input type="button" id="btn" value="Click!" />
    <script type="text/javascript">
    $addHandler($get("btn"), "click", btnClick);
    function btnClick(evt) 
    {
        alert(evt.target.value);
    }
    </script>
    延伸閱讀:使用教學
  3. Array.enqueue(arrayVariable, object)Array.dequeue(arrayVariable):
    原本打算自己寫個Queue的,沒想到AJAX Client Library裡就有現成的可用。以下是簡單的範例:
    <script type="text/javascript">
    var ary = [ "1", "2", "3" ];
    Array.enqueue(ary, "4");
    Array.enqueue(ary, "5");
    while (ary.length > 0) {
        alert(Array.dequeue(ary));
    }
    </script>
  4. Number.format & Number.parseInvariant:
    Number.format()主要用來轉成#,##0.00的格式,但它比.NET的Format函數陽春許多, Number.parseInvariant則可以用將具有千位號的文字轉回數字。 格式化字串分兩部分,第一個字元代表格式,之後接著的是小數點的位數,例如: num.format("n2")表示以千位逗點號分隔,並留兩位小數。可用的格式如下:
    • p: 百分比字串(e.g.: -1,234.56 %)
    • d: 無逗點分隔號字串(e.g.: -1234.56)
    • c: 金額格式,負數用括號夾(e.g.: (¤1,234.56))
    • n: 逗點分隔字串 (e.g.: -1,234.56)
      延伸閱讀: 函數說明

【PS】

在Post這篇的同時,向大家報告一個消息:

我移情別戀了!!

要搞定Javascript,ASP.NET AJAX Client Library已不是我的最愛了。最近我與另一位美人jQuery陷入瘋狂熱戀中! 這位美人究竟有何魔力,讓原本心如止水的中年人再度熱血沸騰?? 就留待近期陸續揭曉吧!

【茶包射手專欄】ADO.NET開啟Excel傳回未知錯誤0x80004005

【問題】

使用"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Temp\SomeExcel.xls;Extended Properties='Excel 8.0;HDR=Yes;'"的OleDbConnection方式開啟Excel檔案,在本機執行正常,在Server上卻得到0x80004005錯誤,訊息為"未知的錯誤"

【排除步驟】

  1. 檢查Server上的目錄,該檔案確實存在。
  2. 由於0x800004005是典型的Access Denied訊息,但使用Process Monitor監看,卻沒有發現存取檔案/Registry被拒的記錄。
  3. Google了一下,沒找到完全相符的情境,但有篇文章提到了system32/msexcl40.dll,它是Jet 4.0的相關檔案,註冊失效時會傳回"Could not find installable ISAM"訊息,與本次遇到的訊息並不同,但依該文作者的經驗,雖然訊息不同,但試了有效。所以... 我當然要試試,又不會少塊肉。
  4. regsvr32 msexcl40.dll後再試,仍然無效。但IISRESET後再試則成功。

由於先後做了regsvr32 msexcel40.dll及IISREST後修復了這個問題,無法確定何者是關鍵(或者兩者都為必須)。為了驗證,regsvr32 /u msexcl40.dll後再試,會得到Could not find installable ISAM,亦非原來的錯誤訊息。

問題解了,但真實原因未能釐清。總之,有相同情境的朋友,不坊試試以上步驟,如有不同發現,歡迎留言回饋給我。

TIPS-SELECT DISTINCT IN ADO.NET

ADO.NET裡的Select()提供部分類似SQL的查詢功能,例如: 簡化版的LIKE(%只能放前後,不能擺中間),但有些基本的SQL語法還是做不到的,例如: DISTINCT。

微軟曾針對ADO.NET 1.1提出過解決方案KB,但所謂的DataSetHelper,複雜度看來跟自己DIY沒差多少,只差在是MS提出的官方範例。所幸,在ADO.NET 2.0裡,DataView.ToTable()終於將DISTINCT的功能歸為內建,我們可以直接匯出一個只包含指定欄位的DataTable,而且可以決定是否DISTINCT。

廢話不多說,請看示範:

static void testDistinct()
{
    DataTable t = new DataTable();
    t.Columns.Add("Category", typeof(string));
    t.Columns.Add("Product", typeof(string));
    t.Columns.Add("Version", typeof(string));
    t.Rows.Add("OS", "Windows", "2003");
    t.Rows.Add("OS", "Windows", "Vista");
    t.Rows.Add("Application", "Office", "XP");
    t.Rows.Add("Application", "Office", "2003");
    t.Rows.Add("Application", "Project", "2003");
    t.Rows.Add("Database", "SQL", "2000");
    t.Rows.Add("Database", "SQL", "2005");
    t.Rows.Add("Database", "SQL", "2000"); //Duplicated
    Console.WriteLine("Original Rows Count = "
        + t.Rows.Count.ToString());
    Console.WriteLine("DISTINCT Category Rows Count = " + t.DefaultView
        .ToTable(true, "Category").Rows.Count.ToString());
    Console.WriteLine("DISTINCT Category, Product Rows Count = " + t.DefaultView
        .ToTable(true, "Category", "Product").Rows.Count.ToString());
    Console.WriteLine("DISTINCT Category, Product, Version Rows Count = " + t.DefaultView
        .ToTable(true, "Category", "Product", "Version").Rows.Count.ToString());
}

執行結果如下:

Original Rows Count = 8
DISTINCT Category Rows Count = 3
DISTINCT Category, Product Rows Count = 4
DISTINCT Category, Product, Version Rows Count = 7

那LINQ呢?

LINQ有個Distionct()函數可以套用,但比起DataView.ToTable()沒省什麼功夫。當然,這種小把戲並非LINQ精華所在,日後再找實例介紹LINQ的"特異功能"。

//...省略...
    t.Rows.Add("Database", "SQL", "2005");
    t.Rows.Add("Database", "SQL", "2000"); //Duplicated
 
    var rows = from row in t.AsEnumerable()
               select new
               {
                   Category = row.Field<string>("Category"),
                   Product = row.Field<string>("Product")
               };
    Console.WriteLine("Orig RowCount=" + (rows).Count());
    Console.WriteLine("Distinct RowCount=" + (rows).Distinct().Count());
TIPS-當Oracle Client遇上高精確度數字

同事遇到的問題。

用PL/SQL UPDATE資料表,設定一個NUMBER(30,10)欄位為2425251.6261653065(整數7位,小數10位,共17位),再SELECT時卻被四捨五入過,與原先的值不同。同事試了PL/SQL Developer與Toad都發生位數被偷工減料的情形,例如: Toad的查詢結果如下,最後的53065硬生生變成531。

我試了手上的Aqua Data Studio(4.7版是Free的,幾乎可頂替Toad)及QueryExpress(非常輕巧的Query工具,可以想成可查ORACLE的精簡版Query Analyzer),則沒發生精確度遺失的問題,因此首先懷疑問題出在Client Tool上。

看Toad的結果,顯示出來的部分為15位,15位!? 看起來像是double data type的精確度上限,加上我找不到可以改變顯示精確度的選項。因此大膽推測,可能Toad在開發時,只用double來處理查詢結果,而非decimal(先前有篇KB提過),若是如此,此問題就無解了。

另外發現一件有趣的事。心想外來的Client有問題,隨便也試了SQLPus,乍看之下更慘! 只出了.63兩位小數。

由於只有兩位小數實在太誇張,我猜應該有設定可以修改,Google後果然找到:

col colName format 99999.99999

【茶包射手專欄】window.open時發生"類別未登錄"錯誤

使用者反應他的IE只要遇到Javascript window.open,就會跳出"類別未登錄"的錯誤訊息!

推測"類別未登錄"的英文原文應為"Class not registered"(這就是為什麼我鍾愛英文版OS的原因,可以不必玩中翻英猜猜看),用window.open加class not registered去Google大廟求一下籤,Bingo!

微軟有篇KB 306831,100%符合這次遇到的情境,照著KB的說明regsvr32 ulrmonurlmon.dll,藥到病除。

花不到兩分鐘就解決了問題,但大部份是Google的功勞,我禁不著要說:

Without Google, I am nothing!

但也不免開始擔心,如果有一天Google倒了,就是我該回鄉種田的日子,呃... 關於種田的方法... 快來Google一下! orz

VS 2008 Hot-Fix Roll-Up

在Scott Gu的Blog看到VS2008出了Hotfix Roll-up(Roll-up差不多就像Hotfix懶人包,可省去得逐一安裝的麻煩)的消息,看了一下它所修理的Bug,主要都是集中在HTML編輯相關的功能:

HTML Source view performance

  • Source editor freezes for a few seconds when typing in a page with a custom control that has more than two levels of sub-properties.
  • “View Code” right-click context menu command takes a long time to appear with web application projects.
  • Visual Studio has very slow behavior when opening large HTML documents.
  • Visual Studio has responsiveness issues when working with big HTML files with certain markup.
  • The Tab/Shift-Tab (Indent/Un-indent) operation is slow with large HTML selections.

Design view performance

  • Slow typing in design view with certain page markup configurations.

HTML editing

  • Quotes are not inserted after Class or CssClass attribute even when the option is enabled.
  • Visual Studio crashes when ServiceReference element points back to the current web page.

JavaScript editing

  • When opening a JavaScript file, colorization of the client script is sometimes delayed several seconds.
  • JavaScript IntelliSense does not work if an empty string property is encountered before the current line of editing.
  • JavaScript IntelliSense does not work when jQuery is used.

Web Site build performance

  • Build is very slow when Bin folder contains large number of assemblies and .refresh files with web-site projects.

從VS 2005切換到VS 2008後,一直覺得Web Design View點選不同的Control時,Properties Window的反應很慢,常要等個幾秒才會切換到新點選的Control。在Souce View編輯HTML Tag時,也常有拖拍的感覺,總之整體操作過程很不順暢。害我一度以為才買一年的Core 2 Duo E6400 CPU已經玩不起VS 2008這個大傢伙,差點興起掏錢升級的衝動(另一個催敗的理由是現在的RAM真是便宜到不行,好想把機器升到8G)。

看來有此感受的不只我一個,這次蒐集的Hot-Fix,幾乎都在解決IDE回應緩慢的問題(我特別跟"慢"有關的部分都標了出來,呵呵),聽到這個消息,當然就是義無反顧、亳不猶豫,直接下載安裝。

有需要的朋友可到此下載(需要使用Microsoft Passport登入)

Update @ 2008-02-22
經網友James, Eric反應,我再仔細看了該文章的回文,發現該Patch並非Scott原先以為的跨語系,而只適用英文與日文版,裝中文版的朋友要再等等。

Update 2008-03-28 該Hotfix已支援中文囉, 謝謝網友James提供情資

 

發現病毒兩枚

接獲兩封可疑電子郵件通報。

第一封信件(2/4)標題為"我被騙了...",內文如下:

我被騙了...昨天被騙了1000元..心情真的是很幹!!騎車回家..都在狂哭...很氣自己氣自己怎會熊熊就借錢給對方..什麼都沒留就借...心情超糟的...還好我還有拍下她的相片...>"

附件為"騙子相片.zip",內含256,523 bytes的"騙子相片.cmd"檔案

第二封信(2/5)標題為"新年好",內文如下:

新年到了給你準備了一份禮物希望你笑口常開
Edger

附件為"新年禮物",內含270,404 bytes的"新年禮物.cmd"檔案

很巧二者手法相似,都用ZIP包了CMD檔,是病毒的成份居多。第一封說要給相片,裡面附的卻是CMD,病毒作者顯然不夠用心;第二封信有點意思,因為署名Edger真的是寄信者的英文名字,收信人在第一時間還真以為是本人發出的,差點中計。它不知用什麼技巧取得發信者署名,讓我有點好奇,二封信都來自@yahoo.com.tw,也都有Yahoo免費信箱強制加上的"Yahoo!奇摩迷你筆,英文單字一點就翻"廣告,看來不像是透過Outlook管道取得收信人清單及寄發,我懷疑是竊取或騙取Yahoo信箱密碼後發動的攻擊。

Google了一下,"騙子相片"病毒在去年12月下旬就有傳出風聲(信件用字完全相同,因此確認手上這件為毒),至於"新年禮物"則查無所獲。但我安裝的AVG Anti-Virus倒檢測出"新年禮物.cmd"中包含了KLONE.H這個後門程式。由以上線索,確認二者應是病毒無誤,殺!!!

【提醒】郵件附檔ZIP裡內含.exe, .com, .cmd, .pif, .scr,是病毒的機率很高,如果不執行不會少塊肉,就別開啟吧!

Several Javascript Howto Tips

這陣子在狂打Javascript巷戰,以下是我整理出來的幾則Howto Tips,如果有人知道其他的解法也歡迎提出來跟大家分享。

  1. 檢查物件是否被隱藏
    【情境】
    <input>被包在<tr><td>中,當<tr style="display:none;">,我希望能用Javascript檢測出<input>處於不顯示狀態。
    【解法】
    利用document.getElementById("inputName").offsetWidth,被隱藏時數值為0。注意,要網頁完全載入後才有效,建議放在window.onload事件之後。
  2. 取得目前焦點所在的元素
    【情境】
    <input> <select>可以利用tabindex設定焦點順序,我想知道目前焦點停在哪一個欄位上?
    【解法】
    IE提供document.activeElement屬性,一步到位! 注意: IE Only, Firefox無此屬性。
  3. 保存網頁元素自訂的數值或設定
    【情境】
    假設網頁上有十個<input>數字輸入欄位,每個有其上下限,且會因使用者的選取而動態改變,要怎麼保存? 另設20個<input type=hidden>嗎?
    【解法】
    善用HTML DOM中Attribute可以任意設定的特性,document.getElementById("inputName").MyAttributeName = theValue; 就可以了。
  4. 四捨五入到小數第n位
    【情境】
    講到四捨五入,一般人想到的是Math.round,但它永遠取到整數,我要Round到小數第三位怎麼辦? Math.round(n*1000) / 1000嗎?
    【解法】
    別再耍笨了(鳴~~~ 我笨很久了),數值類別有個Number.toFixed(d),可以直接取到小數第d位,例如: var num = 1.249; alert(num.toFixed(2));
  5. 可有可無的自訂函數
    【情境】
    寫了一個共用js,引用它的網頁可以視需要加上客製的自訂函數,並由js中觸發,但也可以不宣告。在js中要如何做到檢查若函數存在就Call,沒定義就算了?
    【解法】
    if (typeof(CustFunction) == "function") CustFunction();
  6. 函數的參數個數不固定
    【情境】
    在.NET裡有string.Format("...", arg1, arg2, arg3...)這種參數個數不固定的宣告及呼叫法,在Javascript裡要怎麼做?
    【解法】
    函數裡可以用arguments取回參數陣列
    function dynaParam(s) 
    {
        alert("s = " + s);
        for (var i=1; i<arguments.length; i++) 
            alert("arg" + i + " = " + arguments[i]);
    }
    dynaParam("Only One", "P1");
    dynaParam("Try Three", "P1", "P2", "P3");

Search

Go

<February 2008>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
2425262728291
2345678
 
RSS
【工商服務】


BlogLook Score and Rank

Syndication