2011年7月19日 星期二

[ASP.NET] 解決Oracle IN clause 超過1000個參數

不管在SQL Plus或其他Tool,甚至ASP.NET中,只要出現以下錯誤訊息:
ORA-01795 maximum number of expressions in a list is 1000

不用懷疑,就是你的SQL中,IN的參數超過1000個了。

最快的解決方法有兩種:
1. OR
2. Union

OR Sample如下:
select * from TestTable where ID in (1,2,3,4,...,1000)
union all
select * from TestTable where ID in (1001,1002,...)

Union Sample如下:
select * from TestTable where ID in (1,2,3,4,...,1000) or ID in (1001,1002,...,2000)


在ASP.NET中,Sample如下(使用OR):

strSQL = "select * from TestTable where {0} ";
int limitCount = 900;
                double dLoopCycle = (IDs.Count / limitCount);
                int loopCycle = Convert.ToInt32(Math.Ceiling(dLoopCycle));
                loopCycle = loopCycle == 0 ? 1 : loopCycle;

                string strIDs = string.Empty;
                string strTempSQL = string.Empty;
                //more than 1000 parameter would raise error
                for (int i = 0; i < loopCycle; i++)
                {
                    int rangeIndex = (i * limitCount);
                    List tempList = IDs.GetRange(rangeIndex, Math.Min(limitCount, IDs.Count - rangeIndex));

                    strIDs = string.Join(",", tempList.ToArray());
                    if (i == 0)
                        strTempSQL = string.Format("ID in ({0})", strIDs);
                    else
                        strTempSQL += string.Format("or ID in ({0}) ", strIDs);
                }

strSQL = string.Format(strSQL, strTempSQL);

[ASP.NET] 解決Linq Contain 參數超過2100的錯誤

在Linq使用Contain時,必須注意參數的個數,限制為2100為上限,錯誤訊息如下:
The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Too many parameters were provided in this RPC request. The maximum is 2100.

表示你踩到IN Parameter最多2100個的限制。

以下為我的解決之道:

double dLoopCycle = (containList.Count / 2000);
int loopCycle = Convert.ToInt32(Math.Ceiling(dLoopCycle));
loopCycle = loopCycle == 0 ? 1 : loopCycle;

List result = new List();
List tempResult = new List();
 //more than 2100 parameter would raise error
 for (int i = 0; i < loopCycle; i++)
 {
     int rangeIndex = (i * 2000);
     var tempList = containList.GetRange(rangeIndex, Math.Min(2000, containList.Count - rangeIndex));

     tempResult = (from r in DataContext.Test where tempList.Contain(r.ID) select r).ToList();
     result = result.Union(tempResult );
}


另外oracle的SQL也有IN Parameter不得超過1000個的限制,這個就會在後續的文章分享我的解決方式囉~~

[ASP.NET] 解決Oracle IN clause 超過1000個參數

2011年7月13日 星期三

[ASP.NET] Nlog:記Log必備的好東西

要瞭解Nlog初步認識一定必須先拜讀保哥的的大作,介紹好用函式庫:NLog - Advanced .NET Logging

當然師傅引進門,詳細的設定就是要靠自己啦...
就如保哥所說的,install之後就有完整的API文件跟範例,
其實不外乎只要把 Nlog.config 設定好,就完成大半的工作了!!!

我的設定主要:
1.存成File的部分,七天回滾一次,自動刪除過期的Log,讓Disk不會被擠爆。
2.寄出Mail的部分,集滿五個拉環才寄出,不會一個Message寄發信,讓我的信箱不被塞爆。

首先附上我的Nlog.config



    
        
        
        
            
        
    

    
        
        
    



2010年12月20日 星期一

[Oracle]Update data from another Table

Web系統不免會有由Excel Upload的資料去更新資料表的需求,當然如果Excel資料一筆一筆的對Table做更新是不符合效益,這將造成對database的transaction過多,而且因為目前需Update的資料表資料量相當大,所以採用的方法如下:
1.Insert data in db temp table from excel data
2.update data from temp table

上述的從Temp table取用資料Update資料表,就切入本篇的主題,可用的方法有三:
1.Update by sub-query
2.Update table view
3.Merge

方法一:
UPDATE bigTable b
   SET (col1,col2,col3) = (
       SELECT t.col1,t.col2,t.col3
         FROM tempTable t
        WHERE b.col = t.col)
where exists(
       SELECT t.col1,t.col2,t.col3
         FROM tempTable t
        WHERE b.col = t.col);
方法二:
UPDATE (
SELECT b.col1 as old_col1,
       b.col2 as old_col2,
       b.col3 as old_col3,
       t.col1 as new_col1,
       t.col2 as new_col2,
       t.col3 as new_col3 
  FROM bigTable b, tempTable t
 WHERE b.col = t.col)
   SET old_col1 = new_col1,
       old_col2 = new_col2,
       old_col3 = new_col3;

方法三:
MERGE INTO bigTable b
 USING (SELECT col1 , col2 , col3 , col
          tempTable t ) t
    ON ( b.col = t.col)
