2012年7月14日 星期六

SQL - 中文長度的問題、LEN、DATALENGTH

因為轉檔的關係,有時候需要把名稱的欄位簡短後塞到簡稱的欄位去,
不過常常都會出現的狀況就是....



即便我已經用了 SUBSTRING 也是一樣!
但是我用 LEN 看一下 SUBSTRING 之後的長度明明就沒有超過呀?
後來上網查了一下有關 LEN 中文長度的搜尋,
然後找到了一個新的函數 DATALENGTH ,
大致上 LEN 的算法是中文算長度1、英文也算長度1,
然後 DATALENGTH 的算法是中文長度2、英文長度1,
中間的差異大概就是一個算字元數,一個算BYTE數吧?
所以當我寫出下面 SQL 的時候,算出來的數字是完全不一樣的!

LEN(name_ch) AS "LEN", DATALENGTH(name_ch) AS "DATALENGTH"



於是乎我就想說那 SUBSTRING 有沒有類似的函數可以用呢?
很遺憾的是我沒有找到,也許 SQL SERVER 2020 會支援吧?
所以當我寫下面那樣的話還是會出現二進位截斷的問題,

SUBSTRING(name_ch, 1, 10)

最後我只好改用 CONVERT 的方式來寫,如下:

CONVERT(VARCHAR(10), name_ch)

如果大家知道 SUBSTRING 有類似 DATALENGTH 的函式可以用的話麻煩通知我一下嘿!

2012年7月9日 星期一

如何在 Linq 裡面使用類似 SQL 的 IN 的語法?

需求是這樣的,使用者會輸入一個日期區間、並挑選業務員,
我在查詢的畫面會【列出所有的主檔資料】讓使用者勾選要列印哪一個主檔的資料,
但是當使用者按下一個【filter】的按鈕之後,
我會過濾出那個業務員有業績的資料,
然後取代剛剛那個【列出所有的主檔資料】的畫面讓使用者勾選。
以前的作法會大概會是過濾的時候順便 JOIN 主檔的資料,
然後列在主檔的畫面讓使用者勾選。

不過我在作的時候突然想到,我前端都已經有全部的主檔資料了,
為什麼還要再 JOIN 一次呢?
為什麼還要再增加那台五年前很強的主機的負擔呢?

所以我就想說有沒有辦法可以在前端作 JOIN 或是用 IN 的方式呢?
摸索了一下, Linq 沒有 IN 可以用,不過找到了另一個方式可以代替,
在我還沒有找到其他方式之前就先這麼辦吧!

測試的畫面大概長這樣!最左邊列出所有的產品,中間列出指定業務員有交易過的產品。


當業務員選擇 Frankie 的時候,則只列出 Frankie 有交易過的產品資料。
所以就不是全部的產品了!


選擇 Mork 的時候,顯示出有交易過的產品又更少了!


程式碼如下:
  1. string sales = leSales.EditValue.ToString();
  2.  
  3. DataTable filterList = DBUtility.GetDataFromDB("deal",
  4.     string.Format("SELECT DISTINCT product FROM deal WHERE sales = '{0}'", sales));
  5.  
  6. var q = filterList.AsEnumerable()
  7.     .Select(f => f.FieldByName("product").AsString);
  8. var filterResult = allProducts.AsEnumerable()
  9.     .Where(r => q.Contains(r.FieldByName("code").AsString));
  10.  
  11. DataTable filterProducts = null;
  12. if (filterResult.Count() > 0) filterProducts = filterResult.CopyToDataTable();
  13. grdFilter.DataSource = filterProducts;

這邊有用 DevExpress 的元件,所以有些物件的屬性不懂就跳過吧!

1.先取得業務員代號。

3.取得業務員曾交易過的產品代號。

6.將交易過的產品存到 q 裡面。

8.這個時候就可以用 q.Contains 當 SQL IN 來用了!

13.最後將過濾過的資料集塞回去 Grid 就可以了!