zoukankan      html  css  js  c++  java
  • Managed Database Objects: The CLR Enters the Relational Stage

    本文将对MSDN中ms-help://MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.NETDEV.v10.en/dnreal/html/realworld03112005.htm的用法进行改写,因为它针对的是Sql Server 2005 beta版本。


    The following managed database objects are supported by SQL Server 2005 Beta 2:

    • Scalar-valued user-defined functions (scalar UDFs) 
    • User-defined aggregates (UDAs)
    • Table-valued user-defined functions (TVFs)
    • User-defined procedures (UDPs)
    • User-defined data types (UDTs)
    • User-defined triggers


    下面将通过一个具体实际的例子展示用法:

    1> 生成测试数据

    create table Person
    (
       ID 
    bigint NOT NULL identity (11primary key clustered,
       FirstName 
    nvarchar(50NOT NULL,
       LastName 
    nvarchar(50NOT NULL,
       Country 
    nvarchar(50NOT NULL,
       City 
    nvarchar(50NOT NULL,
       ZipCode 
    nvarchar(50NOT NULL,
       Street 
    nvarchar(50NOT NULL,
       BirthDate 
    smalldatetime NOT NULL,
       Category 
    int NOT NULL DEFAULT(0)
    )  
    ON [PRIMARY]




    declare @CategoryCount as int
    declare @PersonCount as bigint
    declare @PersonCountMax as bigint
    declare @CountryCount as int
    declare @RowCount as int

    delete Person
    set @RowCount = 0
    set @CategoryCount = 0

    --create categories
    while @CategoryCount < 10
    begin
       
    set @CategoryCount = @CategoryCount + 1
       
    set @CountryCount = 0
       
    --create countries in each category
       while @CountryCount < 10
       
    begin   
          
    set @CountryCount = @CountryCount + 1
          
    set @PersonCount = 0      
          
    --create a random number of persons
          set @PersonCountMax = rand() * 50      
          
    while @PersonCount < @PersonCountMax
          
    begin
             
    set @PersonCount = @PersonCount + 1      
             
    insert into 
                Person       
             
    values
             (
                
    'fn' + cast(@PersonCount as nvarchar(10)),
                
    'ln' + cast(@PersonCount as nvarchar(10)),
                
    'country' + cast(@CountryCount as nvarchar(10)),
                
    'SqlCity',
                
    '000000',
                
    'SqlStreet',
                
    GetDate(),
                
    @CategoryCount
             )   
             
    set @RowCount = @RowCount + 1
             
    print @RowCount         

          
    end
       
    end
    end


    Requirements:


    What we have here is a very simple table storing information about people. The business requirements specify that each person has to part of a single category, identified by an integer value. One day, our boss (the suite, for those who attended Tech-Ed 2004 in Amsterdam) comes to us with the following requirement—he wants to know, for each category of persons, which are the three countries having the largest number of persons in that particular category.



    2> Aggregate

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


    [Serializable]
    [Microsoft.SqlServer.Server.SqlUserDefinedAggregate(Format.UserDefined, 
        IsInvariantToDuplicates
    =false,
        IsInvariantToNulls
    =true,
        IsInvariantToOrder
    =false,
        IsNullIfEmpty
    =true,
        MaxByteSize
    =8000
    )]
    public struct Aggregate_StrJoin:IBinarySerialize
    {
        
    private StringBuilder _result;

        
    public void Init()
        
    {
            _result 
    = new StringBuilder();
        }


        
    public void Accumulate(SqlString Value)
        
    {
            
    if (Value.IsNull)
            
    {
                
    return;
            }

            
    else
            
    {
                
    if (_result.Length > 0)
                    _result.Append(
    ",");
                _result.Append(Value.Value);
            }


        }


        
    public void Merge(Aggregate_StrJoin Group)
        
    {
            _result.Append(Group._result);
        }


        
    public SqlString Terminate()
        
    {
            
    if (_result.Length > 0)
            
    {
                
    return new SqlString(_result.ToString());
            }

            
    return new SqlString("");

        }


        
    IBinarySerialize Members


    }


    使用方法:

    select category,dbo.Aggregate_StrJoin(country) as countries from person
     group by category
     order by category


    3> TVF

    using System;
    using System.Data;
    using System.Collections;
    using System.Data.SqlClient;
    using System.Data.SqlTypes;
    using Microsoft.SqlServer.Server;

    public partial class UserDefinedFunctions
    {
        [Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName 
    = "readRow", TableDefinition = "category INT, countries NVARCHAR(100)", DataAccess = DataAccessKind.Read)]
        
    public static IEnumerable TableValueFunction()
        
    {
            DataTable dt 
    = new DataTable();
            dt.Columns.Add(
    new DataColumn("category", Type.GetType("System.Int32")));
            dt.Columns.Add(
    new DataColumn("countries", Type.GetType("System.String")));
            DataRow row;

            
    using (SqlConnection cn = new SqlConnection())
            
    {
                cn.ConnectionString 
    = "context connection=true";
                
    using (SqlCommand cmd = cn.CreateCommand())
                
    {
                    cmd.CommandText 
    = "select category,country,count(*) as PersonCount from person" +
                                        
    " group by category,country" +
                                        
    " order by category,PersonCount desc";
                    cn.Open();
                    SqlDataReader dr 
    = cmd.ExecuteReader();

                    
    int previousCategory = 1, currentCategory = 0;
                    
    int coutries = 0;
                    
    string coutryList = "";

                    
    while (dr.Read())
                    
    {
                        currentCategory 
    = dr.GetInt32(0);
                        
    if (currentCategory != previousCategory)
                        
    {
                            row 
    = dt.NewRow();
                            row[
    0= previousCategory;
                            row[
    1= coutryList;
                            dt.Rows.Add(row);

                            previousCategory 
    = currentCategory;
                            coutries 
    = 0;
                            coutryList 
    = "";
                        }


                        
    if (++coutries <= 3)
                        
    {
                            coutryList 
    += dr.GetString(1+ ",";
                        }

                    }

                }

            }


            
    return dt.Rows;
        }


        
    public static void readRow(object row, out SqlInt32 category, out SqlString countries)
        
    {
            DataRow r 
    = (DataRow)row;

            category 
    = Convert.ToInt32(r[0]);
            countries 
    = Convert.ToString(r[1]);
        }

        
    }
    ;




    感受到,使用C#写存储过程,用户函数的好处:

    1. 可方面的使用.Net类库,进行文件操作等(sql不易处理)
    2. 进行逻辑复杂的查询、统计等,使用CLS可提高效率
    3. 可创建自己的聚合函数

  • 相关阅读:
    异步编程案例分享—后台线程事实通知任务进度
    ORACLE 常见错误
    设计模式——工厂模式
    sql 脚本编写之路 常用语句(一)
    C# 深入浅出 异步(八)
    设计模式——单例模式
    Sql Server 学习链接
    SqlServer 常用函数
    2016 ACM/ICPC Asia Regional Shenyang Online
    2016 ACM/ICPC Asia Regional Dalian Online
  • 原文地址:https://www.cnblogs.com/silva/p/841466.html
Copyright © 2011-2022 走看看