23、SQL Server 基础 - 部分可编程对象

变量

声明一个变量,则它可以在声明它的同一批处理语句中引用,因为SQL Server会将批处理中的语句编译成为单个可执行单元。

 DECLARE @i AS INT;
SET @i=10;

在SQL Server 2008以后,还可以直接这样写:

 DECLARE @i AS INT=10;

可以用标量表达式的结果赋值给符合数据类型的变量,这是很自然的。

 USE MyDB;
DECLARE @s_name AS NVARCHAR(20);
SET @s_name=(
            SELECT firstname+N' '+lastname
            FROM dbo.ok
            WHERE myid=1182
            );
SELECT @s_name AS '得到的单值';

 USE MyDB;
DECLARE @s_name AS NVARCHAR(20);
SET @s_name=(
            SELECT firstname+N' '+lastname
            FROM dbo.ok
            WHERE Pid=1012  --满足这个条件的可是有多行
            );
SELECT @s_name AS '得到的单值';

 USE MyDB;
DECLARE @s_name AS NVARCHAR(20);
--下面是非标准的赋值SELECT语句
SELECT @s_name=firstname+N' '+lastname
FROM dbo.ok
WHERE Pid=1012; --满足这个条件的可是有多行
SELECT @s_name AS '得到的单值';

批处理

批处理语句将多条T-SQL语句作为一个可执行单元,要经历的阶段有:分析(语法检查)->解析(存在性、权限)->优化(作为执行单元)。

作为语法分析的单元

如果批处理单元中存在语法错误,整个批处理都不会提交到SQL Server执行,批处理之间可以用GO隔开。在使用时,不同的批处理不互相影响。
并且,变量只能在声明它的批处理中被使用:

 PRINT @i;
GO
DECLARE @i AS INT=10;
PRINT @i+1;
GO
PRINT @i+2;

不能在同一批处理中编译的语句

有些语句必须单独放到一个批处理中,之前学表表达式时,创建视图的时候就出现了这样的问题。这样的语句有:

 CREATE DEFAULT
CREATE FUNCTION
CREATE PROCEDURE
CREATE RULE
CREATE SCHEMA
CREATE TRIGGER
CREATE VIEW

必须用GO和旁边的其它语句隔开。

作为语句解析的单元

批处理作为语句解析的单元,如果对数据对象的架构进行修改,并在同一批处理中使用这些修改时,SQL Server可能还不知道架构定义发生了变化(因为在解析这条语句时,前面那条修改架构的还没有被执行)。

 USE MyDB;
ALTER TABLE dbo.ji1 ADD newcol INT;
SELECT myint,mychar,mychar2,newcol FROM dbo.ji1;--在解析这句时,前面那句还没执行

 USE MyDB;
ALTER TABLE dbo.ji1 ADD newcol INT;
GO
SELECT myint,mychar,mychar2,newcol FROM dbo.ji1;--与前面那句已经是两个批处理块

GO n选项

从SQL Server 2005开始对GO就进行了增强,可以带一个数字表示GO之前的批处理将执行指定的次数。

 DECLARE @i AS INT=6;
PRINT @i;
GO 3

流程控制元素

判断条件实际上是不用加括号的,我习惯加上括号,看起来更清楚(改变优先级的时候肯定要加吧),也是向其它语言看齐。

IF-ELSE

只要注意下三值逻辑,当为FALSE或者UNKNOWN时都会进入ELSE块里。

 DECLARE @i AS INT=5;
IF(@i>5)
SET @i=7;
ELSE
    IF(@i<3)
        SET @i=1;
    ELSE
        SET @i=4;
PRINT @i;

 DECLARE @i AS INT=5;
IF(@i>5)
    BEGIN
        SET @i=@i+1;
        PRINT @i+1;
    END
ELSE
    BEGIN
        SET @i=@i-1;
        PRINT @i-1;
    END

WHILE

WHILE也是只接受TRUE的,FALSE和UNKNOWN都会让循环终止。

 DECLARE @i AS INT=1;
WHILE(@i<=10)
    BEGIN
        PRINT @i;
        SET @i=@i+1;
    END

BREAK和CONTINUE在SQL里也是有的。

 DECLARE @i AS INT=1;
WHILE(@i<=10)
    BEGIN
        IF(@i=6)
            BREAK;--跳出
        PRINT @i;
        SET @i=@i+1;
    END

 DECLARE @i AS INT=1;
WHILE(@i<=10)
    BEGIN
        IF(@i=6)
            BEGIN
                SET @i=@i+1;
                CONTINUE;--跳过
            END
        PRINT @i;
        SET @i=@i+1;
    END

用户自定义函数

例程是为了计算结果或执行任务而对代码进行封装的一种编程对象。本节只学用户自定义函数,除此之外还有存储过程和触发器,后面再学。

 USE MyDB;
IF OBJECT_ID('dbo.fn_cat') IS NOT NULL
    DROP FUNCTION dbo.fn_cat;
GO

CREATE FUNCTION dbo.fn_cat
(
    @s1 AS NVARCHAR(10),
    @s2 AS NVARCHAR(20)
)
RETURNS NVARCHAR(21)
AS
    BEGIN
        RETURN @s1+N'-'+@s2;
    END;

然后就可以使用了:

 SELECT
    dbo.fn_cat(firstname,lastname) AS CAT
FROM dbo.ok;