顯示具有 T-SQL 標籤的文章。 顯示所有文章
顯示具有 T-SQL 標籤的文章。 顯示所有文章

2014年6月22日 星期日

一秒看破 樞紐 查詢 SQL PIVOT UNPIVOT LINQ

什麼是樞紐?






......






DB

弄點假資料(手 KEY 就太傻太天真)

查出來這樣

但是 User 要這樣

硬幹吧 男孩 For~For~For~






多想兩分鐘,你可以不必自殺






官方有解 MS SQL 2005 + 都能玩

http://technet.microsoft.com/zh-tw/library/ms177410(v=sql.105).aspx

SELECT <非樞紐資料行>,

    [第一個樞紐資料行] AS <資料行名稱>,

    [第二個樞紐資料行] AS <資料行名稱>,

    ...

    [最後一個樞紐資料行] AS <資料行名稱>

FROM

    (<產生資料的 SELECT 查詢>)

    AS <來源查詢的別名>

PIVOT

(

    <彙總函式>(<要彙總的資料行>)

FOR

[<包含將變成資料行標頭之值的資料行>]

    IN ( [第一個樞紐資料行], [第二個樞紐資料行],

    ... [最後一個樞紐資料行])

) AS <樞紐分析表的別名>

<選擇性的 ORDER BY 子句>;






WTF...






