内部排序
代码更新地址:https://github.com/myourys/Algorithm/blob/master/InternalSort.cpp


BubbingSort         冒泡排序 O(n^2)
SimpleSelectSort    简单选择排序 O(n^2)
QuickSort           快速排序O(n*logn)
InsertSort          插入排序O(n^2)
BInsertSort         折半插入排序O(n^2)
ShellSort           希尔排序 O(N*(logN))
RadixSort           基数排序O(nlog(r)m)
MergeSort           归并排序O(n*log(n))
HeapSort            堆排序O(n*log(n)
BucketSort          桶排序O(N)~O(n^2)
/*=============================================================================
#     FileName: InternalSort.cpp
#         Desc: 内部排序算法
#       Author: Hector
#        Email: myourys@gmail.com
#     HomePage: http://www.yiwuye.com
#      Version: 0.0.1
#   LastChange: 2013-03-25 00:02:24
#      History:
=============================================================================*/

#include<iostream>
#include <stdlib.h>
#include <ctime>
using namespace std;

void swap(int &a,int &b)
{
    int t = a;
    a = b;
    b = t;
}

/*
 * 冒泡排序
 * O(n^2) =  (n-1)*n/2
 *
 */
void BubbingSort(int s[],int n)
{
    int i,j;
    for(i=0;i<n-1;i++)
        for(j=i+1;j<n;j++)
            if(s[j]<s[i])
                swap(s[i],s[j]);
}

/*
 * 简单选择排序
 * O(n^2) =  (n-1)*n/2
 * 对冒泡的一种改进,减少交换次数,如果内循环元素比外循环元素大,则记下位置和大小,内循环完成后得到最大的数
 * 每次外循环将最大(小)的数放在前面
 */
void SimpleSelectSort(int s[],int n)
{
    int i,j,t,pos;
    for(i=0;i<n-1;i++)
    {
        t=s[i];
        pos = i;
        for(j=i+1;j<n;j++)
        {
            if(s[j]<t)
            {
                pos = j;
                t = s[j];
            }
        }
        if(i!=pos)
            swap(s[i],s[pos]);
    }
}

/*
 * 快速排序
 * O(n*logn)
 * 以开头第一个元素为中间点,大的放在前面,小的放在后边,递归排序
 * 分别从后往前搜索,将大数放前面,然后从前往后搜索,将小的放在后边
 */
void QuickSort(int s[],int begin,int end)
{
    if(begin>=end) return; //重合点
    // a,b 为前后搜索的定位点,e为中间点
    int a = begin,b = end;
    int e = a;

    //从后往前搜索
    for(b=end;b>a;b--)
    {
        if(s[b]<s[e])
        {
            swap(s[e],s[b]);
            e=b;
            //从前往后搜索
            for(a = a+1;a<b;a++)
            {
                if(s[a]>s[e])
                {
                    swap(s[e],s[a]);
                    e=a;
                    break;//反方向搜索
                }
            }
        }
    }
    QuickSort(s,begin,e-1);
    QuickSort(s,e+1,end);
}

/*
 * 插入排序
 * O(n^2) 
 * 算法适用于少量数据的排序
 *⒈ 从第一个元素开始,该元素可以认为已经被排序
 *⒉ 取出下一个元素,在已经排序的元素序列中从后向前扫描
 *⒊ 如果该元素(已排序)大于新元素,将该元素移到下一位置
 *⒋ 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
 *⒌ 将新元素插入到下一位置中
 *⒍ 重复步骤2
 */

void InsertSort(int s[],int n)
{
    int i,j;
    for(i=0;i<n-1;i++) //i前面都是排好序的数列
       for(j=i+1;j>0 && s[j] < s[j-1];j--) // 大数往前面冒泡
           swap(s[j],s[j-1]);

}
/*
 * 折半插入排序
 * O(n^2)
 * 只能减少插入排序的比较次数,移动次数不变
 */
void BInsertSort(int s[],int n)
{
    int i,j,begin,end,mid,t;
    for(i=0;i<n-1;i++) //i前面都是排好序的数列
        if(s[i+1]<s[i])
        {
            begin = 0;
            end = i;
            // 找到最接近的右侧点
            while(begin<=end)
            {
                mid = (begin+end)/2;
                if(s[i+1]<s[mid])
                    end = mid-1;
                else
                    begin = mid+1;
            }
            t = s[i+1];
            //记录后移
            for(j=i;j>=begin;j--)
                s[j+1]=s[j];
            s[begin]= t;
        }
}

/*
 * 希尔排序
 * O(N*(logN)2)
 * 希尔排序是插入排序的一种。
 * 如此例第一次分为5组,上下为一组,然后每组排序
 * 8,1,3,0,9           得到: 8,2,4,6,9
 * 7,2,4,6,5                 7,1,3,0,5
 * 然后分为5/2=2组,每组排列...
 * 直至分为1组就是有序了
 */
void ShellSort(int s[],int n)
{
    int i,j;
    for(int gap =n/2;gap>0;gap /=2) //每次折半
        for(i=gap;i<n;i++) //从第二行数据开始,直接插入排序
        {
            for(j=i-gap;j>=0 && s[j+gap]<s[j];j-=gap) //与之前一列数据比较,此处参考插入排序
                swap(s[j],s[j+gap]);
        }
}

/*
 * 基数排序
 * O (nlog(r)m),其中r为所采取的基数,而m为堆数
 * 在某些时候,基数排序法的效率高于其它的比较性排序法
 * 即:先按个位排序,然后按十位排序...
 */

void RadixSort(int m[],int n)
{
    int w = 6,j,k,r=1; //最大6位数
    for(int i = 1;i<=w;i++)
    {
        for(j=1;j<n;j++) //插入排序
            for(k=j-1;k>=0 && m[k+1]/r % 10 < m[k]/r %10;k--)
                swap(m[k],m[k+1]);

        r*=10;
    }
}



/*
 * 堆排序
 */

/*
 * 归并排序
 * O(N*logN)
 * 将两个有效数列合并成一个,因此可以考虑分成两个1组,2组合并成1组,直至整个数列完成
 */
void Merge(int a[], int b[], int low, int mid, int high)  //将A序列的两组(low-mid,mid+1-high),合并到同大小的b中
{
    int k = low;
    int begin1 = low;
    int end1 = mid;
    int begin2 = mid + 1;
    int end2 = high;
    while(k <= high )
    {
        if(begin1 > end1) //第1组完成,将第二组附加上去
            b[k++] = a[begin2++];
        else if(begin2 > end2)
            b[k++] = a[begin1++];
        else
        {
            if(a[begin1] <= a[begin2])
                b[k++] = a[begin1++];
            else
                b[k++] = a[begin2++];
        }
    }
}


//合并序列
void SubMerge(int a[], int b[], int ibegin, int mid,int iend)
{
   int pos = ibegin,i,j;
   for(i=ibegin,j=mid;i<=mid-1&&j<=iend;)
   {
       if(a[i]>a[j])
           b[pos++] = a[j++];
       else
           b[pos++] = a[i++];
   }
   while(i<=mid-1)
       b[pos++] = a[i++];
   while(j<=iend)
       b[pos++] = a[j++];

   //同时保持a也有序
   for(i=ibegin;i<=iend;i++)
	   a[i]=b[i];
}

/*
 * 将a中的从seg开始,长度为size的数排好序
 */

void SubMergeSort(int a[], int b[], int seg, int size)
{
    if(size>=2)
    {
        SubMergeSort(a,b,seg,size/2);//前一半合并到b中
        SubMergeSort(a,b,seg+size/2,size-size/2);//后一半合并到b中
		SubMerge(b,a,seg,seg+size/2,seg +size-1); //保持a,b都有序
    }
}

void MergeSort(int a[],int size)
{
	int *t=a;
    int *temp=new int[size];
	for(int i=0;i<size;i++)
		temp[i]=a[i];
	SubMergeSort(a,temp,0,size);
    delete []temp;
}

/*
 * 堆排序 [采用数组排序]
 * O(N * logN)
 * 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
 * 2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)
 * i结点的父结点下标就为(i – 1) / 2,孩子2 * i + 1和2 * i + 2
 * 由于每次重新恢复堆的时间复杂度为O(logN),共N - 1次重新恢复堆操作,再加上前面建立堆时N / 2次向下调整,
 * 每次调整时间复杂度也为O(logN)。二次操作时间相加还是O(N * logN)。故堆排序的时间复杂度为O(N * logN)
 */
void MiniHeap(int a[],int n); //堆话数组 ->建立最小堆
void MinHeapFixdown(int a[],int i,int n); //调整堆元素
void HeapSort(int a[],int n)
{
	int* t = new int[n];
	for(int i=0;i<n;i++)
		t[i]=a[i];
	MiniHeap(t,n);//建立堆
	for(int i=0;i<n;i++)
	{
		a[i] = t[0];
		t[0] = t[n-i-1];//删除堆顶,并调整堆,使堆顶是最小元素
		MinHeapFixdown(t,0,n-i);
	}
	delete []t;
}

void MiniHeap(int a[],int n) //堆话数组 ->建立最小堆
{
	//i 从最后一个不是叶子节点的位置开始调整堆
	for(int i= n/2 - 1;i>=0;i--)
		MinHeapFixdown(a,i,n);
}

void MinHeapFixdown(int a[],int i,int n) //大数下沉,自下而上
{
	int child = 2*i+1; //左孩子
	if(child>=n)//无左右孩子
		return;
	if(child+1<n && a[child+1]<a[child]) //找到左右孩子最小的
		child++;
	if(a[child]>=a[i]) //如果本身就是有序的
		return;
	swap(a[i],a[child]);
	MinHeapFixdown(a,child,n);//孩子继续下沉
}

/*
 * 桶排序
 * 类似Hash,采用分治的思想
 * O(N)-O(N^2)
 */

struct Bucket //桶结构
{
    int* s;
    int size;
    Bucket()
    {
        s =NULL;
        size = 0;
    }
};

void BucketSort(int a[],int n)
{
	Bucket b[1000]; //1千个桶
    for(int i=0;i<1000;i++)
        b[i].s = new int[n];
    //假如数在[0~1,000,000) 之间,分桶
    int t;
    for(int i = 0;i<n;i++)
    {
        t = a[i]/1000;
        b[t].s[b[t].size++] = a[i];
    }
    int pos =0;
    for(int i=0;i<1000;i++)
    {
        if(b[i].size >0)
        {
            QuickSort(b[i].s,0,b[i].size-1); //桶中数字排序
            for(int j=0;j<b[i].size;j++)
                a[pos++] = b[i].s[j];
        }
        delete []b[i].s;
    }
}

int main()
{
	int Flag = 0;
	while(Flag < 10)
	{
		Flag++;
		int n = 1000000;
		int* s =new int[n];
		for(int i=0;i<n;i++)
			s[i] = rand() %1000000; //注rand()产生的数在0到RAND_MAX之间
		srand(time(NULL));
		clock_t ibegin, iend;
		ibegin = clock();
		switch(Flag)
		{
		case 19:
			cout<<"冒泡排序【BubbingSort】:"<<endl;
			BubbingSort(s,n);break;
		case 29:
			cout<<"简单选择排序【SimpleSelectSort】:"<<endl;
			SimpleSelectSort(s,n);break;
		case 3:
			cout<<"快速排序【QuickSort】:"<<endl;
			QuickSort(s,0,n-1);break;
		case 49:
			cout<<"插入排序【InsertSort】:"<<endl;
			InsertSort(s,n);break;
		case 59:
			cout<<"折半插入排序【BInsertSort】:"<<endl;
			BInsertSort(s,n);break;
		case 6:
			cout<<"希尔排序【ShellSort】:"<<endl;
			ShellSort(s,n);break;
		case 7:
			cout<<"归并排序【MergeSort】:"<<endl;
			MergeSort(s,n);break;
		case 8:
			cout<<"堆排序【MiniHeap】:"<<endl;
			HeapSort(s,n);break;
		case 99:
			cout<<"基数排序【RadixSort】:"<<endl;
			RadixSort(s,n);break;
		case 10:
			cout<<"桶排序【BucketSort】:"<<endl;
	            BucketSort(s,n);break;
		}
		iend = clock();
		if(iend - ibegin>0.1)
			cout<<"时间(毫秒):"<<iend - ibegin<<endl;
		//for(int i =0;i<n;i++)
		//	cout<<s[i]<<"  ";
        delete []s;
	    cout<<endl;
	}

    return 0;
}

简单的是运行Vs开发人员控制台,cl命令就可以直接用了。

其实可以将相应的资源文件放在环境变量里面即可。

1.加载exe到path里面

找到VS的安装目录,进入VC/BIN目录里面,如果是64位机器,注意进入里面64位的目录,然后将此路径加到环境变量的Path里面

2.加载include目录

将VC目录的include目录路径加载到环境变量include里面。

3.加载lib目录

将VC目录的lib目录路径加载到环境变量lib里面。此时尝试编译一个cpp文件,如果显示无法打开某些lib文件,尝试在Program Files文件夹下搜索此文件,然后将这个文件的目录也加载到环境变量lib里面,同时也注意64系统要选择x64的目录。

WNMP安装及使用

WNMP,是基于WINDOWS的NGINX+PHP+MYSQL+MEMCACHED的服务器集成环境。
此文所用的绿色版WNMP来自http://www.hdj.me/wnmpserver,详细使用请见原文,仅作简单介绍,不详细赘述。

MySQL默认用户名:root,密码为空
访问本机:http://127.0.0.1/ 或 http://localhost/ (若80端口被IIS等占用,请修改配置文件监听端口)
访问phpMyAdmin:http://127.0.0:8080/

wnmp程序所在路径不能含有汉字和空格。
绿色版须解压wnmp目录至任意磁盘根目录,如:D:\wnmp。

启动:wnmp_start.bat
停止:wnmp_stop.bat

添加Wordpress配置文件

找到\wnmp\nginx\conf\nginx.conf 文件用记事本打开

将默认站点,即第一个server{……}的内容复制到最后一个站点配置后面

修改此配置的监听地址 listen 为其他端口,root 网站存放目录

替换ReWrite规则为wordpress的

location / {
if (!-e $request_filename){
rewrite ^/(.*)$ /index.php/$1 last;
}
}

替换为

location / {
if (!-e $request_filename) {
rewrite (.*) /index.php;
}
}

在SQL Server 2000中,VARCHAR的最大长度是8000,如果字符串的长度超过8000,保存在VARCHAR中时就会被截断。
也不能定义DECLARE @largeText TEXT ,常见的字符串函数也不能使用,除了datalength,substring(substring中英文字符作为一个字符)。

这几个数据类型在行为上和较小的数据类型 varchar、nvarchar 和 varbinary 相同,最大长度都为2^31-1。

微软的说法是用这个数据类型来代替之前的text、ntext 和 image 数据类型,它们之间的对应关系为:

varchar(max)——-text;

nvarchar(max)—–ntext;

varbinary(max)—-image.

注意:
1.VARCHAR和VARCHAR(MAX)混在一起做处理时还是会变成VARCHAR,从而可能被截断,所以需要全转成VARCHAR(MAX)

2.在变量声明中使用 char 和 varchar 数据类型时,这些数据类型的默认值 n 为 1。

3.在 CAST 和 CONVERT 中使用 varchar 时,显示 n 的默认值为30。

MSSQL2005新增了四个排名函数,ROW_NUMBER, RANK, DENSE_RANK, NTILE。利用这些函数可以有效地分析数据以及向查询的结果行提供排序值。

建立测试数据,分析它们各自的作用。

CREATE TABLE [Test]
(
     [StudentID] [bigint] NOT NULL,
     [ClassID] [bigint] NOT NULL,
     [TestScore] [decimal](4, 1) NOT NULL
) ON [PRIMARY]
 GO

 INSERT INTO [Test]  VALUES (100001,100,90) 
 INSERT INTO [Test]  VALUES (100002,100,85.5)
 INSERT INTO [Test]  VALUES (100003,100,80)
 INSERT INTO [Test]  VALUES (100004,100,80)
 INSERT INTO [Test]  VALUES (100005,100,74)
 INSERT INTO [Test]  VALUES (101001,101,94)
 INSERT INTO [Test]  VALUES (101002,101,85.5)
 INSERT INTO [Test]  VALUES (101003,101,85.5)

测试代码:

 SELECT *, 
      ROW_NUMBER() OVER (ORDER BY TestScore DESC) as RN,
      RANK() OVER (ORDER BY TestScore DESC) as R,
      DENSE_RANK() OVER (ORDER BY TestScore DESC) as DR,
      NTILE(3) OVER (ORDER BY TestScore DESC) as N3
 FROM [Test]

执行结果:

StudentID ClassID  TestScore   RN    R   DR   N
--------- -------- ----------- ----- --- ---- -
101001    101      94.0        1     1   1    1
100001    100      90.0        2     2   2    1
100002    100      85.5        3     3   3    1
101002    101      85.5        4     3   3    2
101003    101      85.5        5     3   3    2
100003    100      80.0        6     6   4    2
100004    100      80.0        7     6   4    3
100005    100      74.0        8     8   5    3

通过以上的例子就很清晰了。

ROW_NUMBER
行号函数。用来生成数据行在结果集中的序号
语法:
ROW_NUMBER( ) OVER ([] )

可以利用ROW_NUMBER函数非常便利的实现分页功能

RANK
排序函数。必须配合over函数,且排序字段值相同的行号一样,同时隐藏行号会占位。
语法:
RANK() OVER ([] )

还可以利用partition进行分组排序,例如对每个班级分别按成绩排序。

DENSE_RANK
紧凑排序函数。与RANK函数不同的是,当排序字段值相同导致行号一样时,同时隐藏行号不占位。
语法:
DENSE_RANK ( ) OVER ([] )
NTILE
分区排序函数。NTILE函数需要一个参数N,这个参数支持bigint。这个函数将结果集等分成N个区,并按排序字段将已排序的记录依次轮流放入各个区内。最后每个区内会从1开始编号,NTILE函数返回这个编号。
语法:
NTILE (integer_expression) OVER ([]< order_by_clause>)

SET ROWCOUNT { number | @number_var }

使 SQL Server 在返回指定的行数之后停止处理查询。 要将此选项设置为 off 以便返回所有的行,请将 SET ROWCOUNT 指定为 0。
SET ROWCOUNT 的设置是在执行时或运行时设置,而不是在分析时设置。

和TOP合用

如果行数值较小,则 SET ROWCOUNT 将覆盖 SELECT 语句 TOP 关键字。

当 INSERT、UPDATE 和 DELETE 语句使用显式 TOP 表达式时,这些语句将忽略 SET ROWCOUNT。这包括 INSERT 后跟 SELECT 子句的语句。

影响范围

设置 SET ROWCOUNT 选项将使大多数 Transact-SQL 语句在受到指定数目的行影响后停止处理。这包括触发器和 INSERT、UPDATE 及 DELETE 等数据修改语句。ROWCOUNT 选项对动态游标无效,但它可以限制键集的行集和不区分游标。应谨慎使用该选项,它主要与 SELECT 语句一起使用。

在 SQL Server 的下一个版本中,使用 SET ROWCOUNT 将不会影响 DELETE、INSERT 和 UPDATE 语句。
对于当前使用 SET ROWCOUNT 的 DELETE、INSERT 和 UPDATE 语句,建议您使用 TOP 语法重写它们。
对于在远程表和本地及远程分区视图上执行的 INSERT、UPDATE 和 DELETE 语句,将忽略 SET ROWCOUNT 选项设置。

select top

在MSSQL2000中是不支持select top + 变量的形式的
在MSSQL2005中却可以,例如:
select top 语句支持变量数目,如下例:

declare @n int
set @n=10
select top(@n) from orders

这样在后台存储过程分页就可以不必用动态语句了。。。

简介

ROW_NUMBER()是MS SQL Server 2005中新增窗口函数,可用来直接生成行号(但是SQL Server 2000中是没有这个函数的)。如:

select ROW_NUMBER() over (order by ENo), ENo,EName  
from Employee 

主要作用

分页

select * from (select orderid,freight,row_number() over(order by freight) as row from Orders) a
where row between 20 and 30

结合通用表达式进行分页

WITH OrderFreight AS( 
    select OrderId, Freight, ROW_NUMBER() OVER(order by Freight) as row from Orders 
) 
select OrderId, Freight from OrderFreight where row between 10 and 20

mssql2000模拟方法

1、使用临时表。

如果是在存储过程中,这是一个不错的选择。
创建一个临时表,其中除了需要的查询结果外,还一个记数列。查询结果放入临时表后(一般情况下可直接使用Insert into语句),用代码进行记数,更新记数列的值。
在记数列数值的生成方法上,还有一个改进的办法是直接将该列定义为自增长字段。这样“记数”的代码也省掉了。

2、采用自连接。

如果是在代码中,不便于使用临时表,可以采用此方法。比如执行一个查询统计,需要一个替代的SQL语句。
这个方法实际上是通过表的自连接给结果行“分等级”的思路来实现的。
语句如下:

select count(*),e1.ENo, e1.EName  
from Employee e1  
inner join Employee e2 on e1.ENo >= e2.ENo  
group by e1.ENo, e1.EName  
order by 1  

或者把join条件放到where子句中:

select count(*),e1.ENo, e1.EName  
from Employee e1, Employee e2,   
where e1.ENo >= e2.ENo  
group by e1.ENo, e1.EName  
order by 1  

如果ENo字段值不重复,还可以这样写:

select (select count(*) from Employee e2 where e1.ENo >= e2.ENo), e1.ENo, e1.EName  
from Employee e1  
order by 1  

如果ENo字段值有重复的情况,要使用最后一种写法可以将where条件变通一下,如:

where e1.ENo+e1.EName >= e2.ENo+e2.EName

总能找到不存在重复值的表达式的。

表变量

定义
一种特殊的数据类型,用于存储结果集以供后续处理。该数据类型主要用于临时存储一组行,这些行将作为表值函数的结果集返回。
尽可能使用表变量而不使用临时表。
表变量有以下特点
  • 1.表变量的行为类似于局部变量,有明确定义的作用域。该作用域为声明该变量的函数、存储过程或批处理。
    在其作用域内,表变量可像常规表那样使用。该变量可应用于 SELECT、INSERT、UPDATE 和 DELETE 语句中用到表或表的表达式的地方。但是,表不能用在下列语句中:
    INSERT INTO table_variable EXEC 存储过程。
    SELECT select_list INTO table_variable 语句。
  • 2.在定义表变量的函数、存储过程或批处理结束时,自动清除表变量。
  • 3·表类型声明中的 CHECK 约束、DEFAULT 值和计算列不能调用用户定义函数。
  • 4·在存储过程中使用表变量与使用临时表相比,减少了存储过程的重新编译量。
  • 5·涉及表变量的事务只在表变量更新期间存在。这样就减少了表变量对锁定和记录资源的需求。
  • 6·不支持在表变量之间进行赋值操作。
    declare @t1 table(t1 int)
    declare @t2 table(t2 int)
    set @t1=@t2 –错误
  • 7·另外,由于表变量作用域有限,并且不是持久数据库的一部分,因而不受事务回滚的影响。

临时表

本地临时表
本地临时表,本地临时表的名称前面有一个编号符 (#table_name).如果本地临时表由存储过程创建或由多个用户同时执行的应用程序创建,则 SQL Server 必须能够区分由不同用户创建的表。为此,SQL Server 在内部为每个本地临时表的表名追加一个数字后缀。存储在 tempdb 数据库的 sysobjects 表中的临时表,其全名由 CREATE TABLE 语句中指定的表名和系统生成的数字后缀组成。为了允许追加后缀,为本地临时表指定的表名 table_name 不能超过 116 个字符。

除非使用 DROP TABLE 语句显式除去临时表,否则临时表将在退出其作用域时由系统自动除去:

当存储过程完成时,将自动除去在存储过程中创建的本地临时表。由创建表的存储过程执行的所有嵌套存储过程都可以引用此表。但调用创建此表的存储过程的进程无法引用此表。

所有其它本地临时表在当前会话结束时自动除去。

全局临时表
全局临时表的名称前面有两个编号符 (##table_name)。
全局临时表在创建此表的会话结束且其它任务停止对其引用时自动除去。任务与表之间的关联只在单个 Transact-SQL 语句的生存周期内保持。
换言之,当创建全局临时表的会话结束时,最后一条引用此表的 Transact-SQL 语句完成后,将自动除去此表。

在存储过程或触发器中创建的本地临时表与在调用存储过程或触发器之前创建的同名临时表不同。如果查询引用临时表,而同时有两个同名的临时表,则不定义针对哪个表解析该查询。嵌套存储过程同样可以创建与调用它的存储过程所创建的临时表同名的临时表。嵌套存储过程中对表名的所有引用都被解释为是针对该嵌套过程所创建的表。

当创建本地或全局临时表时,CREATE TABLE 语法支持除 FOREIGN KEY 约束以外的其它所有约束定义。如果在临时表中指定 FOREIGN KEY 约束,该语句将返回警告信息,指出此约束已被忽略,表仍会创建,但不具有 FOREIGN KEY 约束。在 FOREIGN KEY 约束中不能引用临时表。
考虑使用表变量而不使用临时表。当需要在临时表上显式地创建索引时,或多个存储过程或函数需要使用表值时,临时表很有用。通常,表变量提供更有效的查询处理。