目录

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

第一章 数据类型相关问题

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

在线上环境更改数据类型是非常危险的

使用 SET STATISTICS IO ON 来检查是否有I/O操作,如果没报告I/O操作,那么可以确定不需要访问基表,执行速度会非常快,

例如,把varchar列的大小改为更大的值将不涉及对基本数据的I/O操作,更改会瞬间完成,如果缩短varchar列的长度需要访问基表数据,对大表操作时会花费很多时间

 

尽量不要使用SSMS来更改架构,使用这些工具会带来不必要的操作:比较创建一个新表,复制数据,删除原表,把新表重名为原来的表名,

好习惯是使用TSQL代码来执行架构更改!!

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记 

F

datetime数据类型

datetime在内部使用2个4字节来存储,一共需要8字节,前4个字节表示年月日,后4个字节表示一天中的时间

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

SET DATEFORMAT对日期处理的影响

SET DATEFORMAT DMY

USE [sss]
INSERT INTO [dbo].[counttb]
        ( [id], [TESTDATE] )
VALUES  ( 100, -- id - int
          '2012-12-3 10:20:10'  -- TESTDATE - datetime
          )

SELECT   CAST(CONVERT(CHAR(8), [TESTDATE], 112) AS DATETIME) FROM [dbo].[counttb]
SELECT   * FROM [dbo].[counttb]

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

查询session级别的set 选项

DBCC USEROPTIONS

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

SQLSERVER根据当前session的语言设置进行转换,session的语言由登录login的默认语言决定,也可以使用set languagesession选项重新设置,通过使用set dateformat选项,指定字符d,m,y的组合,也可以控制如何解释由数字和分隔符组成的datetime字面值

SET DATEFORMAT DMY
SET DATEFORMAT YDM
.
.
.
.
.
.

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

sqlserver有两种datetime的字面格式独立于任意设置

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

依赖ODBC api的格式

datetime的数据类型四舍五入

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

datetime函数的表达式返回的一些结果依赖于特定的语言,如果session的语言设置为us_english,那么datename返回的是Wednesday

getdate()返回服务器本地的datetime值,getutcdate()返回当前的通用协调时间,他是根据服务器本地时间和设置的时区计算得出的,

current_timestamp是ansi形式的getdate()!!

当仅指定日期时,你可以忽略时间部分,当转换到datetime时,该值包含时间部分,但是该部分表示午夜
当只包含时间部分的字符串转换到datetime时,sqlserver把日期部分设置为基本日期1900-1-1

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

从getdate()仅提取日期部分用作默认值

SELECT DATEADD(d, DATEDIFF(d, 0, GETDATE()), 0)
SELECT CAST(CONVERT(CHAR(8), GETDATE(), 112) AS DATETIME)

前者最高粒度是秒,后者是毫秒


2014-09-13 00:00:00.000

F

datetime相关查询问题
解决闰年问题

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

标识重叠 identifying overlay

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

分组重叠 grouping overlay

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

在sqlserver2000中可以使用派生表derived table代替CTE,派生表即子查询

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

标识星期数(identifying weekday)

F

datepart标识星期数依赖于datefirst,还有语言设置langguage setting

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

星期数的坐标轴是循环的,这一特点为反比关系的计算增加了些难度,数学中有完整的学科可以处理循环坐标轴,例如,下面是几个基于星期数坐标轴的计算
1+1=2
7-1=1
7-1=6
1-1=7

 

datefirst的设置值和datepart函数返回的星期数之间存在反比关系!!

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

SELECT (weekday,GETDATE()+@@DATEFIRST-n)

 

F

1900年1月1日是星期一
那么问题可以这样解决

实际上这种方法就是以1900年1月1日为标准,任何事物都会有一个标准,设定一个标准

USE [AdventureWorks]

SELECT orderid ,
orderdate
FROM orcers
WHERE DATEDIFF(DAY, '19000102', orderdate) % 7 = 0

 

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

使用参照日期的方法

1900年1月1日 --星期一

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

ISO周

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

包含边界(inclusive),不包含边界(non-inclusive)

工作日 working day

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

生成日期序列
你可能会用到两个日期之间的所有可能的日期序列,例如,这种日期序列可以用于填充SSAS中的时间维度time dimension

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

USE [sss]
SET NOCOUNT ON
CREATE TABLE nums
    (
      n INT NOT NULL
            PRIMARY KEY
    )
DECLARE @max AS INT
DECLARE @rc AS INT
SET @max = 1000000
SET @rc = 1

INSERT  INTO nums
VALUES  ( 1 )
WHILE @rc * 2 <= @max
    BEGIN 
        INSERT  INTO nums
                SELECT  n + @rc
                FROM    nums
        SET @rc = @rc * 2
    END

INSERT  INTO nums
        SELECT  n + @rc
        FROM    nums
        WHERE   n + @rc <= @max

SELECT  *
FROM    [dbo].[nums]

-----------------------------------------
DECLARE @s AS DATETIME
DECLARE @e AS DATETIME
SET @s = '20060101'
SET @e = '20061231'
SELECT  @s + n - 1 AS dt
FROM    [dbo].[nums]
WHERE   n <= DATEDIFF(DAY, @s, @e) + 1

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

字符相关问题

模式匹配,分析,区分大小写

sqlserver使用like和patindex支持模式匹配

tsql还不支持正则表达式regular expression,ansi通过similar to运算符支持正则表达式

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

否定逻辑reverse logic比使用肯定逻辑positive logic 更有效

--CHECK匹配序列号
--序列号固定
CHECK(sn LIKE '[0-9][0-9][0-9][0-9][0-9]')
--序列号不固定
CHECK(sn LIKE REPLICATE('[0-9]',LEN(SN)))

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

--否定逻辑
CHECK(sn NOT LIKE '%[^0-9]%')

 

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

--join的时候还可以用like来join 条件
SELECT  ip ,
        CAST(SUBSTRING(ip, s1, l1) AS TINYINT) AS o1 ,
        CAST(SUBSTRING(ip, s2, l2) AS TINYINT) AS o2 ,
        CAST(SUBSTRING(ip, s3, l3) AS TINYINT) AS o3 ,
        CAST(SUBSTRING(ip, s4, l4) AS TINYINT) AS o4
FROM    IPs
        JOIN IPPatterns ON ips.ip LIKE IPPatterns.pattern
ORDER BY o1 ,
        o2 ,
        o3 ,
        o4

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

还可以使用SELECT PARSENAME()的方法来解析ip地址

SELECT PARSE()

F

bin二进制排序规则都是区分大小写的

大写小写的二进制,ascii都不同

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

--如果改变排序规则的话会使用表扫描,这样会降低效率
USE [sss]
SELECT  *
FROM    [dbo].[aaa]
WHERE   [name] COLLATE latin1_general_cs_as = 'sdfsdf'

 

--where里面的搜索条件可以搜索两次,第一次指定排序规则,影响执行计划走索引查找,select运算符会有感叹号
USE [sss]
SELECT  *
FROM    [dbo].[aaa]
WHERE   [name] COLLATE latin1_general_cs_as = 'sdfsdf'
        AND [name] = 'sdfsdf' 

 

F

大型对象lob

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

通过引入bulk行集提供程序(bulk rowset provider),对从文件中加载数据的支持也得到加强,

这个新的提供程序允许你使用bulk引擎高效地将文件数据加载为行集,sqlserver6.5的时候已经有bulk程序!!

通过使用max说明符,varchar,nvarchar,varbinary,sqlserver存储这些值可以达到lob支持的最大容量,即2GB

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

SQLSERVER提供了max列的write方法来修改字符串中的部分数据,而不需要加载整个字段值

试想一下,整个字段值2GB的话,那么读取字段值和写入字段值将会很慢,但是通常我们的业务一个字段很少有2GB数据

一般有100MB就不错了,所以代码中总是set xx=xx,而不是xx.write()

UPDATE  [dbo].[aaa]
SET     [name].WRITE('SDF', 9, 3)
WHERE   [a] = 1

wirte()方法类似于lob数据的,readtext,writetext

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

USE [AdventureWorks]
SELECT shipperid,companyname,phone
FROM OPENROWSET(BULK 'C:\TEMP\SHIPPER.TXT',FORMATFILE='C:\TEMP\SHIPPERS.FMT')AS S

OPENROWSET的bulk提供程序

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

bulk行集提供程序加载数据可以使用表提示
keepidentity
keepdefaults
ignore_constraints
ignore_triggers
tablock

USE [tempdb]
CREATE TABLE shippers
    (
      shipperid INT NOT NULL
                    PRIMARY KEY ,
      companyname NVARCHAR(40) NOT NULL ,
      phone NVARCHAR(24) NOT NULL
                         CHECK ( phone NOT LIKE '%[^0-9()]%' )
    )

INSERT  INTO [dbo].[shippers] WITH ( IGNORE_CONSTRAINTS )
        SELECT  *
        FROM    OPENROWSET(BULK 'C:\TEMP\SHIPPER.TXT',
                           FORMATFILE= 'C:\TEMP\SHIPPERS.FMT') AS S
INSERT  INTO [dbo].[shippers] WITH ( IGNORE_TRIGGERS )
INSERT  INTO [dbo].[shippers] WITH ( KEEPIDENTITY )
INSERT  INTO [dbo].[shippers] WITH ( KEEPDEFAULTS )
USE [tempdb]
CREATE TABLE student(id INT PRIMARY KEY,name NVARCHAR(200))
CREATE TABLE score(scoreId INT ,level INT)



--外键约束如下:比如student表id位主键,score为子表scoreId为外键
alter table score ADD CONSTRAINT FK_Score_ScoreId foreign key(scoreId) references student(id);

INSERT [dbo].[student]
        ( [id], [name] )
VALUES  ( 1, -- id - int
          N'lily'  -- name - nvarchar(200)
          )

--外键约束 报错
INSERT [dbo].[score]
        ( [scoreId], [level] )
VALUES  ( 2, -- scoreId - int
          2  -- level - int
          )

--方法一
ALTER TABLE [dbo].[score] NOCHECK CONSTRAINT  FK_Score_ScoreId
ALTER TABLE [dbo].[score] NOCHECK CONSTRAINT ALL


--方法二
DELETE FROM [dbo].[score]

ALTER TABLE [dbo].[score] CHECK CONSTRAINT ALL


INSERT [dbo].[score] WITH (IGNORE_CONSTRAINTS)
        ( [scoreId], [level] )
VALUES  ( 2, -- scoreId - int
          2  -- level - int
          )
----消息 8171,级别 16,状态 1,第 1 行
--对象 'dbo.score' 上的提示 'ignore_constraints' 无效。

INSERT [dbo].[student] WITH (IGNORE_CONSTRAINTS)
        ( [id], [name] )
VALUES  ( 2, -- id - int
          N'tom'  -- name - nvarchar(200)
          )
消息 8171,级别 16,状态 1,第 1 行
对象 'dbo.student' 上的提示 'ignore_constraints' 无效。

表提示 IGNORE_CONSTRAINTS不行的

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

隐式转换

tsql表达式的结果数据类型result datatype是由表达式中具有最高优先级的操作数的数据类型决定的,

在msdn论坛里的case when里返回的数据的数据类型导致不能执行动态sql!!

字符串varchar的优先级比interger低

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

case表达式的结果数据类型由then子句的结果表达式中具有优先级最高的数据类型决定,不论实际返回到哪个表达式

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

SELECT  CASE WHEN 1 > 1 THEN 10
             WHEN 1 = 1 THEN 'abc'
             WHEN 1 < 1 THEN 10.1
        END
--消息 8114,级别 16,状态 5,第 1 行
--从数据类型 varchar 转换为 numeric 时出错。

 