WHEN matched THEN
UPDATE
   SET old_col1 = new_col1,
       old_col2 = new_col2,
       old_col3 = new_col3;

測試結果:
方法一:140 sec
方法二:1 sec
方法三:未測

透過方法二 明顯是效能最佳的解法,但若會被update的bigTable並非符合UK或PK的條件,將會產生"ORA-01779: cannot modify a column which maps to a non-key-preserved table"的錯誤,若你的table不適合建立UK或PK時,可透過hint的方式/*+ BYPASS_UJVC */來忽略UK的檢查。
UPDATE (
SELECT /*+ BYPASS_UJVC */ b.col1 as old_col1,
       b.col2 as old_col2,
       b.col3 as old_col3,
       t.col1 as new_col1,
       t.col2 as new_col2,
       t.col3 as new_col3 
  FROM bigTable b, tempTable t
 WHERE b.col = t.col)
   SET old_col1 = new_col1,
       old_col2 = new_col2,
       old_col3 = new_col3;

參考網址:http://blog.csdn.net/yuhua3272004/archive/2008/08/06/2776121.aspx

2010年11月17日 星期三

[Oracle]處理中文亂碼 -- NLS_LANG設定

開發連結oracle資料庫不可不注意中文的處理問題

首先必須確認DB Server的編碼設定

select userenv('language') from dual;
取得結果為TRADITIONAL_CHINESE.TAIWAN.ZHT16BIG5

接下來就是設定client端的NLS_LANG,只要與DB Server相同,中文顯示就會正確了

1. 開始 -> 執行 -> regedit
2. 找出 HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE
3. NLS_LANG改為TRADITIONAL_CHINESE.TAIWAN.ZHT16BIG5

這樣由這台client連到TRADITIONAL_CHINESE.TAIWAN.ZHT16BIG5 的DB Server中文顯示就會是正確的。

另一個議題,單一client要連結的DB Server有多種NLS_LANG,擔任Web Server的client常有這種狀況!!!

以ASP.NET為例:

public void ReadMyData(string connectionString)
{
    //設定Oracle NLS_LANG,在connect db前設定環境變數
    System.Environment.SetEnvironmentVariable("NLS_LANG", "AMERICAN_AMERICA.ZHT32EUC");
    string queryString = "SELECT OrderID, CustomerID FROM Orders";
    using (OleDbConnection connection = new OleDbConnection(connectionString))
    {
        OleDbCommand command = new OleDbCommand(queryString, connection);
        connection.Open();
        OleDbDataReader reader = command.ExecuteReader();

        while (reader.Read())
        {
            Console.WriteLine(reader.GetInt32(0) + ", " + reader.GetString(1));
        }
        // always call Close when done reading.
        reader.Close();
    }
}


其關鍵就是
System.Environment.SetEnvironmentVariable("NLS_LANG","AMERICAN_AMERICA.ZHT32EUC");
 
針對單一Web Site設定連線到DB NLS_LANG,就可以一勞永逸的解決中文問題,不管程式被Deploy到哪裡,
都不受那台Web Server的NLS_Lang影響。

2010年10月11日 星期一

[ASP.NET]Visual Studio建立N-Tier的Solution

於Visual Studio實現N-Tier,目前將程式分為三層:
1.UI (Web Form)
2.BLL (Bussiness Logic Layer)
3.DAL (Data Access Layer)

要建立起這樣的架構,首先必須建立一個空白專案,我們可用此專案開啟我們的N-Tier全部檔案來檢視。
1.建立空白專案




























 2.建立Client檔案夾,加入Web Application 的Project











3.建立General檔案夾,建立BLL與DAL的Project








4.檢視建立完畢的Solution






















5.各Layer間要加入Reference,這樣就可以把整個Solution關係都拉起來了~
首先,BLL將DAL加入Reference,
接著就是在Web Application加入BLL與DAL。










6.檢視整個Solution加入Reference後的結果










































這樣就大致的把3-Tier切出來了,
透過如此的切法,
DAL主要只負責用來連結資料庫,對資料庫做資料處理。
BLL則是扮演DAL與UI之前的橋樑,對於取出資料庫取出的資料作邏輯處理,回覆資料給UI。
UI則是單純的扮演呼叫BLL與呈現資料,不做邏輯處理與判斷。

2010年6月7日 星期一

[Oracle]箱型圖(BoxPlot)統計值運算

繪製箱型圖顯示一組數據的分散情況,而若從資料庫中的Raw Data,來繪製箱型圖,則需結算出六個必要數值:最大值、最小值、中位數、平均值、Q1下四分位數、Q3下四分位數

以Oracle範例資料庫中的employees資料表為例,計算每個部門的箱型圖數值:


select department_id,
       max(salary) Upper_whisker,
       min(salary) Lower_whisker,
       round(avg(salary),3) Average,
       PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY salary ASC) Q1,
       PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary ASC) Median,
       PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY salary ASC) Q3
  from employees t
 group by department_id