<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 312, 文章 - 14, 評論 - 1393, 引用 - 0
    數據加載中……

    SQL Server2005雜談(4):在SQL Server2005中按列連接字符串的三種方法

    本文為原創,如需轉載,請注明作者和出處,謝謝!

    上一篇:
    SQL Server2005雜談(3):四個排名函數(row_number、rank、dense_rank和ntile)的比較

    最近做一個項目,遇到一個在分組的情況下,將某一列的字段值(varchar類型)連接起來的問題,類似于sum函數對int型字段值求和。 如有一個表t_table,結構和數據如圖1



                                              圖1

        其中要按著xh字段分組,并且將每一組name字段值連接起來。最終結果希望如圖2所示




                 圖2

    表中的th字段值對于每一個xh值是唯一的,也是有限的,也就是說,對于一個xh值,th的值不會太多,如最多是10個(從110)。

    以上需求最終想了三種方法來解決這個問題。

    一、修改表結構

    如果是新的項目,可以考慮修改一下表的結構。如果t_table的結構修改如下:

        xh     value1 value2   value3    value4     .... ....                 value10

       0001 123456 654321 456789 
       0002 12abcd 4d2r343 343dfd
       0003 abcde3 132323

    這種方法將value的值縱向改為橫向,也就是說,按每一個xh值,將value字段的值按逆時針旋轉了90度。 但這種方法要有一個前提,就是假設xh的每一個值所對應的value值不會太多,如上面不超過10個,這樣才有可能建立有限個字段。如果按著上面的字段結構,只需要將這些字段加一起就可以了,也不用分組。如下所示:


    select xh , (value1 + value2 + value3 +  + value10) as value from t_table

    但這種方法至少有如下三個缺陷:

    1. 需要修改表結構,這對于已經進行很長時間或是已經上線的項目產不適用

    2. 對每一個xh字段的value取值數有限制,如果太多,就得建立很多字段。這樣性能會降低。

    3. 這樣做雖然查詢容易,但如果需要對每一個xh的不同值頻繁修改或加入新的值時,如果把它們都放到一行,容易因為行鎖而降低性能。

    二、動態生成select語句

        讓我們先看三條SQL語句:

    select xh,value as th1 from t_table where th=1 
    select xh,value as th2 from t_table where th=2
    select xh,value as th3 from t_table where th=3

    這三條語句分別使用th字段按著所有th可能的值來查詢t_table,這三條SQL語句所查詢出來的記錄如圖3所示。



                            圖 3

        然后再使用下面的語句按著xh分組:

    select xh from t_table group by xh


    得到的結果如圖4所示。



           圖4


    然后使用left join,以圖4所示的表為最左邊的表,進行連接,SQL語句如下:


    select a.xh, b.th1, c.th2, d.th3 from
    (
    select xh from t_table group by xh) a 
    left join 
    (
    select xh,value as th1 from t_table where th=1) b on a.xh=b.xh 
    left join 
    (
    select xh,value as th2 from t_table where th=2) c on a.xh=c.xh 
    left join 
    (
    select xh,value as th3 from t_table where th=3) d on a.xh=d.xh

        之所以使用left join,是因為按著th查詢后,有的表的某些xh值可以沒有,如圖3中的第三個表,就沒有0003。如果使用內連接,0003就無法在記錄集中體現。這面的SQL的查詢結果如圖5所示。




                  圖5

        然后我們就可以使用如下的語句來連接th1th2th3了。 

    select xh, (th1+th2+th3) as th from myview

    myview表示將上面用left join的語句保存成的視圖。

    下面可以將這個過程寫成一條SQL語句:

    select xh, (th1+th2+th3) as th from 
    (
    select a.xh,  (case when b.th1 is null then '' else b.th1 endas th1,
     (
    case when c.th2 is null then '' else c.th2 endas th2,
     (
    case when d.th3 is null then '' else d.th3 endas th3 
    from
    (
    select xh from t_table group by xh) a  
    left join 
    (
    select xh,value as th1 from t_table where th=1) b on a.xh=b.xh 
    left join 
    (
    select xh,value as th2 from t_table where th=2) c on a.xh=c.xh 
    left join
    (
    select xh,value as th3 from t_table where th=3) d on a.xh=d.xh
    ) x

        由于null加上任何字符串都為null,因此,使用case語句來將null轉換為空串。上面的SQL就會得到圖2所示的查詢結果。也許有的讀者會問,如果th的可能取值可變呢!如xh0001th值四個:14 那上面的SQL不是要再加一個left join嗎?這樣不是很不通用。 要解決這個問題也很容易。可以使用程序(如C#Java等)自動生成上述的SQL,然后由程序提交給數據庫,再執行。 當然,這需要程序事先知道th值對于當前程序最多有幾個值,然后才可以自動生成上述的SQL語句。

    這種方法幾乎適合于所有的數據庫,不過如果th的取值比較多的話,可能SQL語句會很長,但是如果用程序自動生成的話,就不會管這些了。


    三、使用C#實現SQL Server2005的擴展聚合函數(當然,也可以用VB.NET

        這一種方法筆者認為是最“酷”的方法。因為每一個人都只想寫如下的SQL語句就可以達到目錄。

    select xh, dbo.joinstr(value) from t_table group by xh

    其中joinstr是一個聚合函數,功能是將每一組的某個字符串列的值首尾連接。上面的SQL也可以查詢圖2所示的結果。但遺憾的是,sql server2005并未提供可以連接字符串的聚合函數。下面我們就來使用C#來實現一個擴展聚合函數。

         首先用VS2008/VS2005建立一個SQL Server項目,如圖6所示。



                                                                        圖6

        點擊“確定”按鈕后,SQL Server項目會要求連接一個數據庫,我們可以選擇一個數據庫,如圖7所示。



                                           圖7

        然后在工程中加入一個聚合類(joinstr.cs),如圖8所示。



                                                                                          圖8
        joinstr.cs中的最終代碼如下:


    using System;
    using System.Data;
    using Microsoft.SqlServer.Server;
    using System.Data.SqlTypes;
    using System.IO;
    using System.Text;

    [Serializable]
    [SqlUserDefinedAggregate(
        Format.UserDefined, 
    //use custom serialization to serialize the intermediate result
        IsInvariantToNulls = true//optimizer property
        IsInvariantToDuplicates = false//optimizer property
        IsInvariantToOrder = false//optimizer property    
        MaxByteSize = 8000//maximum size in bytes of persisted value
    ]

    public struct joinstr :IBinarySerialize
    {
        
    private System.Text.StringBuilder intermediateResult;
        
        
    public void Init()
        {
            
    // 在此處放置代碼
            intermediateResult = new System.Text.StringBuilder();
        }

        
    public void Accumulate(SqlString Value)
        {
            intermediateResult.Append(Value.Value);
        }

        
    public void Merge(joinstr Group)
        {
            intermediateResult.Append(Group.intermediateResult);
        }

        
    public SqlString Terminate()
        {
            
    return new SqlString(intermediateResult.ToString());
        }

        
    public void Read(BinaryReader r)
        {
            intermediateResult 
    = new StringBuilder(r.ReadString());
        }

        
    public void Write(BinaryWriter w)
        {
            w.Write(
    this.intermediateResult.ToString());
        }
    }

    由于本例需要聚合字符串,而不是已經被序列化的類型,如int等,因此,需要實現IBinarySerialize接口來手動序列化。使用C#實現SQL Server聚合函數,也會受到字符串最大長度為8000的限制。

         在編寫完上述代碼后,可以使用Visual Studio來部署(右向工程,在彈出菜單上選“部署”即可)。也可以使用SQL語句來部署。假設上面的程序生成的dllMyAggregate.dll,可以使用下面的SQL語句來部署:

    CREATE ASSEMBLY MyAgg FROM 'D:\test\MyAggregate.dll'

    CREATE AGGREGATE joinstr (@input nvarchar(200)) RETURNS nvarchar(max)
    EXTERNAL NAME MyAgg.joinstr

        要注意的是,字符串類型需要用nvarchar,而不能用varchar。

    第一條SQL語句是裝載dll,第二條SQL語句是注冊joinstr聚合函數(每一個C#類就是一個聚合函數)

    在執行上面的SQL語句之前,需要將SQL Server2005clr功能打開。如圖9所示。




                                                   圖9

        如果想刪除上面建立的聚合函數,可以使用如下的
    SQL語句:

    drop aggregate joinstr

    在刪除聚合函數后,可以將MyAggregate.dll卸載。

    drop assembly MyAgg

    OK,現在可以使用joinstr來聚合字符串了。

       
    這種方法雖然顯示很“酷”,但卻要求開發人員熟悉擴展聚合函數的開發方法,如果開發人員使有的不是微軟的開發工具,如使用Java,恐怕這種方法就只能是空談了(除非開發小組內有人會用微軟的開發工具)。

    當然,如果使用其他的數據庫,如oraclemysql,也是可以實現類似擴展函數的功能的,如oracle可以使用java來進行擴展。但這要求開發人員具有更高的素質。

    以上介紹的三種方法僅供參考,至于采用哪種方法,可根據實際需要和具體情況而定。如果哪位讀者有更好的方法,請跟貼!

    下一篇:
    SQL Server2005雜談(5):將聚合記錄集逆時針和順時針旋轉90度



    Android開發完全講義(第2版)(本書版權已輸出到臺灣)

    http://product.dangdang.com/product.aspx?product_id=22741502



    Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


    新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

    posted on 2008-06-25 13:16 銀河使者 閱讀(2851) 評論(3)  編輯  收藏 所屬分類: SQL Serverdatabases 原創

    評論

    # re: 在SQL Server2005中按列連接字符串的三種方法  回復  更多評論   

    俄~~~~好厲害。不過如果讓我做的話。我寧愿使用臨時變量再最后組合。樓主的上面幾個用法好像把簡單問題復雜化了。
    2008-07-09 16:17 | 天草麟

    # re: 在SQL Server2005中按列連接字符串的三種方法  回復  更多評論   

    用表變量好象效率不高。采用哪種方法,讀者可以實際情況而定
    2008-07-10 09:53 | 銀河使者

    # re: SQL Server2005雜談(4):在SQL Server2005中按列連接字符串的三種方法  回復  更多評論   

    那該怎么辦
    2011-05-14 23:53 | cheap sunglasses
    主站蜘蛛池模板: 国产亚洲视频在线播放大全| 亚洲精品高清在线| 久久午夜无码免费| 免费视频精品一区二区| 中文日韩亚洲欧美制服| 亚洲日本视频在线观看| 亚洲AV日韩精品久久久久| 国产亚洲精品不卡在线| 成人伊人亚洲人综合网站222| 成年人在线免费观看| 8x8×在线永久免费视频| 国产成人无码区免费网站| 一区二区三区免费视频观看| 麻豆亚洲AV成人无码久久精品| 国产成人精品亚洲日本在线| 亚洲欧洲日本精品| 久久久婷婷五月亚洲97号色| 久久久久久亚洲精品中文字幕| 亚洲精品美女久久久久99| ZZIJZZIJ亚洲日本少妇JIZJIZ| 亚洲AV无码乱码精品国产| 免费一级毛片一级毛片aa| 免费在线视频一区| 国产国产人免费视频成69大陆| 麻豆精品国产免费观看| 在线免费一区二区| 国产美女a做受大片免费| 色吊丝最新永久免费观看网站 | 亚洲国产情侣一区二区三区| 亚洲成电影在线观看青青| 精品亚洲成a人片在线观看| 亚洲黄色三级视频| 亚洲国产精品成人综合色在线婷婷 | 亚洲av无码片在线观看| 激情亚洲一区国产精品| 亚洲伦理中文字幕| 亚洲国产aⅴ成人精品无吗| 国产综合激情在线亚洲第一页| 全部一级一级毛片免费看| xxxx日本在线播放免费不卡| 成全视成人免费观看在线看|