F

sql2005 技术内幕 TSQL程序设计 P37


有两种方法解决这个问题 CASE 语句的结果表达式问题
1、把索引结果表达式显式转换为都可以转换的通用类型,但是会发生功能错误,例如比较和排序时
2、把所有结果表达式转换为SQL_VARIANT,他是一个通用类型,所有基本类型(base type)都可以在其中保存

SELECT  CASE WHEN 1 > 1 THEN CAST(10 AS SQL_VARIANT)
             WHEN 1 = 1 THEN CAST('abc' AS SQL_VARIANT)
             WHEN 1 < 1 THEN CAST(10.1 AS SQL_VARIANT)
        END

DECIMAL优先级比FLOAT低

SQL_VARIANT数据类型系列和数据类型层次结构
数据类型层次结构(datatype hierarchy)中,数据类型系列(datatype family)具有较高的优先级,他自己就可以确定该值优先级更高,

不管实际值是什么,所以下面的语句返回smaller,

因为float是属于近似数字(approximate numeric)数据类型系列decimal属于精确数字(exact numeric)数据类型系列
在层次结构中,前者比后者级别更高

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

筛选表达式

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

如果表达式两侧的数据类型不同,不同版本的sqlserver的行为是不一样的,sqlserver7.0总是把标量表达式的数据类型转换为列的数据类型,这样该表达式就是一个SARG,允许利用col1上的索引

sqlserver2000改了这行为,标量表达式的数据类型优先级比列高,那么列类型要转换为标量表达式的类型,尽管有些时候优化使用常量扫描constant scan和nested loop运算符以允许使用索引,但是在有join个的情况下,t1.col1=t2.col2,但是如果处于同一个数据类型系列,int和decimal,优化器也不会假设两个索引具有相同的排序行为

这种情况下无法执行merge join

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

sql2005中收集字符串概要string summary统计信息,用于改进对包含任意通配符的like谓词的基数评估cardinality estimation

他收集字符列中子字符串的频率分布frequency distribution

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

为什麽关系数据库管理系统并没有强制主键,mysql默认加隐藏主键

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

对象关系映射工具ORM

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

使用UDT创建正则表达式

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

CREATE ASSEMBLY 导入数据库,注册程序集,该命令有一个PERMISSION_SET  子句,默认是safe级别

safe权限执行的程序集代码不能访问外部系统资源,比如文件,网络,环境变量,注册表
external_access允许程序集访问一些外部系统资源
unsafe级别允许不受限制的资源访问,包括sqlserver实例内部和外部的资源,并可调用非托管代码

CREATE ASSEMBLY complenumerCS
FROM 'C:\COMPLEXNUMBERCS\BIN\DEBUG\COMPLENX.DLL'
WITH PERMISSION_SET =SAFE

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

如果你需要一个支持UDT的聚合函数,必须自己创建他,这个聚合函数是UDA,用户定义聚合函数

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

accumulate:累积

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

--修改程序集以添加complex UDA
ALTER ASSEMBLY COMP
FROM ''

--创建聚合函数
CREATE AGGREGATE [dbo].complex_sum(@input compl)
RETURNS comp
EXTERNAL NAME comp

 

F

你可以看到,可以开发CLR UDA以支持CLR UDT

使用VB.NET创建UDT和UDA

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

XML数据类型

使用符合W3C标准的XQuery语言操作XML

XQuery语言包括

查询query方法

获取值value方法

检查是否存在exists方法

修改一部分XML数据modify方法区别于覆盖全部数据,

把xml数据拆分到结果集中的多行nodes方法

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Freinventing the wheel 重复发明轮子

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

使用xml的原因
DDL触发器里的EventInfo函数返回xml格式的事件信息,这样增加新事件将非常方便
还有执行计划set showplan_xml
adjacency list:邻接列表

 

.net应用程序中的对象支持两种持久化的方法,使用二进制序列化或XML序列化

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

如果visio文档保存为xml,你甚至可以使用全文索引来搜索visio文档中的数据

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

向存储过程传递一个数组参数的方法有3个
1、以逗号分隔的字符串形式数组


2、http://www.51cto.com/art/200805/75029.htm

SQL2008表值参数,表值参数(Table-valued parameter)是SQL Server 2008的一个新特性DECLARE @TV AS [OfficeLocation_Tabetype]
INSERT INTO @TV (Id, Shortname, Name) SELECT 12, 'ME1', 'Dubai'
INSERT INTO @TV (Id, Shortname, Name) SELECT 13, 'ME2', 'Tehran'
INSERT INTO @TV (Id, Shortname, Name) SELECT 17, 'EA1', 'Bombay'
INSERT INTO @TV (Id, Shortname, Name) SELECT 18, 'EA2', 'Karachi'
INSERT INTO @TV (Id, Shortname, Name) SELECT 3, 'NA3', 'NewYork'
INSERT INTO @TV (Id, Shortname, Name) SELECT 4, 'EU1', 'London'
exec usp_InsertProdLocation @TV


3、传递XML形式的数组,使用.nodes方法把值保存到关系形式

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

把XML文档导入到数据表中

SINGLE_BLOB

USE [sss]
CREATE TABLE VisioDocs
(
id INT NOT NULL ,
doc XML NOT NULL
)
INSERT INTO VisioDocs(id,doc)
SELECT 1 ,* 
FROM OPENROWSET(BULK,'C:\PRODUCTORM.VDX',SINGLE_BLOB)AS X

 

新的bulk行集提供程序加载文件数据的优势非常明显

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

.VALUE()方法返回一个标量值,所以他可以用于select列表

prolog  :开端;开场白

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

xml数据类型实际上是一个lob类型,每列数据最大可以达到2GB
你在xml列上创建的第一个索引主XML索引primary xml index
该索引将分解xml值的持久表示


创建主xml索引后,再创建另外三种类型的辅助xml索引secondary xml index
path

value

property

 

必须先创建主索引,创建xml索引的表必须具有主键聚集索引!!

USE [sss]

CREATE TABLE VisioDocs
    (
      id INT NOT NULL ,
      doc XML NOT NULL
    )
INSERT INTO VisioDocs(id,doc)
SELECT 1 ,* 
FROM OPENROWSET(BULK,'C:\PRODUCTORM.VDX',SINGLE_BLOB)AS X

--创建聚集主键
ALTER TABLE VisioDocs ADD CONSTRAINT PK_VisioDocs PRIMARY KEY CLUSTERED(ID)

--先创建主xml索引
CREATE PRIMARY XML INDEX idx_xml_primary ON VisioDocs(doc)
--消息 6332,级别 16,状态 201,第 1 行
--表 'VisioDocs' 需要具有一个包含的列数小于 16 的聚集主键,才能为其创建主 XML 索引。
--符合两个要求:聚集,主键
--创建辅助xml path索引
CREATE XML INDEX idx_xml_path ON VisioDocs(doc)
USING XML INDEX idx_xml_primary FOR PATH

DROP INDEX idx_xml_primary ON idx_xml_primary

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

删除主xml索引,所有的辅助xml索引也将会自动删除

DROP INDEX idx_xml_primary ON idx_xml_primary

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

--获取架构集合的信息
SELECT  *
FROM    sys.[xml_schema_collections]
WHERE   [name] = 'contranotherarrtibutes'

--获取架构集合中的命名空间信息
SELECT  N.*
FROM    SYS.[xml_schema_namespaces] AS N
        JOIN SYS.[xml_schema_collections] AS C ON N.[xml_collection_id] = C.[xml_collection_id]
WHERE   C.[name] = 'contranotherarrtibutes'

--获取架构集合中的组件信息
SELECT  *
FROM    sys.[xml_schema_components] AS CP
        JOIN SYS.[xml_schema_collections] AS C ON CP.[xml_collection_id] = C.[xml_collection_id]
WHERE   C.[name] = 'contranotherarrtibutes'

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

约束输入的xml数据的合法性使用xml架构验证,再进一步约束要使用check约束

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

.NODES方法,当把xml值拆分到关系数据时这个方法非常有用.nodes方法的结果集包含原始xml实例的逻辑副本

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

.NODES方法返回xml值的副本,你必须用其他方法提取其中的标量值,表中每一行都要调用.nodes方法,那么apply运算符,

cross apply为基表的每一行调用from子句的.nodes方法

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

使用xml作为存储过程的参数

CREATE PROCEDURE [dbo].GetContacts
@inplist XML
AS 
SELECT C.*
FROM [dbo].Contact AS C
JOIN (SELECT D1.C1.VALUE('(./TEXT())[1]','NVARCHAR(50)')AS NAMENEEDED
FROM @INPLIST.NODES('/NAMES/NAMENEEDED') AS D1(C1)) AS D2
ON C.CONTACTNAME=D2.NAMENEEDED
GO

 

F

XQUERY的修改语句
.modify方法与varchar(max)的write方法类似

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

XQUERY的修改语句
insert
delete
replace value of

F

XQUERY的方法严格使用小写字母,因为他们是区分大小写的,就像xml中的任何数据一样
value
modify
nodes
path
property

--VisioDocs
UPDATE VisioDocs
SET doc.MODIFY ('')

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 第二章 临时表和表变量

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

#T1_________________________00000000000001E这是表的内部名称,在代码中你应该引用创建他时使用的名称#T1

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

SET CONTEXT_INFO
将最多 128 字节的二进制信息与当前会话或连接关联。

http://msdn.microsoft.com/zh-cn/library/ms187768(SQL.90).aspx

DECLARE @BinVar varbinary(128)
SET @BinVar = CAST(REPLICATE( 0x20, 128 ) AS varbinary(128) )
SET CONTEXT_INFO @BinVar

SELECT CONTEXT_INFO() AS MyContextInfo;
GO

一旦超出动态批处理的范围,临时表就不再存在了

临时表的范围scope

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

跟踪临时表统计信息的基数(唯一值个数)

重编译阀值recompilation threshold

F

持久表的重编译阀值RT
如果n<=500,则RT=500;n=当编译查询计划时表的基数
如果n>500,则RT=500+0.20*n


临时表的重编译阀值RT:
n<6 则RT=6;
如果6<=n<=500,则RT=500;
如果n>500,则RT=500+0.20*n

 

优化器不会为表变量创建统计信息!!但是优化器会保存表变量的行计数信息,在sysindexes表和sys.partition表

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

你可以自己使用recompile提示强制重编译表变量

F

临时表名称解析 name resolve

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

proc1

proc2

在两个存储过程中命名相同名字的临时表,并在的存储过程1里调用存储过程2,报错
当存储过程2的临时表被缓存的时候,不会报错,当缓存失效,那么发生重编译的时候,还会继续报错

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

在动态SQL中修改临时表架构的解决办法

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

由于全局临时表是所有会话访问,你不能创建多个同名的全局临时表

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

创建一个不属于任何会话的全局临时表,这时,不论哪个会话打开或关闭,他总是存在,只有显式的删除他才会被移除。
你可以在一个特殊的存储过程中(使用sp_前缀,在master中创建)该存储过程使用startup选项标记该存储过程。sqlserver会在每次启动时调用启动过程startup procedure
而且,sqlserver为在启动过程中创建的全局临时表维护一个大于0的引用计数器,这样就确保sqlserver不会尝试去自动删除他

 

--创建不会自动删除的全局临时表 
USE [master]
GO
IF OBJECT_ID('dbo.sp_Globals') IS NOT NULL
DROP PROC dbo.sp_Globals
GO

CREATE PROC dbo.sp_Globals
AS
CREATE TABLE ##Globals
(
varname sysname NOT NULL
PRIMARY KEY ,
val SQL_VARIANT NULL
)
EXEC sys.[sp_procoption] @ProcName = N'sp_Globals', -- nvarchar(776)
@OptionName = 'startup', -- varchar(35)
@OptionValue = 'true' -- varchar(12)

 

 ##Globals是一个全局共享的临时表,可以维护跨会话的全局变量

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