看圖 (那堆 欄位沒法 直接用 SQL 搞 死心吧 只能靠 C# 組字串)

用 WITH 能略顯風騷???

沒了






等等...UNPIVOT 勒?






官網說 就是把 PIVOT 反過來






WTF...






有張反正規化的表

翻滾吧 Table

沒了






等等...LINQ 勒?






: P






http://abundantcode.com/how-to-create-pivot-data-using-linq-in-c/

http://linqlib.codeplex.com/wikipage?title=Pivot






2014年2月7日 星期五

關於 LINQ to Entities 的時候 MSSQL 相等比較 預設不區分大小寫的問題

其實這個故事並不是發生在使用 LINQ to Entities 的時候

而是在 SSMS 敲 SQL 的時候

當時在 try 舊 DB 資料轉移新 DB 的整合的方法

說時遲那時快

這鬼才 DB 的 account 欄位的資料 竟然有在重複的 但是 key 不同

雖然登入是靠 SSO 的方式 但是 account 相同應該還是無法辨識才對

除了那些真正相同的 account 之外 忽然發現 大小寫不同 但是字串相同 也會被判斷成相同

估狗了一下才發現 原來 MSSQL 預設是沒在管大小寫的

跟啥 定序 之類的鬼東西有關

解法自然也有

1.直接改那個 定序 的設定

2.加上關鍵字 COLLATE Chinese_Taiwan_Stroke_CS_AS

參考







這種 MSSQL 才有的專屬天使

LINQ to Entities 應該絕對是會無視它的

立馬玩一下 果真如此

走訪 估狗 跟 stackoverflow 之後 解法約有二

1. .ToList() 之後再玩一次 因為這時候後就是 C# 物件 就認得大小寫

但是資料多的話肯定是 GG

2. 用之前的 T - SQL 方法 有很多鬼法子可以讓 LINQ to Entities 也吃 T - SQL

但是就跟 ORM 精神說掰掰



目前的選擇是 2 因為 1 讓人覺得實在多此一舉

但是要搞這種家醜不得外揚的東東

通常都會包成一個方法

有朝一日科技進步 或者 牛人出世 之際 再來改做法




雖然理想上我想要包成這種感覺

var q = db.user.UpperOrLowerCaseWhere(x => x.account == "amy");

讓人有種還是 LINQ 的錯覺

但是實際上有許多難點

1. 可能要反射來反射去 我才有辦法抓到 "account" 這個欄位名稱

2. 浪打返回布林 那我也無法抓到 "amy" -.-

3. 最後還是靠 T - SQL 作亂 如果在這行後面在加其他 LINQ 方法 肯定也是 GG





最後選擇擴充 IQueryable<T> 用法如下

var q = db.user.AsQueryable().UpperOrLowerCaseEquals(db"account""amy");

Where() 會轉成 IQueryable<T> 所以不必加 AsQueryable()

var q = db.user
    .Where(x => x.email.Length > 0)
    .UpperOrLowerCaseEquals(db"account""amy");

Extension 大概長這樣

    public static class IQueryableExtension
    {
        public static IEnumerable<TEntity> UpperOrLowerCaseEquals<TEntity>(
            this IQueryable<TEntity> query,
            DbContext db,
            string columnName,
            string keyword
        ) where TEntity : class
        {
            string sql = query.ToString();
            
            IObjectContextAdapter adapter = db as IObjectContextAdapter;
 
            ObjectContext objectContext = adapter.ObjectContext;
 
            var q = objectContext.ExecuteStoreQuery<TEntity>(
                string.Format(@"
                    SELECT * FROM ( {0} ) AS [table] 
                    WHERE [{1}] COLLATE Chinese_Taiwan_Stroke_CS_AS = @keyword ",
                    sql,
                    columnName
                ),
                new SqlParameter("@keyword"keyword)
            );
 
            return q.ToList();
        }
    }




命名為 UpperOrLowerCaseEquals 而非 UpperOrLowerCaseWhere

則是限制只用在相等比較

WHERE 要搞定的東東或許太複雜 ˊ_>ˋ



最後...牛人快出世吧

2012年12月25日 星期二

一秒看破 T-SQL 強大的 ISNULL() 函數

查詢最怕的就是沒法一次查出來

分幾次查 再用C# 乾坤大挪移 是個以快打快的大絕招

但是理想代碼的世界 這麼做是不好的 因為違背 SOC原則

在資料查詢層 進行了邏輯的演算 這還不包括 有可能加入一些排版的語法

如果所以必須練就出一擊斃殺式的 TSQL查詢 才能夠切的乾淨





然後是最近有人問我的一個查詢

需求如下

有兩張表 一張是訂單清單 一張是成本報價清單

兩者跟產品的關係是多對多

目的是給訂單標上成本

條件是 訂單日期 如果有 相符月份的報價 則填該日期報價

否則標最新的一個日期的報價



一開始我還不明題意的時候 直覺用 CASE 來搞 後來發現兩張表是多對多關係 CASE 不起來

最後的解法是依靠 我的愛將 ISNULL() 函數 來做子查詢


SELECT B.[PID],B.[Name],B.[Date],
ISNULL(
    (
        SELECT C.[Cost] From CostTable AS C
        WHERE B.[PID] = C.[PID]
        AND B.[Date] = C.[Date]
    ),
    (
        SELECT TOP 1 C.[Cost] From CostTable AS C
        WHERE B.[PID] = C.[PID]
        ORDER BY C.[Date] DESC
    )
) AS 'COST'
FROM BillTable AS B

aaa 跟 bbb 都有相符的報價 所以顯示對應的報價

ccc 兩筆 都無相符的報價 所以顯示最後的報價

2012年12月11日 星期二

一秒看破 T - SQL 多筆欄位合併

外表看似簡單難度卻異於常人的 T - SQL 這次又有什麼新難題呢?

就讓我們看下去

首先我有三張表 兩張 List 表 一張 Mapping 表

原先 Hyperlink 跟 Tag 的對應關係為多對多 但是為了符合正規化 拆成兩組 一對多的形式 非常常見

需求也還算合理 我想看到 每個 Hyperlink 對應的 TagName

但是我想要 不管有多少 TagName 都收錄於同一筆之中

各位看官如果沒有試過的話 不妨先自行嘗試一遍 如果輕易的就解開了 表示您已經是踢吸摳之神 值得瞻仰





就跟魔術一樣說穿了其實沒那麼難 主要需要 JOIN 跟 子查詢 這都不難想像

但是最難的應該就是這個合併成一行的 TagName

定番 估狗了一下 發現 FOR XML 子句

神人文:http://www.dotblogs.com.tw/chhuang/archive/2008/03/19/1926.aspx

簡單來說就是把查詢結果變成一行 XML 來表示

目前是針對單一比的合併 要跟 整張 Hyperlink 合併 就要借助子查詢了

但是身為具有偏執狂熱的PG 不可能允許 那個多餘的 逗點

使用 STUFF 函數 來搞定





備忘


SELECT Title, Url,
STUFF((
    SELECT DISTINCT ',' + T.TagName FROM Hyperlink AS H
    JOIN HyperlinkTag AS HT ON H.ID = HT.HyperlinkID
    JOIN Tag AS T ON T.ID = HT.TagID
    WHERE H.ID = Hyperlink.ID
    FOR XML PATH('')
),1,1,'') AS 'Tags'
FROM Hyperlink

2012年11月22日 星期四

一秒看破T-SQL分頁 使用 ROW_NUMBER() 函數

分頁~分頁~分頁~

勞版表示:ㄟ~那個誰 這頁要分頁 那頁也要 我沒說不要的都要

這時候就發現 「有沒有 在勞版的指示過後 gridview 的自動分頁都突然失效了 的八卦」 是真的

身為悲催小PG 立當自強



首先是一般查詢語法 定番是北風

不管是這樣

SELECT P.ProductID
      ,P.ProductName
      ,S.CompanyName
      ,C.CategoryName
  FROM Products AS P, Categories AS C, Suppliers AS S
 WHERE P.CategoryID = C.CategoryID AND P.SupplierID = S.SupplierID

還是這樣

SELECT P.ProductID
      ,P.ProductName
      ,S.CompanyName
      ,C.CategoryName
  FROM Products AS P
  JOIN Categories AS C ON P.CategoryID = C.CategoryID
  JOIN Suppliers AS S ON P.SupplierID = S.SupplierID

都會得到一張 完全合體型態的 查詢結果 如果你的北風是原廠的 那結果應該會是 77筆資料



接下來我們利用 ROW_NUMBER() 函數

ROW_NUMBER() 函數 其實只是幫每筆資料作編號而已 為了從中挑出某某頁的 某OO ~ XX筆 必須再加工一次



SELECT PPI AS '產品哀低'
      ,PPN AS '產品念母'
      ,SCN AS '公司念母'
      ,CCN AS '分類念母'
FROM (

SELECT ROW_NUMBER() OVER (ORDER BY ProductID) AS ROW,
       P.ProductID AS PPI
      ,P.ProductName AS PPN
      ,S.CompanyName AS SCN
      ,C.CategoryName AS CCN
  FROM Products AS P, Categories AS C, Suppliers AS S
 WHERE P.CategoryID = C.CategoryID AND P.SupplierID = S.SupplierID

) AS NewTable
WHERE NewTable.ROW >= (@PageRows * @PageIndex) + 1
  AND NewTable.ROW <= (@PageRows * @PageIndex) + @PageRows

圖解

結果

2012年5月23日 星期三

SQL CASE語法 bit型態 顯示轉換

其實沒什麼東西,但是每次要用總要查一下,人老了腦子不好使

口訣(?):CASE WHEN THEN ELSE END

2012年3月26日 星期一

SQL 從查詢結果中範圍筆數顯示 分頁查詢

如果查詢結果有一千萬萬萬萬..............筆,你想要全部顯示的話,就用select * from product

如果你還正常,你會用select Top 10 * from product 一次只顯示10筆

那第二頁呢?

...

簡單,套件無雙開了,GridView分頁開落去

但是聽說GridView的分頁其實是把全部查出來才去慢慢分頁的...

SqlDataSource Performance

你的客戶受不鳥效能差 所以把手機關掉就好了 小客戶你欺負他

但是 大客戶他欺負你

sql如何返回第三或从第三条记录开始返回(分页问题)?

至於怎麼把結果變成分頁自己找迴圈打滾吧

孟克表示:

但是如果你的客戶是小客戶...你知道的。

2012年3月15日 星期四

Join外的新選擇 - 多重From

借助先人的力量時總會有些新發現

黑暗執行緒:在LINQ中實踐多條件LEFT JOIN

文章中提到的LINQPad,還誠彼娘之超級強 -.-

用過的就會覺得自己寫LINQ 再自己猜猜SQL是什麼的行為像個傻B

以下正題

以往要多表複合喇作夥的時候你會這樣寫

但是其實這樣寫查到的結果也一樣

個人認為後者的寫法還比較容易閱讀理解

第一行明確的知道要顯示什麼欄位

第二行明確的知道要FROM哪幾個TABLE

真要說缺點的話,就是沒有什麼 左舊影 右舊影 交叉舊影 可以用

 

 

 

 

順帶附上LINQ比較

2012年3月10日 星期六

最新版 怪獸查詢

除了頭像之外的欄位都能拿來當作查詢條件

字串以LIKE查詢

數值 日期 能夠以 等於、大於、小於、介於 此四種方式查詢(大於等於、小於等於 等方式則無法)

唯一缺點是資料庫內不能有NULL值

2012年3月1日 星期四

蝴蝶效應

當初SQL欄位隨性設計

怪獸查詢隨意JOIN

第一次苦頭,在GridView顯示的時候全部重寫排序 -.-

之後又要拿出GridView的值來自定義顯示

WTF,GridView.Columns 一個順序, DisplayIndex 另一個順序

只好用個Dictionary放這兩個值,再用個List來排序,再從Dictionary取值 囧rz

簡單功能,超複雜寫法...

2012年1月31日 星期二

SQL 一秒看破 T - SQL 動態條件查詢

相信很多人有這種經驗

一個複雜的查詢 讓使用者很彈性 讓程式設計師很痛苦

你想要給人查 1.商品符合關鍵字 2.價錢介於範圍值 3.產品種類的限制 4.人氣 5.庫存 ... 等條件

簡單,你爺爺我會 T - SQL,就一項條件寫一個 Where ... and ... and ... and ... and ... and ...

判斷的方式用 C嚇 IF ELSE 就搞定了呀

code大概會長這樣

但是芳芳說:自己codeing寫一堆,麻煩做,聰明小孩就交給微軟 xxxTableAdapter 兩行就搞定了

既是強型別,又能直接造方法

但是查詢方法一種要造一個方法來查

 

 

 

 

以下正題。

其實沒那麼恐怖,T - SQL就能搞定,只要寫一個方法

 

 

 

 

先實驗T - SQL



DECLARE @uid int, @rank_id int, @bonus int, @bonusMoreThen int
DECLARE @account nchar(20), @password nchar(20)
DECLARE @email nchar(50), @name nvarchar(50), @nickname nvarchar(50), @phone nvarchar(50), @residence nvarchar(50)
DECLARE @date datetime, @birthday date
DECLARE @gender bit, @employee bit

set @uid = null
set @rank_id = null
set @bonus = null --123
set @bonusMoreThen = null --500

set @account = null
set @password = null

set @email = null
set @name = null
set @nickname = null
set @phone = null
set @residence = null

set @date = null
set @birthday = null

set @gender = null
set @employee = null

select * from account 
where rank_id = IsNull(@rank_id,rank_id)
and bonus = IsNull(@bonus,bonus)
and bonus > IsNull(@bonusMoreThen,1)

and account = IsNull(@account,account)
and password = IsNull(@password,password)

and email = IsNull(@email,email)
and name = IsNull(@name,name)
and nickname = IsNull(@nickname,nickname)
and phone = IsNull(@phone,phone)
and residence = IsNull(@residence,residence)

and date = IsNull(@date,date)
and birthday = IsNull(@birthday,birthday)

and gender = IsNull(@gender,gender)
and employee = IsNull(@employee,employee)


前大半是宣告參數不用管,後面是把14個條件都寫出來

最神奇的是使用了 IsNull()函數

IsNull()函數 接受2個參數,當第一個參數不為Null時 使用第一個參數,當第一個參數為Null時 使用第二個參數

參數不為Null就像是使用者選定了條件來查詢,所以 Where 欄位 = 參數 來查詢特定條件

參數為Null就像是使用者沒給條件就查詢,所以 Where 欄位 = 欄位

這是什麼意思呢,舉例來說就像是 Where 1 = 1 等於這個條件恆為真,所以會查到所有的資料

也可以理解成 Where 欄位 = 任意值 (因為 目前查詢到的值 等於 目前查詢到的值 ex:Where account = account)

因為預設沒設定參數就是不管這行條件,所以讓這行恆為真,再加上所有條件是以AND串連,就等於不管這行條件的意思

 

 

 

 

然後是TableAdapter查詢組態精靈裡面的語法

不用管變數宣告了 微軟幫你搞定了 真那麼好奇可以移至定義 (人生在世不需要什麼都知道)

 

 

 

 

好啦,大成功

以上