表变量的限制条件

表变量只能创建primary key和unique约束
表变量创建后不能改变架构
sql2000不能对表变量执行select into和insert exec
sql2005 支持对表变量执行insert exec
不能使用表变量的别名名称 例如select t.a from @tb as t
表变量不使用并行计划

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

SELECT [TABLE_NAME]
FROM [tempdb].[INFORMATION_SCHEMA].[TABLES]
WHERE [TABLE_NAME] LIKE '%#%'

DECLARE @T TABLE(col1 INT)
INSERT INTO @T VALUES(1)

SELECT [TABLE_NAME]
FROM [tempdb].[INFORMATION_SCHEMA].[TABLES]
WHERE [TABLE_NAME] LIKE '%#%'

#A1E86A5D是临时表名称

F

表变量范围只能在当前级别的当前批处理内

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

如果语句是外部事务的一部分,外部事务回滚后,对表变量已经完成的更改将不可撤销,表变量在这一点上是独一无二的

表变量涉及更小的日志操作和锁操作

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

spool数据,排序,行版本都放在tempdb

最理想的磁盘划分是
数据文件使用RAID10,事务日志使用RAID1

SQL2005的tempdb初始大小是8MB,并且不能改变initial size

《Tempdb initial size和dbcc shrinkfile》

http://www.cnblogs.com/stswordman/p/3358496.html

SQL2008才可以,那么下面这句话是不是有错

改变tempdb数据文件的size参数,当重启sql后,以定义的大小创建tempdb

 

SQL2012的tempdb初始大小还是8MB

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

sql重启之后保留tempdb的对象
方法一:在model库里创建
方法二:创建启动存储过程

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

sqlserver不会物化表表达式

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

在范围和可见性方面,派生表和CTE只对当前语句有效,而视图和UDF对所有有权限访问他们的用户有效

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

各种临时对象的比较

临时表

表变量

表表达式

-------------------------------------------------

范围/可见性

是否在tempdb中有物理显示

受外部事务回滚影响

是否支持统计信息/重编译/高效执行计划

表大小

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

使用XML的path方法会更快,只用了7秒钟

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

第三章 游标

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

游标和关系模型的主要前提有冲突,使用游标,你可以应用过程逻辑代替基于集合的逻辑

游标可以接受有序数据作为输入,而查询只能接受关系输入

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

游标不好的地方有两个
1、游标强制优化器执行固定计划,并没有给优化器太多余地,至少没有基于集合的解决方案多
2、逐行操作产生大量开销

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

使用了FAST_FORWARD游标依然比基于集合的操作慢十倍

cold cache:冷缓存

warm cache:暖缓存

 

游标对于解决过程性的问题非常有用,这种问题要求你必须单独处理每一行

在测试该解决方案的性能,确保选中SSMS中的“执行后放弃结果选项”

f

SSMS的alwayson选项

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

阻止保存要求重新创建表的更改

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

执行后放弃结果

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

SQL-92查询标准

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

SELECT @@ROWCOUNT
SELECT ROWCOUNT_BIG

基于排序数据的游标解决方案也会受益于索引,如果没有索引,这种方案也非常慢
因为扫描数据后还需要对数据排序,因为排序的时间复杂度是0(n log n) ,而扫描仅仅是0(n)

 

 按顺序访问

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

自定义聚合

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

解决连续聚合问题的基于集合的解决方案会多次扫描数据,而基于游标的方案只扫描一次数据

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

SUM(QTY) OVER (PARTITION BY EMPID ORDER BY ORDERMONTH) 实现连接聚合

SELECT  empid ,
        CONVERT(VARCHAR(7), ordmonth, 121) AS ordmonth ,
        qty ,
        SUM(qty) OVER ( PARTITION BY empid ORDER BY ordermonth ) AS runqty
FROM    emporders

 

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

between and 和大于小于的区别,大于小于更灵活,>= 或者>
ts>= starttime and st<endtime

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

匹配问题

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

第四章 动态SQL 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

通常sp_executesql更具优势,因为他提供了输入/输出接口,而exec没有

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

下面的代码尝试在括号中调用QUOTENAME函数以引用对象名称
把代码构造到一个变量中,这样就不会受限制了

exec不提供接口

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

串联变量的内容存在性能方面的弊端,sqlserver将为每个唯一的查询字符串创建新的即席执行计划adhoc execution plan,

即使查询模式相同也是这样,执行计划不能缓存

 

SELECT  [cacheobjtype] ,
        [objtype] ,
        [usecounts] ,
        [sql]
FROM    sys.[syscacheobjects]
WHERE   [sql] NOT LIKE '%cache%'
        AND [sql] NOT LIKE '%sys.%'

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

因为exec()没有输出,那么需要使用insert exec语法把输出插入到一个目的表

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

临时表在动态sql内部和外部都可以用,但是需要在外部create一下

USE [sss]
DECLARE @tablename AS NVARCHAR(128)
DECLARE @sql AS NVARCHAR(800)
DECLARE @cnt AS INT

SET @tablename = 'testrow'
SET @sql = 'insert into #T(cnt) select count(*) from ' + QUOTENAME(@tablename)

CREATE TABLE #T ( CNT INT )
EXEC(@SQL)
SET @CNT = ( SELECT CNT   FROM   [#T] )
SELECT  @cnt


SELECT  COUNT(*)
FROM    TESTROW 

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

尽管技术上,sp_executesql的输入代码字符串是NTEXT类型
所以sp_executesql中执行的查询字符串被限制为Unicode字符串nvarchar支持的最大长度:4000个字符

而exec支持常规字符串varchar,允许最大8000个字符

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

在sql2005中支持varchar(max)和nvarchar(max),支持最大2GB大小
varchar(max)支持二十亿个字符
nvarchar(max)支持十亿个字符

EXEC AT:sql2005引入了EXEC AT语法,允许你在linked server执行动态sql

 

在sql2000的时候只能使用openquery和openrowset来在linked server执行代码
openquery有很多限制,输入字符串不能是变量,不接受参数

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

EXEC(
'select productid,productname,unitprice
from products
where productid=?;',3) AT dojo

 

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

对access数据库执行transform查询

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

sp_executesql比exec引入晚一些,他主要为重用执行计划提供更好的支持

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

SELECT [cacheobjtype] ,
[objtype] ,
[usecounts] ,
[sql]
FROM sys.[syscacheobjects]
WHERE [sql] NOT LIKE '%cache%'
AND [sql] NOT LIKE '%sys.%'
AND [sql] NOT LIKE '%sp_executesql%'

查询执行计划缓存,sqlserver只生成了一个prepared plan,而exec生成了3个adhoc plan

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

把二进制值转换为字符串的函数

DECLARE @b AS VARBINARY(1000)
SET @b = 0x0123456
SELECT  SYS.[fn_varbintohexstr](@b)

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

--内部批处理不影响外部批处理的数据库上下文
USE [AdventureWorks]
DECLARE @db AS NVARCHAR(200)
SET @db=QUOTENAME('sss')
EXEC('USE'+@DB+';EXEC(''SELECT DB_NAME()'');')

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

使用动态sql的场景

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

sql2005联机丛书中的索引碎片整理的示例代码,在msdn上面也有

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

碎片级别大于30%重建索引,小于30%重组索引

30%是为了演示而任意选择的,你应该根据查询性能和有效的维护周期使用自己的临界值,维护窗口

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

使用触发器的inserted表和sp_executesql存储过程可以把方法看起来像excel电子表格

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

SELECT COLUMNS_UPDATED()

SELECT COLUMNS_UPDATED()函数检查表中的列是否有被修改,该函数是一个位图bitmap,

其中每一位表示一列,对于update语句,如果某列包含在update语句的set子句中,则相应的位为开启状态1,对于insert语句,所有的列都为开启状态

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

http://www.users.drew.edu/SKASS/SQL/INFIX.SQL.TXT

http://www.users.drew.edu/SKASS/

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

动态sql 的动态筛选器

动态sql可以获得高效的执行计划,把输入定义为参数,甚至可以高效地重用执行计划

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

create proc usp_getorders

with recompile

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

拼接sql,where1=1

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

SELECT  [cacheobjtype] ,
        [objtype] ,
        [usecounts] ,
        [sql]
FROM    sys.[syscacheobjects]

 

F

动态pivot和unpivot,处理数量未知的被旋转元素

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

--检查 @col是否存在SQL注入尝试
--当示例扩展到用于串联字符串时使用
--
IF UPPER(@col) LIKE UPPER(N'%0x%')
    OR UPPER(@col) LIKE UPPER(N'%;%')
    OR UPPER(@col) LIKE UPPER(N'%''%')
    OR UPPER(@col) LIKE UPPER(N'%--%')
    OR UPPER(@col) LIKE UPPER(N'%/*%*/%')
    OR UPPER(@col) LIKE UPPER(N'%exec%')
    OR UPPER(@col) LIKE UPPER(N'%xp[_]%')
    OR UPPER(@col) LIKE UPPER(N'%sp[_]%')
    OR UPPER(@col) LIKE UPPER(N'%select%')
    OR UPPER(@col) LIKE UPPER(N'%insert%')
    OR UPPER(@col) LIKE UPPER(N'%update%')
    OR UPPER(@col) LIKE UPPER(N'%delete%')
    OR UPPER(@col) LIKE UPPER(N'%truncate%')
    OR UPPER(@col) LIKE UPPER(N'%create%')
    OR UPPER(@col) LIKE UPPER(N'%alter%')
    OR UPPER(@col) LIKE UPPER(N'%drop%')
--其他一些用于SQL注入的字符串
    BEGIN
        RAISERROR('possible sql injection attempt',16,1)
        RETURN
    END

 

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

这里使用[INFORMATION_SCHEMA].[COLUMNS]来动态获取表的各个列名

SELECT  *
FROM    [INFORMATION_SCHEMA].[COLUMNS]
WHERE   [TABLE_SCHEMA] = 'dbo'
        AND [TABLE_NAME] = 'pvtcustorders'
        AND [COLUMN_NAME] NOT IN ( 'cusid' )

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

防止sql注入
1、减少攻击面,不开xp_cmdshell等功能

2、使用足够权限的登录用户连接数据库,不要用高权限,例如sa
在sql2005中,你可以模拟用户,甚至可以在服务器上把新的凭据credential应用于动态调用的代码,于此同时,这也为黑客打开了一个全新的机会之窗,动态sql可以在模拟用户的凭据下运行,甚至不需要该用户有执行存储过程的直接权限

3、使用模式匹配检查输入参数,例如单引号,破折号等

4、限制输入的长度

5、使用存储过程

6、避免使用动态SQL

7、当你引用输入时,不要直接使用,应该使用QUOTENAME()函数,如果想更安全
用CHAR(39)+ CHAR(39)代替CHAR(39)

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

--SQL注入
DECLARE @lastname AS NVARCHAR(40) 
DECLARE @sql AS NVARCHAR(200)
SET @lastname = N'''drop database sss'
SET @sql = N'select * from employees where lastname=' + QUOTENAME(@lastname,
                                                              '''') + ';'
PRINT @sql
select * from employees where lastname='''drop database sss';

--没有SQL注入
DECLARE @lastname AS NVARCHAR(40) 
DECLARE @sql AS NVARCHAR(200)
SET @lastname = N'lily'
SET @sql = N'select * from employees where lastname=' + QUOTENAME(@lastname,
                                                              '''') + ';'
PRINT @sql
select * from employees where lastname='lily';

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

第五章 视图

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

1、不能在视图定义中使用order by,除非定义中包含top或for xml说明符
2、所有的结果列必须有名称
3、所有结果列的名称必须是唯一的

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

EXISTS只关心行是否存在,而不引用行的属性,select 列表可以被完全忽略
下面代码运行时不会有任何错误

IF EXISTS(SELECT 1/0) PRINT 'no error'
no error

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

视图中的order by

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

创建视图时,sqlserver会保存元数据信息在系统表中,包括列名,视图定义,安全,依赖等信息
基表的架构更改不影响视图的元数据信息,更改基表架构后,使用EXEC sys.[sp_refreshview] @viewname = N'' -- nvarchar(776)刷新视图的元数据信息是个好习惯

EXEC sys.[sp_refreshview] @viewname = N'' -- nvarchar(776)

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

使用下面的动态sql刷新没有绑定架构的视图schema-bound

USE [sss]
SELECT N'EXEC sys.sp_refreshview ' + QUOTENAME(VIEW_NAME, '''') + ';' AS CMD
FROM ( SELECT QUOTENAME(TABLE_SCHEMA) + N'.' + QUOTENAME(TABLE_NAME) AS VIEW_NAME
FROM [INFORMATION_SCHEMA].[VIEWS]
) AS V
WHERE OBJECTPROPERTY(OBJECT_ID([VIEW_NAME]), 'IsSchemaBound') = 0


--SELECT * FROM [INFORMATION_SCHEMA].[VIEWS]
SELECT OBJECTPROPERTY(OBJECT_ID('ABC'), 'IsSchemaBound')

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

SELECT SIGN()

SIGN函数在输入为正时返回1,输入为0时返回0,输入为负时返回-1,输入NULL返回NULL

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

更新视图 update对基表进行

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

行级安全

Implementing Row- and Cell-Level Security in Classified Databases Using SQL Server 2005 

 

f

修改视图有下列限制


只要视图有一列不能隐式获取值,就不能向视图插数据

视图是join 的话,修改只能修改一端

不能修改视图的计算列,聚合,标量表达式

如果在创建或修改视图时指定了with check option选项,与视图查询筛选器有冲突的insert或update语句将拒绝

对视图定义了instead of触发器,违反上面这些限制的数据修改语句可以被执行

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

SELECT  keycol ,
        datacol
FROM    [dbo].userdata
WHERE   loginname = SUSER_NAME()
DENY SELECT ,INSERT,UPDATE,DELETE ON [dbo].userdata TO PUBLIC
GRANT SELECT ,INSERT,UPDATE,DELETE ON [dbo].userdata TO PUBLIC

 

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

视图选项

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

encryption选项
未指定encryption选项,sqlserver会在[sys].[sql_modules](在sql2000中是sys.[syscomments])以纯文本形式保存用于定义对象/程序主体的语句

所以sys.[sp_refreshview] 存储过程内部执行的是sys.sp_refreshsqlmodule_internal

EXEC sys.[sp_refreshview] @viewname = N'' -- nvarchar(776)

SET QUOTED_IDENTIFIER OFF
SET ANSI_NULLS OFF
GO
create procedure sys.sp_refreshview
@viewname    nvarchar(776)
as
declare @ret int
exec @ret = sys.sp_refreshsqlmodule_internal @viewname, N'OBJECT', 1 -- viewonly
return @ret
GO

 

f

 

schemabinding选项

如果视图已经存在,使用ALTER VIEW命令比删除视图后重建视图更明智,因为ALTER VIEW可以保持权限!!

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

在子查询中使用了常量1代替*,这样就符合了schemabinding选项的要求

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

check option

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

没有check option的话,有join约束也不用怕

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

有check option的话,insert插入就会失败,一定要两表都要有数据

 

view_metadata

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

在sql2000的企业管理器里的视图图形界面修改视图数据,使用sql profiler来跟踪发现企业管理器实际上是对基表进行操作

但是在sql2005里的SSMS则会失败

USE [AdventureWorks]
CREATE VIEW Vcustswithorders
WITH ENCRYPTION,SCHEMABINDING,VIEW_METADATA
AS 
SELECT [Sales].[CustomerAddress]
FROM [Person].[Address] AS c
JOIN b AS b
ON [AddressID].sdf=[c].sdf
WITH CHECK OPTION 
GO

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

索引视图

SCHEMABINDING选项创建索引视图,必须为对象名称使用两部分命名约定,并在select列表中显式指定列名称

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

sqlserver企业版和开发版功能一样

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

如果使用企业版,直接查询基表的语句跟定义索引视图的sql语句一样,那么sqlserver会查询索引视图

如果你使用非SQLSERVER企业版或开发版,默认情况下,即使你直接查询视图,也不会考虑使用索引视图,这时,要使用索引视图,

你必须指定NOEXPAND提示

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

integrity rule完整性规则

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

当允许多个null,但是不想允许有重复值的列的时候可以考虑使用索引视图来做约束

 

为什麽使用索引视图可以减少I/O,首先索引视图就是基表,在定义索引视图的时候,索引视图的列的数量一般会比定义他的基表的列数量要少,

这样的话,那么索引视图的页面一页能容纳更多的数据行,这样的话,读取索引视图的I/O就会比定义他的基本要少!!

F

第六章 用户定义函数

sql2000引入UDF 用户定义函数

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

内联表值函数跟视图非常相似,唯一不同是他可以接收参数

创建函数时可以指定RETURNS NULL ON NULL INPUT或者CALLED ON NULL INPUT(默认值)
RETURNS NULL ON NULL INPUT:函数的参数为null时返回null
CALLED ON NULL INPUT:无论是否为null都调用函数

创建函数时指定SCHEMABINDING和RETURNS NULL ON NULL INPUT选项是一个好习惯

SCHEMABINDING:防止删除基础对象和修改引用列

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

当操作的主要成本来自基于集合的操作而不是过程计算时,TSQL-UDF比CLR-UDF快

聚合串联(aggregate concatenation)技术

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

字符串串联

串联订单ID

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

在sql2005你可以使用for xml path,并用一个空字符串作为其输入来完成字符串串联

UDA:用户定义聚合函数

sql2000中扩展了tsql的语法,将查询结果作为xml输出
for xml raw
for xml auto
for xml explicit

 

sql2005 for xml改进
利用type选项,for xml可以从使用 for xml的select语句中输出,他还允许将select...for xml
的结果嵌套在另一个select语句中
利用新选项for xml path 可以更容易整理数据,生成基于元素的xml

xpath 测试函数
data
comment
node
text
处理指令

精通SQL Server2008程序设计 笔记

SET NOCOUNT ON
SELECT CustomerID,
(SELECT CAST(OrderID AS VARCHAR(10))+';' AS [text()]
FROM dbo.Orders AS O
WHERE O.CustomerID=C.CustomerID
ORDER BY OrderID
FOR XML PATH('')) AS Orders
FROM dbo.Customers AS C

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

在SSMS中启用“执行后放弃结果”选项,这样你的统计结果将不包含生成输出所花费的时间

USE [sss]
--开启执行查询后放弃结果
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
SET STATISTICS TIME ON
SELECT  *
FROM    [dbo].[aaa]
SET STATISTICS TIME OFF



 --SQL Server 执行时间:
 --  CPU 时间 = 0 毫秒,占用时间 = 2 毫秒。

--不开启执行查询后放弃结果
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
SET STATISTICS TIME ON
SELECT  *
FROM    [dbo].[aaa]
SET STATISTICS TIME OFF

 --SQL Server 执行时间:
 --  CPU 时间 = 0 毫秒,占用时间 = 4 毫秒。

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

内联表达式

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

如果你在查询中使用内联表达式实现计算并避免使用UDF,通常会好些

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

在约束中使用UDF

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

索引准则(indexing guideline)
在计算列上创建UDF约束,那么在创建UDF时需要使用SCHEMABINDING,计算列必须具有确定性和精确的,并且要指定持久的

CREATE TABLE a
(id AS MIN(1) PERSISTED)

后续添加计算列

--添加计算列
ALTER TABLE [dbo].[aaa] ADD col1 AS MIN([a]) CONSTRAINT UQ_AAA_COL1 UNIQUE

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

ALTER TABLE [T1]
ADD COL2 AS FN_ADD(KEYCOL) PERSISTED NOT NULL
CONSTRAINT PK_T1 PRIMARY KEY

persisted选项是sql2005中新增的,在sql2000中,要在计算列上创建主键约束,你必须使用isnull函数封装对UDF的调用

ALTER TABLE [T1]
ADD COL2 AS ISNULL(FN_ADD(KEYCOL),0) 
CONSTRAINT PK_T1 PRIMARY KEY

 

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

TSQL不擅长处理:复杂计算,遍历,过程逻辑,字符串处理,操作系统资源访问等,交由CLR来处理

TSQL是一种声明式语言declarative language

F

CLR开发正则表达式

具有确定性

计算列不具有确定性

http://support.microsoft.com/kb/2380361

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

开启CLR选项意味着整个SQL实例都可以运行CLR程序集,这会有风险
在create assembly的时候指定permission_set,选项设置为safe,external_access,unsafe

safe:默认
external_access:以sqlserver服务账户身份运行并访问此账户的外部资源
unsafe:在sqlserver进程空间中执行任意操作,会破坏clr和sqlserver的安全系统
只有sysadmin角色才能修改unsafe程序集

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

如果你修改了程序集,你需要执行alter assembly或drop,create assembly命令来重新把IL代码加载到数据库

 

注册CLR函数

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

你可以在网上找到更多的正则表达式:http://www.regexlib.com/

正则表达式大全网站

检查E-mail地址是否有效

写出更健壮正则表达式的网站

http://www.regular-expressions.info/

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

匹配jpg文件的正则表达式,包含在创建表的check约束里面

F

显式转换 隐式转换
.NET 本机类型(native type)和.NET SQL类型

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

建议在CLR对象的.NET代码中使用.NET 的SQL类型而不要使用本机类型
sql类型SqlString
本机类型string

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

显式转换 和隐式转换的性能差别不大

C#里面sqlstring和string的比较

F

sql 签名 signature

sql签名的tsql实现  是sqlserver cat的成员 stuart ozer

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

http://www.microsoft.com/about/legal/en/us/Copyright/Default.aspx

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

C#代码的数据类型sql类型不是本机类型与TSQL代码的数据类型的对应

存入数据库
            myCommand.Parameters.Add("@VC_A_SNNO", SqlDbType.VarChar).Value = VC_A_SNNO;
            myCommand.Parameters.Add("@VC_OC_UserName", SqlDbType.VarChar).Value = VC_OC_UserName;
            myCommand.Parameters.Add("@VC_OC_Company", SqlDbType.VarChar).Value = VC_OC_Company;
            myCommand.Parameters.Add("@VC_A_CardNO", SqlDbType.VarChar).Value = VC_A_CardNO;
            myCommand.Parameters.Add("@CardType", SqlDbType.Int).Value = CardType;
            myCommand.Parameters.Add("@VC_A_AppendType", SqlDbType.VarChar).Value = VC_A_AppendType;
            myCommand.Parameters.Add("@VC_TicketType", SqlDbType.VarChar).Value = VC_TicketType;
            myCommand.Parameters.Add("@VC_TicketNO", SqlDbType.VarChar).Value = VC_TicketNO;
            myCommand.Parameters.Add("@StartDate", SqlDbType.VarChar).Value = StartDate;
            myCommand.Parameters.Add("@EndDate", SqlDbType.VarChar).Value = EndDate;
            myCommand.Parameters.Add("@TotalRecords", SqlDbType.Int).Value = TotalRecords;
            myCommand.Parameters.Add("@PageIndex", SqlDbType.Int).Value = PageIndex;

            myConnection.Open();
            PageSetInfo _CT_AppendSetInfo = new PageSetInfo();



从数据库取出
     private CT_AppendInfo Populate(SqlDataReader dr)
        {
            CT_AppendInfo _CT_AppendInfo = new CT_AppendInfo();

            _CT_AppendInfo.VC_A_SNNO = Convert.ToString(dr["VC_A_SNNO"]);
            _CT_AppendInfo.VC_A_AppendType = Convert.ToString(dr["VC_A_AppendType"]);
            _CT_AppendInfo.VC_A_CardNO = Convert.ToString(dr["VC_A_CardNO"]);
            _CT_AppendInfo.I_A_CardType = Convert.ToInt32(dr["I_A_CardType"]);
            _CT_AppendInfo.I_A_CardTypeName = Filter.CardTypeToStr(_CT_AppendInfo.I_A_CardType);
            _CT_AppendInfo.I_A_PointToOil = Convert.ToInt32(dr["I_A_PointToOil"]);
            _CT_AppendInfo.VC_TicketType = Convert.ToString(dr["VC_TicketType"]);
            _CT_AppendInfo.VC_TicketNO = Convert.ToString(dr["VC_TicketNO"]);
            _CT_AppendInfo.DE_A_BAmount = Convert.ToDecimal(dr["DE_A_BAmount"]);
            _CT_AppendInfo.DE_A_AppendAmount = Convert.ToDecimal(dr["DE_A_AppendAmount"]);
            _CT_AppendInfo.DE_A_AAmount = Convert.ToDecimal(dr["DE_A_AAmount"]);
            _CT_AppendInfo.D_A_AppendDateTime = Convert.ToDateTime(dr["D_A_AppendDateTime"]);
            _CT_AppendInfo.VC_A_Remark = Convert.ToString(dr["VC_A_Remark"]);
            _CT_AppendInfo.VC_A_OperatorNO = Convert.ToString(dr["VC_A_OperatorNO"]);

            return _CT_AppendInfo;
        }

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

在字符串处理方面,.NET代码比TSQL代码更快,尤其是两个版本实现的是同一个算法,你马上就能看到他们在字符串处理方面的性能差异

F

clr版本比T-SQL版本快100倍

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

clr函数

CREATE FUNCTION fn_RegExReplace(@input AS NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
WITH RETURNS NULL ON NULL INPUT
EXTERNAL NAME xxx.fn_RegExReplace

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

你可能想创建一些有广泛用途的函数
你可以使用同义词功能和model数据库的功能

在每个数据库中创建一个该函数的同义词,就可以调用该函数,而不需要在每个库中创建该函数

USE [AdventureWorks2008]
CREATE SYNONYM [dbo].fn_RegExReplace
FOR clutit.dbo.fn_RegExReplace

 

在model数据库中创建该函数,就可以在新建数据库和tempdb中定义好该函数

 

表值UDF
内联表值 UDF INLINE TABLE-VALUED UDF
多语句表值UDF MULTISTATEMENT TABLE-VALUED UDF
CLR表值UDF

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F


内联表值UDF跟视图是很相似的,但是内联表值UDF可以输入参数

内联表值udf也是展开udf的定义并生成一个访问基表的执行计划
不同于标量udf和多语句表值udf,不能在内联udf里使用begin/end块

CREATE FUNCTION [dbo].fn_GetCusorders ( @cid AS NCHAR(5) )
RETURNS TABLE
AS 
RETURN
SELECT *
FROM [Department]
GO

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

可以修改内联UDF,最终修改的还是基表

UPDATE fn_GetCusorder(N'alfki') SET shipvia=2

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

当然你有权限的话,也可以执行删除操作

DELETE FROM fn_GetCusorder(N'alfki') WHERE YEAR(orderdata)=1997

 

F

拆分数组 split array

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

使用这个拆分函数来拆分字符串,可以缓存执行计划,而用动态sql的话不会缓存执行计划

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

函数头把FillRowMethodName属性设置为"ArrSplitFillRow"
ArrSplitFillRow是一个方法,他把输入的对象转换为字符串,函数头还用TableDefinitin属性定义了输出表的架构,只在使用VS自动部署该函数时才需要该属性,如果你用TSQL手工部署这个函数,不需要指定这个属性

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

stringsplitoptions.removeemptyentries选项,使返回值不包含为空字符串的数字元素

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

CLR版的字符串拆分函数比TSQL版的字符串拆分函数快1倍!

F

多语句表值UDF是一种返回表变量的函数

sqlserver对内联udf像视图,对多语句表值udf像存储过程,你不能对多语句表值udf进行update,delete

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

多语句表值UDF

sql2000版本

CREATE FUNCTION [dbo].fn_subordinates ( @mgrid AS INT )
RETURNS @subs TABLE
    (
      empid INT NOT NULL
                PRIMARY KEY NONCLUSTERED ,
      mgrid INT NULL ,
      empname VARCHAR(255) NOT NULL ,
      salary MONEY NOT NULL ,
      lvl INT NOT NULL ,
      UNIQUE CLUSTERED ( lvl, empid )
    )
AS
    BEGIN
        DECLARE @lvl AS INT;
        SET @lvl = 0
    END
RETURN;

sql2005版本

CREATE FUNCTION [dbo].fn_subordinates ( @mgrid AS INT )
RETURNS  TABLE
AS
RETURN
WITH subsCTE AS (XX)
SELECT * FROM subsCTE
GO;

 

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

cte体中的第二个查询包含一个指向自身的递归引用

递归调用最好用CTE,不断获取下层

F

逐行调用udf

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

不确定性函数,当用相同的参数多次调用他时,他不保证返回相同的输出
例如 rand() getdate()函数

F

 rand()  getdate()函数这些不确定性函数在查询中只被调用一次,而不是每行都调用,唯一的例外是newid()函数

USE [sss]

SELECT  RAND() AS rnd ,
        GETDATE() AS dt ,
        NEWID() AS guid ,
        [name]
FROM    [dbo].[aaa]

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

如果想每行都调用rand函数可以使用udf

可以使用偏方,创建一个视图,该视图调用rand()函数,然后在udf中查询该视图

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

sql2000不允许在udf中调用不确定函数
sql2005检查udf的属性以区分他是否会产生副作用,sql2005更宽容一些

F

在sql2000中你不能在udf中调用getdate函数
sql2005中可以在udf中调用getdate函数

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

第七章 存储过程

存储过程允许有副作用(side effect)也就是收他可以修改表中数据和修改对象架构

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

用户定义存储过程

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

调用存储过程最好加架构名前缀
解析顺序
当前库sys架构
调用方默认架构
当前库的dbo架构

 

如果存储过程未指定架构名称,这些连接会因为要获取编译锁(compile lock)而互相阻塞

 

sql2005 技术内幕 存储引擎笔记

编译锁
support.microsoft.com/?id=263889

 

SELECT [resource_type] FROM sys.[dm_tran_locks]
SR (subresource)
如果锁存在于一个数据库资源上,SR表示下列之一
完全数据库级锁
容量操作锁
如果锁存在于表资源上,SR表示下列之一
完全表级锁(默认)
更新统计锁
编译锁
如果锁存在于索引资源上,SR表示下列之一:
完全索引锁(默认)
索引ID锁
索引名字锁

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

只能使用存储过程,而不能直接查询表数据能控制权限

DENY SELECT ON [dbo].[aaa] TO [db_accessadmin]
GRANT EXECUTE ON [dbo].[usp_GetFreeSpace] TO user1

安全模型

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

使用分号是一个好习惯,分号为所有语句添加后缀,避免歧义

F

微软强烈建议不要使用SP_前缀创建你的自己的存储过程!!

特殊存储过程sp_开头

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

以sp_开头的表名,即使切换数据库,也可用找到该表,但是在sql2012里测试已经不行了

USE [sss]
CREATE TABLE dbo.sp_Globs
    (
      var_name sysname NOT NULL
                       PRIMARY KEY ,
      val SQL_VARIANT NULL
    )
INSERT dbo.sp_Globs
SELECT 'nih','1'

USE [tempdb]
SELECT * FROM dbo.sp_Globs

--消息 208,级别 16,状态 1,第 2 行
--对象名 'dbo.sp_Globs' 无效。


USE [AdventureWorks]
SELECT * FROM dbo.sp_Globs

--消息 208,级别 16,状态 1,第 2 行
--对象名 'dbo.sp_Globs' 无效。

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

 

F

系统存储过程

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

系统存储过程是微软内置在产品中的存储过程,在sql2000中,系统存储过程位于master数据库,以sp_开头,并标记为“system”(MS Shipped)
在sql2005中,系统存储过程在物理上位于一个内部隐藏的资源数据库resource库中,逻辑上存在于每个数据库中

SELECT [is_ms_shipped] FROM sys.[objects]
SELECT [is_ms_shipped] FROM sys.[triggers]
SELECT [is_ms_shipped] FROM sys.[procedures]

特殊存储过程(使用sp_前缀,在master中创建)也被标记为系统存储过程,并具备一些独特的行为,当sqlserver的安装程序运行安装脚本以创建系统存储过程时,安装脚本使用未公开的存储过程sp_MS_marksystemobject把这些特殊存储过程标记为系统存储过程

不应该在产品环境中使用sp_MS_marksystemobject存储过程把用户存储过程标记为系统存储过程

在sql 2008r2安装包里找不到sp_MS_marksystemobject存储过程的脚本

 

 

--sql2005里面直接报没有sp_MS_marksystemobject文本
USE [master]
EXEC sys.[sp_helptext] @objname = N'sp_MS_marksystemobject'
--消息 15197,级别 16,状态 1,过程 sp_helptext,第 91 行
--没有对象 'sp_MS_marksystemobject' 的文本。
--sql2012里面不能够使用ctrl+T的方式显示文本,只能用网格显示sp_MS_marksystemobject存储过程文本
--然后拷到新建查询窗口里,分析语法和用sql prompt
-- 允许配置高级选项
EXEC sp_configure 'show advanced options', 1
GO
-- 重新配置
RECONFIGURE
GO
-- 启用xp_cmdshell
EXEC sp_configure 'xp_cmdshell', 1
GO
--重新配置
RECONFIGURE
GO

--执行想要的xp_cmdshell语句
Exec xp_cmdshell 'query user'
GO


USE [sss]
CREATE TABLE tbtxt(txt NVARCHAR(MAX))

INSERT INTO tbtxt  EXEC sys.[sp_helptext] @objname = N'sp_MS_marksystemobject'

SELECT [txt] FROM [tbtxt]

exec master.. xp_cmdshell 'bcp " select txt from [sss].[dbo].[tbtxt] " queryout d:\sp_MS_marksystemobject.txt -c -U "sa" -P "ttttttt"'

sp_MS_marksystemobject存储过程内容

---------------------------- sp_MS_marksystemobject -----------------------------                                                    
-- FOR INTERNAL USE ONLY ... DO NOT DOCUMENT --                                                    
--#NAME?                                                    
----    groups (starfigther, davinci, replication) use it for different things                                                
--#NAME?                                                    
--    not have this bit set.  Use at your own risk.                                                
--                                                       
                                                    
CREATE PROCEDURE sys.sp_MS_marksystemobject
    @objname NVARCHAR(517) ,  -- 517 is max for two part name                                                
    @namespace VARCHAR(10) = NULL        --#NAME?                                    
AS
    SET NOCOUNT ON                                                    
                                                    
    DECLARE @objid INT                                            
                                                    
    DECLARE @owner sysname ,
        @ns INT ,            --#NAME?                    
        @object sysname                                    
                                        
    -- ============================================================                                                
    -- DEVNOTE:                                                
    --    x_eonc_TrgOnServer        = 20,    // Namespace for Triggers on the Server                                
    --    x_eonc_TrgOnDatabase    = 21,    // Namespace for Triggers on Databases                                    
                                                    
    --#NAME?            0        // Standard Namespace                            
    -- ============================================================                                                
                                        
    IF NOT ( @namespace IS NULL )
        BEGIN                                                
                                                    
            SELECT  @ns = ( CASE LOWER(@namespace)
                              WHEN 'server' THEN 20
                              WHEN 'database' THEN 21
                            END )                                    
        END                                                
    ELSE
        BEGIN                                                
            SET @ns = 0 -- null means standard namespace                                            
        END                                                
                                        
                                                    
    IF @ns IS NULL
        BEGIN                                            
            RAISERROR('sp_MS_marksystemobject: Invalid NameSpace ''%ls''',0,1,@namespace)                                                RETURN (1)                                            
        END                                                
                                    
    -- CHECK THE OBJECT NAME --                                                    
                                                    
    SELECT  @object = PARSENAME(@objname, 1) ,
            @owner = PARSENAME(@objname, 2)                                        
                                                
    -- ============================================================                                                
    -- DEVNOTE:                                                
    --    x_eonc_TrgOnServer        = 20,    // Namespace for Triggers on the Server                                
    --    x_eonc_TrgOnDatabase        = 21,    // Namespace for Triggers on Databases                                
    -- ============================================================                                                
                                                    
    IF @ns = 20
        OR @ns = 21
        BEGIN                                                
            IF NOT ( @owner IS NULL )
                BEGIN                                            
            --#NAME?                                        
                    RAISERROR(1094,-1,-1)                                        
                    RETURN (1)                                        
                END                                            
        END                                                
                                        
                                                    
    IF @ns = 20
        BEGIN                                                
                                                    
            SELECT  @objid = object_id
            FROM    sys.server_triggers
            WHERE   name = @objname                                            
        END                                                
    ELSE
        IF @ns = 21
            BEGIN                                                
                                                    
                SELECT  @objid = object_id
                FROM    sys.triggers
                WHERE   name = @objname
                        AND parent_class = 0                                            
            END                                                
                                                    
        ELSE
            BEGIN                                                
                SELECT  @objid = OBJECT_ID(@objname, 'local')                                            
            END                                                
                                            
                                                    
    -- CHECK THE OBJECT OWNER (MUST BE DBO) --                                                    
    -- DO THE UPDATE --                                                    
                                                    
    BEGIN TRAN                                                
    IF NOT ( @objid IS NULL )
        BEGIN                                                
            IF @ns = 0
                BEGIN                                            
            EXEC %%Object(MultiName = @objname).LockMatchID(ID = @objid, Exclusive = 1, BindInternal = 0)                                        IF @@error <> 0
                        SELECT  @objid = NULL                                    
                    ELSE
                        BEGIN                                        
                            IF @owner IS NULL
                                SELECT  @owner = N'dbo'                                
                                                
                EXEC %%Object( Owner = @owner, Name = @object ).SetSystem()                                    
                                                
                        END                                        
                END                                            
                                                    
            ELSE
                BEGIN                                            
                                                    
            EXEC %%TriggerEx(MultiName = @objname).ValidateAndSetSystem(                                        
                                                    
                                                    ID = @objid, NameSpaceClass = @ns)
                END                                            
                                                    
        END                                                
                                                
    IF @objid IS NULL
        BEGIN                                                
            RAISERROR('sp_MS_marksystemobject: Invalid object name ''%ls''',0,1,@objname)                                                                        
            COMMIT TRAN                                            
            RETURN (1)                                            
        END                                                
                                                    
                                                    
    COMMIT TRAN                                                
    RETURN (0)    --#NAME?                                                

 

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

其他类型存储过程

1、临时存储过程#或##
2、扩展存储过程:允许使用C语言利用开放数据库服务open  data  service ODS API创建外部程序
sql2005支持扩展存储过程只是为了向后兼容,在以后sql版本中将不再支持,现在你可以使用CLR存储过程

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

存储过程接口,即输入,输出参数

F

SET NOCOUNT ON

 

SET NOCOUNT ON选项,一些数据库接口,例如OLEDB,会把该消息作为一个行集,你得到的第一个结果集将是关于受影响行数的消息,而你只想获取查询的结果集

存储过程的参数:命名格式和非命名格式

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

为存储过程的参数指定默认值

CREATE PROC usp_getaaa
(
@name AS NVARCHAR(20) = 'sdf969'
)
AS
SET NOCOUNT ON
SELECT *
FROM [dbo].[aaa]
WHERE [name] = @name
GO

EXEC usp_getaaa

或者

使用默认值

EXEC usp_getaaa DEFAULT

 

F

使用命名赋值格式是一个好习惯

EXEC usp_getaaa @name='sdf969'

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

存储过程的输出参数跟C语言的指针和C# ref类型 一样 从输入一直到输出

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

ADO编程逐个接收结果集,使用recordset对象的nextrecordset属性
而print和raiserror命令的输出,他们都由客户端通过接口结构接收,例如,ADO中的ERRORS集合

ADO.NET中使用SqlCommand对象,CommandType.StoredProcedure

 

ADO.NET中使用SqlCommand对象,CommandType.StoredProcedure
ADO.NET中的SqlDataReader类的NextResult方法遍历返回的行集
SqlCommand对象的Parameters集合接收输出参数

 

 

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F


SqlDataReader类的RecordsAffected属性,用于获取更新,插入,删除的行数,如果是select语句,不能使用该属性

严重级别大于10的错误,他们表示非常严重的错误

 

SqlExceptoin对象
SqlErrors对象

SqlErrors对象的number表示错误号,message表示错误消息

使用SqlConnection对象的InfoMessage事件获取存储过程中的警告

 

TSQL 中的print语句:可以使用SqlConnection对象的InfoMessage事件获取这类输出,或者使用try catch中catch块读取输出

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

DBCC输出:dbcc tableresults选项,使用SqlDataReader对象读取输出,就像读取行集一样
或者使用使用SqlConnection对象的InfoMessage事件获取输出

XML输出:SqlCommand对象的ExecuteXmlReader方法或者SqlDataReader对象

用户定义数据类型UDTs:ADO.NET完全支持UDT,

利用SqlDataReader获取行集架构:使用SqlDataReader的GetSchemaTable方法后去表架构

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

存储过程的解析阶段

F

如果对象根本不存在,sqlserver却可以创建存储过程,并且把解析过程推迟到调用存储过程时再执行,这种技术叫延迟名称解析 (deferred name resolution)

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

没有对象名的时候,创建存储过程不会检查对象名和对象的列名,存在对象的时候创建存储过程会检查对象名和对象的列名

创建存储过程usp_Proc2,引用已存在的T1表不存在的col2列,解析过程不会被推迟到运行时执行,因为T1表已经存在,但存储过程无法被创建

 

sqlserver通过计算查询优化阀值(threshold for optimization)来限制优化器只生成适合数量的执行计划供选项

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

优化器使用基数(cardinality)和密度(density)信息评估他要使用的访问方法的成本

在一个大型表里面,索引的级别可能有三,四级

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

一共是10次逻辑读2(seek)+2*4(lookups)=10

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

流程逻辑(flow logic)

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

修改存储过程,使用RECOMPILE,避免执行计划的不理想

USE [sss]
GO

ALTER procedure [dbo].[sp_MSupd_dboaaa] 
@c1 int = null,@c2 nvarchar(50) = null,@pkc1 int
,@bitmap binary(1)
WITH RECOMPILE
as
begin

end

 

当指定RECOMPILE 你找不到缓存的执行计划

SELECT * FROM sys.[syscacheobjects]
WHERE [sql] NOT LIKE '%cache%'
AND [sql] LIKE '%sp_MSupd_dboaaa%'

 


sql2000的话,使用下面语句

SELECT * FROM [master].[dbo].[syscacheobjects]
WHERE [sql] NOT LIKE '%cache%'
AND [sql] LIKE '%sp_MSupd_dboaaa%'

 

F

--sql2005支持语句级重编译 ,那么在要重编译的那个语句指定OPTION(RECOMPILE)就可以了
ALTER procedure [dbo].[sp_MSupd_dboaaa] 
 @c1 int = null,@c2 nvarchar(50) = null,@pkc1 int
,@bitmap binary(1)
as
begin
update [dbo].[aaa] set 
 [name] = case substring(@bitmap,1,1) & 2 when 2 then @c2 else [name] end
OPTION(RECOMPILE)
END


--sql2000不支持语句级重编译 ,只能在存储过程定义添加WITH RECOMPILE,这样会影响存储过程里面的所有语句!!
ALTER procedure [dbo].[sp_MSupd_dboaaa] 
 @c1 int = null,@c2 nvarchar(50) = null,@pkc1 int
,@bitmap binary(1)
WITH RECOMPILE
as
begin

end

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

重编译

《Microsoft SQL Server 2005技术内幕 查询、调整和优化笔记》

KEEP PLAN:正确性

KEEPFIXED PLAN:最佳性

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

SET CONCAT_NULL_YIELDS_NULL ON:表示当你用任意字符串和NULL串联时,得到的结果都为null

F

除了执行计划,sqlserver还会缓存查询结果的set选项

SELECT [setopts] FROM sys.[syscacheobjects]

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

 

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

当建立数据库连接时,客户端接口工具通常会更改一些set选项的状态,不同的客户端接口更改不同的set选项,

形成不同的执行环境,如果使用多个数据库接口工具连接数据库,而且他们拥有不同环境,你将无法重用其他应用程序的计划!!

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

参数嗅探

优化器无法“嗅探”出变量的内容,因此,优化器必须要猜测变量的值

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

解决参数嗅探的方法一:使用内联表达式代替变量,该表达式引用输入参数,而不是变量

解决参数嗅探的方法二:使用根存储过程(stub procedure),也就是创建两个存储过程,第一个存储过程

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

sql2005为你提供了一个新的查询提示OPTIMIZE FOR,该提示允许你为sqlserver提供一个字面值,

用于表示具有代表性的变量值,如果你知道变量通常是一个高选择性的值,可以提供一个字符串'9999991231'

 

USE [sss]
GO
/****** Object:  StoredProcedure [dbo].[usp_getaaa]    Script Date: 2014/9/18 7:24:14 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROC [dbo].[usp_getaaa]
    (
      @name AS NVARCHAR(20) = 'sdf969'
    )
AS
    SET NOCOUNT ON
    SELECT  *
    FROM    [dbo].[aaa]
    WHERE   [name] = @name
    OPTION(OPTIMIZE FOR(@name='sdf969'))


EXEC [usp_getaaa]

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

execute as

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

存储过程和基对象属于同一个架构
操作是静态的(不是有动态sql)
操作语句是dml(select,insert,update,delete)语句,或者执行另一个存储过程

F

sql2005可以吧存储过程安全上下文设置为其他用户的上下文,

就像其他用户在运行存储过程一样,创建存储过程时,你可以指定下列选项之一的execute as子句

1、caller(默认值)调用者的安全上下文
2、self创建或修改存储过程用户的安全上下文
3、owner数据库所有者的安全上下文
4、‘username’指定用户名称的安全上下文

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

此外,拥有模拟权限的用户可以提交一个独立的execute as<选项>命令以模拟另一个实体(登录用户或数据库用户)。

执行后,就好像当前会话的安全上下文被更改为所模拟实体的安全上下文

 

参数化排序

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

sqlserver更加表达式的结果中优先级最高的数据类型确定case表达式结果的数据类型,而不是按实际返回结果的数据类型确定,这就意味着,如果case表达式的一个then子句返回varchar(30),而另一个返回int值,表达式的结果将总是int,因为int的优先级比varchar高,如果实际返回varchar(30)值sqlserver将尝试转换他,如果该值不可转换,将产生一个运行时错误,如果可以转换,他被转换为int型,当然,可能会导致和原始值不一样的排序行为

 

解决方案一:把返回值都转换为SQL_VARIANT

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

FF

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

解决方案二:使用case when

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

解决方案三:使用动态sql

如果未验证输入可能会产生所有权链(ownership chaining)和sql注入问题

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

解决方案四:每种可能的排序方法都创建一个静态查询存储过程

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

动态Pivot

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

PIVOT运算符不支持*作为聚合函数的输入,所以把count(*)改为count(1)

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

 Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

F

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

sql注入 动态pivot

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

--检查输入的列是否存在

USE [sss]
IF COLUMNPROPERTY(OBJECT_ID('testrow'),'id','ColumnId') IS NOT NULL 
PRINT 'not null'

SELECT OBJECT_ID('testrow')
SELECT COLUMNPROPERTY(OBJECT_ID('testrow'),'id','ColumnId')

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

防范sql注入的几种措施
1、限制输入参数大小
2、只接收数据库存在的对象
3、代码引用列名称和对象时使用QUOTENAME(),并用方括号作为分隔标识符
4、检查变量,使用like语句匹配

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

创建视图获取别的库的数据,这样相对安全

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

要允许EXTERNAL_ACCESS和UNSAFE程序集运行,你需要把数据库选项TRUSTWORTHY设置为ON

ALTER DATABASE [sss] SET TRUSTWORTHY ON

 

TRUSTWORTHY 数据库属性用于指明 SQL Server 的实例是否信任该数据库以及其中的内容。默认情况下,除 msdb 数据库之外的所有系统数据库都将 TRUSTWORTHY 设置为 OFF。对于 model 和 tempdb 数据库,不能更改此值。
1. 可以通过ALTER DATABASE语句来修改数据库的TRUSTWORTHY属性(注意:必须是 sysadmin 固定服务器角色的成员才能设置此选项。)
ALTER DATABASE databasename SET TRUSTWORTHY ON
ALTER DATABASE databasename SET TRUSTWORTHY OFF
2.若要查看数据库TRUSTWORTHY属性的状态,可以查看sys.databases视图的is_trustworthy_on列。
查看具体数据库的TRUSTWORTHY属性:
select is_trustworthy_on from sys.databases where name=databasename
查看当前实例中所有数据库的TRUSTWORTHY属性:
select is_trustworthy_on,name from sys.databases
 
参考资料:
http://msdn.microsoft.com/en-us/library/ms187861.aspx

 

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

一个更为安全的解决方案是使用强名称钥密钥文件(strong-named key file)为程序集签名或使用证书为授权码(authenticode)签名,

强名称或证书是sqlserver内部创建的非对称密钥或证书,对应一个拥有EXTERNAL_ACCESS assembly权限或UNSAFE assembly权限的登录

USE [master]
GO
---从已签名的程序创建非对称密钥
--注意:必须使用强名称密钥文件为程序集签名
CREATE ASYMMETRIC KEY CLRutilitikey
FROM EXECUTABLE FILE='C:\CLUSIT\CLRUTILITIES.DLL'
--创建登录并授予其external_access权限
CREATE LOGIN clrutilitylogin FROM ASYMMETRIC KEY CLRutilitikey
GRANT EXTERNAL ACCESS ASSEMBLY TO clrutilitylogin

程序集安全的更详细信息:http://msdn.microsoft.com/en-us/library/ms345106.aspx

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记

f

所有的.net程序集都包含元数据,用于描述在程序集中定义的所有类型(类和结构),包括所有public方法和属性,.net中system.reflection命名空间的一些类和接口提供已加载类型的管理视图(managed view).NET 反射(http://www.cnblogs.com/yaozhenfa/p/CSharp_Reflection_1.html)

使用Reflector for .NET反编译.NET程序集 www.aisto.com/roeder/dotnet

(http://www.red-gate.com/products/dotnet-development/reflector/)被redgate收购

http://blogs.msdn.com/b/sqlclr/archive/2005/11/21/495438.aspx
提供了一个CLR DDL触发器,这个触发器在执行CREATE ASSEMBLY语句时触发,他会自动地注册程序集中的所有CLR对象,包括UDT,UDA,UDF,SP和触发器

We use reflection to look through the assembly. :我使用反射去查找程序集

 

CLR Trigger for Automatic Registration of UDXs on CREATE ASSEMBLY

CLR Trigger for Automatic Registration of UDXs on CREATE ASSEMBLY

对此进行分级
较差较差凑合凑合平均平均良好良好优秀优秀 Miles Trochesset Tue, Nov 22 2005 12:43 AM 1
This code is provided "AS IS" with no warranties, and confers no rights.

I've made some small modifications to comply with standard naming conventions on 11/30/2005.

Save the following into AutoRegisterTrigger.cs

--------------------------------------------------------

using System;
using System;
using Microsoft.SqlServer.Server;
using System.Data;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using System.Xml;
using System.Reflection;
using System.Text.RegularExpressions;

namespace Microsoft.SqlServer.Sample

{

    public class AutoRegister
    {
        [SqlTrigger(Name = "AutoRegister", Event = "FOR CREATE_ASSEMBLY", Target = "DATABASE")]
        public static void AutoRegisterTrigger()
        {
            // Checks that we are executing this trigger after a create assembly
            SqlTriggerContext triggContext = SqlContext.TriggerContext;
            if (triggContext.TriggerAction != TriggerAction.CreateAssembly)
            {
                throw new Exception("This trigger is only meaningful for CREATE ASSEMBLY.");
            }

            // Retrieves the name of the assembly being registered
            String asmName = null;
            XmlReader eventreader = triggContext.EventData.CreateReader();
            while (eventreader.Read())
            {
                if (eventreader.Name.Equals("ObjectName"))
                {
                    asmName = eventreader.ReadElementContentAsString();
                    break;
                }
            }
            if (asmName == null)
            {
                throw new Exception("Could not find the assembly name.");
            }

            // Retrieve the clr name of the assembly
            String ClrName = null;
            using (SqlConnection myConnection = new SqlConnection("Context connection = true"))
            {
                myConnection.Open();
                using (SqlCommand myCommand = new SqlCommand())
                {
                    myCommand.Connection = myConnection;
                    myCommand.CommandText = "SELECT clr_name FROM sys.assemblies WHERE name = @AsmName";
                    myCommand.Parameters.Add("@AsmName", SqlDbType.NVarChar);
                    myCommand.Parameters[0].Value = asmName;
                    ClrName = (String)myCommand.ExecuteScalar();
                }
            }

            // Load the assembly from SQL database to memory
            Assembly a = Assembly.Load(ClrName);

            // Iterating over types in assembly
            Type[] types = a.GetTypes();
            foreach (Type type in types)
            {

                try
                {
                    // Iterating over custom attributes of type
                    Attribute[] Type_attributes = Attribute.GetCustomAttributes(type);
                    foreach (Attribute att in Type_attributes)
                    {
                        if (att.ToString().Equals("Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute"))
                        {
                            RegisterUDT(asmName, type, (SqlUserDefinedTypeAttribute)att);
                        }
                        else if (att.ToString().Equals("Microsoft.SqlServer.Server.SqlUserDefinedAggregateAttribute"))
                        {
                            RegisterUDA(asmName, type, (SqlUserDefinedAggregateAttribute)att);
                        }
                    }
                }
                catch (AutoRegisterException e)
                {
                    SqlContext.Pipe.Send("[" + asmName + "].[" + type.Name + "] : " + e.Message);
                }

                // Iterate over public static methods
                MethodInfo[] methodInfos = type.GetMethods();
                foreach (MethodInfo methodInfo in methodInfos)
                {
                    if (methodInfo.IsPublic && methodInfo.IsStatic)
                    {
                        try
                        {
                            Object[] Method_attributes = methodInfo.GetCustomAttributes(false);
                            foreach (Attribute att in Method_attributes)
                            {
                                if (att.ToString().Equals("Microsoft.SqlServer.Server.SqlProcedureAttribute"))
                                    RegisterProcedure(asmName, type, (SqlProcedureAttribute)att, methodInfo);
                                if (att.ToString().Equals("Microsoft.SqlServer.Server.SqlTriggerAttribute"))
                                    RegisterTrigger(asmName, type, (SqlTriggerAttribute)att, methodInfo);
                                if (att.ToString().Equals("Microsoft.SqlServer.Server.SqlFunctionAttribute"))
                                    RegisterUDF(asmName, type, (SqlFunctionAttribute)att, methodInfo);
                            }

                        }
                        catch (AutoRegisterException e)
                        {
                            SqlContext.Pipe.Send("[" + asmName + "].[" + type.Name + "].[" + methodInfo.Name + "] : " + e.Message);
                        }
                    }
                }
            }
        }

        private static void RegisterUDT(String asmName, Type type, SqlUserDefinedTypeAttribute sqlUserDefinedTypeAttribute)
        {
            String Name = sqlUserDefinedTypeAttribute.Name;
            if (Name == null) Name = type.Name;

            // Check that the name is valid
            if (!IsValid(Name))
                throw new InvalidNameException(Name);

            // Check if the object is already registered
            if (IsRegistered(Name))
                throw new ObjectRegisteredException(Name);

            String CommandString = "CREATE TYPE [" + Name + "] EXTERNAL NAME [" + asmName + "].[";
            if (type.Namespace != null) CommandString += type.Namespace + ".";
            CommandString += type.Name + "]";

            Register(CommandString);
        }

        private static void RegisterUDA(String asmName, Type type, SqlUserDefinedAggregateAttribute sqlUserDefinedAggregateAttribute)
        {
            String Name = sqlUserDefinedAggregateAttribute.Name;
            if (Name == null) Name = type.Name;

            // Check that the name is valid
            if (!IsValid(Name))
                throw new InvalidNameException(Name);

            // Check if the object is already registered
            if (IsRegistered(Name))
                throw new ObjectRegisteredException(Name);

            String CommandString = "CREATE AGGREGATE [" + Name + "]";
            String CommandString_return = "";
            bool hasAccumulateMethod = false;

            // Iterate over public methods to find parameter and return type
            MethodInfo[] methodInfos = type.GetMethods();
            foreach (MethodInfo methodInfo in methodInfos)
            {
                if (methodInfo.Name.Equals("Accumulate"))
                {
                    // Add parameter
                    ParameterInfo[] pis = methodInfo.GetParameters();
                    if (pis.Length != 1)
                        throw new InvalidNumberOfArgumentsException();

                    ParameterInfo pi = pis[0];
                    char[] refchar = { '&' }; // double check that this is a unicode array
                    String param_type;

                    // if parameter is passed by reference as in (@i INT OUTPUT) display an error
                    if (pi.ParameterType.ToString().LastIndexOfAny(refchar) != -1)
                        throw new InvalidArgumentByReferenceException(pi.ParameterType.ToString());

                    param_type = NETtoSQLmap(pi.ParameterType.ToString());
                    if (param_type == null)
                        throw new InvalidTypeException(pi.ParameterType.ToString());

                    // Check the validity of the parameter strings (we construct param_type no need to validate it)
                    if (!IsValid(pi.Name))
                        throw new InvalidNameException(pi.Name);

                    CommandString += " (@" + pi.Name + " " + param_type + ")";
                    hasAccumulateMethod = true;
                }
                else if (methodInfo.Name.Equals("Terminate"))
                {
                    String return_type = NETtoSQLmap(methodInfo.ReturnType.ToString());
                    if (return_type == null)
                        throw new InvalidReturnTypeException(methodInfo.ReturnType.ToString());
                    CommandString_return = " RETURNS " + return_type + " "; // we construct return_type no need to validate it
                }
            }

            if (CommandString_return.Equals(""))
                throw new MissingTerminateMethodException();

            if (!hasAccumulateMethod)
                throw new MissingAccumulateMethodException();

            CommandString += CommandString_return;
            CommandString += "EXTERNAL NAME [" + asmName + "].[";
            if (type.Namespace != null) CommandString += type.Namespace + ".";
            CommandString += type.Name + "]";

            Register(CommandString);
        }

        private static void RegisterProcedure(String asmName, Type type, SqlProcedureAttribute sqlProcedureAttribute, MethodInfo methodInfo)
        {
            String Name = sqlProcedureAttribute.Name;
            if (Name == null) Name = methodInfo.Name;

            // Check that the name is valid
            if (!IsValid(Name))
                throw new InvalidNameException(Name);

            // Check if the object is already registered
            if (IsRegistered(Name))
                throw new ObjectRegisteredException(Name);

            String CommandString = "CREATE PROCEDURE [" + Name + "]";
            CommandString += GetParameterString(methodInfo);
            CommandString += " AS EXTERNAL NAME [" + asmName + "].[";
            if (type.Namespace != null) CommandString += type.Namespace + ".";
            CommandString += type.Name + "].[" + methodInfo.Name + "]";

            Register(CommandString);
        }

        private static void RegisterTrigger(String asmName, Type type, SqlTriggerAttribute sqlTriggerAttribute, MethodInfo methodInfo)
        {
            String Name = sqlTriggerAttribute.Name;
            if (Name == null) Name = methodInfo.Name;

            // Check that the name is valid
            if (!IsValid(Name))
                throw new InvalidNameException(Name);

            // Check if the object is already registered
            if (IsRegistered(Name))
                throw new ObjectRegisteredException(Name);

            // Check that the target is valid
            String Target = sqlTriggerAttribute.Target;
            if (Target == null)
                throw new NoTargetException();
            if (!IsValid(sqlTriggerAttribute.Target))
                throw new InvalidNameException(sqlTriggerAttribute.Target);

            // Check that the event is valid
            String Tr_event = sqlTriggerAttribute.Event;
            if (Tr_event == null)
                throw new NoEventException();
            if (!IsValid(sqlTriggerAttribute.Event))
                throw new InvalidNameException(sqlTriggerAttribute.Event);

            String CommandString = "CREATE TRIGGER [" + Name + "] ";
            CommandString += "ON " + Target + " WITH EXECUTE AS CALLER ";
            CommandString += Tr_event + " AS EXTERNAL NAME [" + asmName + "].[";
            if (type.Namespace != null) CommandString += type.Namespace + ".";
            CommandString += type.Name + "].[" + methodInfo.Name + "]";

            Register(CommandString);
        }

        private static void RegisterUDF(String asmName, Type type, SqlFunctionAttribute sqlFunctionAttribute, MethodInfo methodInfo)
        {
            String Name = sqlFunctionAttribute.Name;
            if (Name == null) Name = methodInfo.Name;

            // Check that the name is valid
            if (!IsValid(Name))
                throw new InvalidNameException(Name);

            // Check if the object is already registered
            if (IsRegistered(Name))
                throw new ObjectRegisteredException(Name);

            String CommandString = "CREATE FUNCTION [" + Name + "]";
            CommandString += GetParameterString(methodInfo);
            String return_type = NETtoSQLmap(methodInfo.ReturnType.ToString());
            if (return_type == null)
                throw new InvalidReturnTypeException(methodInfo.ReturnType.ToString());

            CommandString += "RETURNS " + return_type + " ";
            CommandString += "AS EXTERNAL NAME [" + asmName + "].[";
            if (type.Namespace != null) CommandString += type.Namespace + ".";
            CommandString += type.Name + "].[" + methodInfo.Name + "]";

            Register(CommandString);
        }

        // could we use a solution similar to Xiaowei's question to make this more robust
        private static String NETtoSQLmap(String typeName)
        {
            switch (typeName)
            {
                case "System.Data.SqlTypes.SqlBoolean": return "bit";
                case "System.Data.SqlTypes.SqlBinary": return "varbinary"; // other choices: binary, image, timestamp,
                case "System.Data.SqlTypes.SqlByte": return "tinyint";
                case "System.Data.SqlTypes.SqlChars": return "nvarchar"; //other choices: char, nchar, text, ntext, varchar
                case "System.Data.SqlTypes.SqlDateTime": return "smalldatetime"; // other choice: datetime
                case "System.Data.SqlTypes.SqlDecimal": return "decimal";
                case "System.Data.SqlTypes.SqlDouble": return "float";
                case "System.Data.SqlTypes.SqlGuid": return "uniqueidentifier";
                case "System.Data.SqlTypes.SqlInt16": return "smallint";
                case "System.Data.SqlTypes.SqlInt32": return "int";
                case "System.Data.SqlTypes.SqlInt64": return "bigint";
                case "System.Data.SqlTypes.SqlMoney": return "money"; // other choice smallmoney
                case "System.Data.SqlTypes.SqlSingle": return "real";
                case "System.Data.SqlTypes.SqlString": return "nvarchar"; //other choices: char, nchar, text, ntext, varchar
                case "System.Data.SqlTypes.SqlXml": return "xml";
                default:
                    {
                        switch (typeName.ToLower())
                        {
                            case "short": return "smallint";
                            case "int": return "int";
                            case "long": return "bigint";
                            case "bool": return "bit";
                            case "boolean": return "bit";
                            case "float": return "float";
                            case "single": return "single";
                            default: return null;
                        }
                    }
            }
        }

        // Check if the object is already registered, return true if it is, false otherwise
        private static bool IsRegistered(String name)
        {
            bool b;

            using (SqlConnection myConnection = new SqlConnection("context connection = true"))
            {
                myConnection.Open();
                using (SqlCommand myCommand = new SqlCommand())
                {
                    myCommand.Connection = myConnection;
                    myCommand.CommandText = "SELECT * FROM sys.objects WHERE name = @Name";
                    myCommand.Parameters.Add("@Name", SqlDbType.NVarChar);
                    myCommand.Parameters[0].Value = name;
                    if (myCommand.ExecuteScalar() != null) b = true;
                    else b = false;
                }
                return b;
            }

        }

        private static void Register(String commandString)
        {
            using (SqlConnection myConnection = new SqlConnection("context connection = true"))
            {
                myConnection.Open();
                using (SqlCommand comm = new SqlCommand(commandString, myConnection))
                {
                    try
                    {
                        comm.ExecuteNonQuery();
                        SqlContext.Pipe.Send("AutoRegister: " + commandString);
                    }
                    catch (SqlException e)
                    {
                        SqlContext.Pipe.Send(e.Message);
                    }
                }
            }
        }

        /* We assume namespace, class and method names are valid strings for
         * TSQL statements (alphanumeric or underscore only) since the
         * compiler accepted them and so is the assembly name since
         * it was provided by the DBA */
        private static bool IsValid(String s)
        {
            return Regex.IsMatch(s, "[^_.[:alnum:]]");
        }

        private static String GetParameterString(MethodInfo methodInfo)
        {
            String s_params = "";

            // Add parameters
            ParameterInfo[] pis = methodInfo.GetParameters();
            bool empty = true;
            char[] refchar = { '&' }; // double check that this is a unicode array
            String param_type;
            foreach (ParameterInfo pi in pis)
            {
                // add OUTPUT if parameter is passed by reference as in (@i INT OUTPUT)
                int ix = pi.ParameterType.ToString().LastIndexOfAny(refchar);
                if (ix != -1)
                {
                    param_type = NETtoSQLmap(pi.ParameterType.ToString().Substring(0, ix));
                    if (param_type == null)
                        throw new InvalidTypeException(pi.ParameterType.ToString().Substring(0, ix));
                    param_type += " OUTPUT";
                }
                else
                {
                    param_type = NETtoSQLmap(pi.ParameterType.ToString());
                    if (param_type == null)
                        throw new InvalidTypeException(pi.ParameterType.ToString());
                }

                // Check the validity of the parameter strings (we construct param_type no need to validate it)
                if (!IsValid(pi.Name))
                    throw new InvalidNameException(pi.Name);

                if (empty)
                {
                    s_params += " (@" + pi.Name + " " + param_type;
                    empty = false;
                }
                else
                    s_params += ", @" + pi.Name + " " + param_type;
            }
            if (!empty)
                s_params += ") ";

            return s_params;
        }
    }

    internal class AutoRegisterException : ApplicationException
    {
        internal AutoRegisterException(String Message)
            : base(Message + " UDX not registered.")
        {
        }
    }

    internal class InvalidTypeException : AutoRegisterException
    {
        internal InvalidTypeException(String sType)
            : base("Argument type " + sType + " cannot be mapped to a SQL Type.")
        {
        }

    }

    internal class InvalidReturnTypeException : AutoRegisterException
    {

        internal InvalidReturnTypeException(String sType)
            : base("Return type " + sType + " cannot be mapped to a SQL Type.")
        {
        }
    }

    internal class ObjectRegisteredException : AutoRegisterException
    {
        internal ObjectRegisteredException(String Name)
            : base(Name + " is already registered.")
        {
        }
    }

    internal class InvalidNameException : AutoRegisterException
    {
        internal InvalidNameException(String Name)
            : base(Name + " is not a valid name.")
        {
        }
    }

    internal class NoEventException : AutoRegisterException
    {
        internal NoEventException()
            : base("Missing the 'Event' argument for the SqlTriggerAttribute constructor.")
        {
        }
    }

    internal class NoTargetException : AutoRegisterException
    {
        internal NoTargetException()
            : base("Missing the 'Target' argument for the SqlTriggerAttribute constructor.")
        {
        }
    }

    internal class InvalidNumberOfArgumentsException : AutoRegisterException
    {
        internal InvalidNumberOfArgumentsException()
            : base("Wrong number of arguments.")
        {
        }
    }

    internal class InvalidArgumentByReferenceException : AutoRegisterException
    {
        internal InvalidArgumentByReferenceException(String Argument)
            : base("Expected argument " + Argument + "passed by value, passed by reference instead.")
        {
        }
    }

    internal class MissingTerminateMethodException : AutoRegisterException
    {
        internal MissingTerminateMethodException()
            : base("The user defined aggregate is missing a 'Terminate' method.")
        {
        }
    }

    internal class MissingAccumulateMethodException : AutoRegisterException
    {
        internal MissingAccumulateMethodException()
            : base("The user defined aggregate is missing an 'Accumulate' method.")
        {
        }
    }
}
-------------------------------------

then run the following TSQL batch
-------------------------------------

CREATE ASSEMBLY AutoRegisterAsm
FROM -- path to your dll goes here
WITH PERMISSION_SET = SAFE
GO

CREATE TRIGGER AutoRegisterTrigger
ON DATABASE
FOR CREATE_ASSEMBLY
AS EXTERNAL NAME AutoRegisterAsm.[Microsoft.SqlServer.Sample.AutoRegister].AutoRegisterTrigger
GO

ENABLE TRIGGER AutoRegisterTrigger ON DATABASE
GO
- Miles Trochesset, Microsoft SQL Server
View Code

相关文章:

  • 2021-11-08
  • 2022-12-23
  • 2021-12-23
  • 2021-11-24
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-01-29
  • 2021-11-13
  • 2022-12-23
  • 2021-11-06
  • 2021-09-30
  • 2022-01-28
相关资源
相似解决方案