通用SQL

  • 保存行列数不固定的数据。

    1. 方法1: 列使用分隔符进行分割。
    2. 方法2: 使用两个表,一个表存数据的行的序号(主表),一个表的行保存(具体的数据)。最后查询的时候使用行转列的方式,根据一个id,将多行转成多列。mysql行转列(列不固定)
  • 查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断

select * from people
where peopleId in (select peopleId from people group by peopleId having count(peopleId) > 1)
  • 删除表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断,只留有rowid最小的记录
delete from people
where   peopleName in (select peopleName    from people group by peopleName      having count(peopleName) > 1)
and   peopleId not in (select min(peopleId) from people group by peopleName     having count(peopleName)>1)
  • 查找表中多余的重复记录(多个字段)
-- a.peopleId,a.seq 如果两条记录的这两个字段都相同,则判定为该记录重复
select * from vitae a
where (a.peopleId,a.seq) in (select peopleId,seq from vitae group by peopleId,seq having count(*) > 1)
  • 删除表中多余的重复记录(多个字段),只留有rowid最小的记录
delete from vitae
where (peopleId,seq) in (select peopleId,seq from vitae group by peopleId,seq having count(*) > 1)
and rowid not in (select min(rowid) from vitae group by peopleId,seq having count(*)>1)
  • 查找表中多余的重复记录(多个字段),不包含rowid最小的记录(查询出来多余的重复记录)
select * from vitae a
where (a.peopleId,a.seq) in (select peopleId,seq from vitae group by peopleId,seq having count(*) > 1)
and rowid not in (select min(rowid) from vitae group by peopleId,seq having count(*)>1)  
  • 消除一个字段的左边的第一位:
update tableName set [Title]=Right([Title],(len([Title])-1)) where Title like '村%'
  • 消除一个字段的右边的第一位:
update tableName set [Title]=left([Title],(len([Title])-1)) where Title like '%村'
  • 假删除表中多余的重复记录(多个字段),不包含rowid最小的记录
update vitae set ispass=-1
where peopleId in (select peopleId from vitae group by peopleId
  • 查找字符串在字符串中的位置,并截取字符串
-- "教师职业道德###教师职业道德的基本原理"  截取出: "教师职业道德"
select substring(question_pointsName,0,charindex('###',question_pointsName)) from examination limit 1
  • 查询年级内每个班的第一名同学/查询
select a.*  
from student_table a,
(select class_id,max(score) score from student_table group by class_id) b 
where a.class_id = b.class_id and a.score = b.score

SQLite

SQLite删除了数据但文件没变小

  • 方法1: 在数据删除后,手动执行VACUUM命令,执行方式很简单,执行命令vacuum;即可。
    VACUUM命令会清空“空闲列表”,把数据库尺寸压缩到最小,但是要耗费一些时间。
    FQA里面说,在Linux的环境下,大约0.5秒/M。并且要使用两倍于数据库文件的空间。
    我憎恨此FQA,他只说系统环境,不说机器硬件环境。我在测试手机上执行用了将近13秒时间压缩了将近3M的空间。至于它所占用的另一部分空间,是生成了一个.db-journal后缀名的临时文件。(这个问题对我现在来说是无所谓的)
  • 方法2: 在数据库文件建成时,将auto_vacuum设置成“1”。
    注意:只有在数据库中未建任何表时才能改变auto-vacuum标记。试图在已有表的情况下修改不会导致报错。
    cmd.CommandText = "PRAGMA auto_vacuum = 1;"
    cmd.ExecuteNonQuery()
    当开启auto-vacuum,当提交一个从数据库中删除除数据的事物时,数据库文件自动收缩。
    但是第二个方法同样有缺点,只会从数据库文件中截断空闲列表中的页, 而不会回收数据库中的碎片,也不会像VACUUM 命令那样重新整理数据库内容。实际上,由于需要在数据库文件中移动页, auto-vacuum 会产生更多的碎片。而且,在执行删除操作的时候,也有那个.db-journal文件产生。
    要使用auto-vacuum,需要一些前题条件。 数据库中需要存储一些额外的信息以记录它所跟踪的每个数据库页都找回其指针位置。 所以,auto-vacumm 必须在建表之前就开启。在一个表创建之后, 就不能再开启或关闭 auto-vacumm 。

其实按照运行时间上的比较,两个在做了大删除操作后,从3M变到35K的时间其实差不多,执行VACUUM命令稍微长一点,但是也长不了多少,相对而言,这种一点点的长可以忽略不计。
加上AUTO的方式对碎片的造成情况,如果数据交换次数多的话,这种方式很不合适。

SQL Server

我在工作中用过的一些关于SQL Server的使用经验

查看数据库连接数/查看数据库连接状态的几种方法

方法1

登录SQLSERVER管理软件,然后左侧面板最外层级→右键→活动和监视器
image.png

方法2

SELECT * FROM [Master].[dbo].[SYSPROCESSES] WHERE [DBID] IN 
(
  SELECT 
   [DBID]
  FROM 
   [Master].[dbo].[SYSDATABASES] 
  WHERE 
   NAME='HEKDB'
) and [Master].[dbo].[SYSPROCESSES].loginame='mba'

方法3

查询每个数据库的连接数

SELECT name, COUNT(*)
FROM (
   SELECT b.name, a.*
   FROM [Master].[dbo].[SYSPROCESSES] a
      INNER JOIN [Master].[dbo].[SYSDATABASES] b ON a.dbid = b.dbid
) t
GROUP BY t.name

查询所有活跃用户的连接: SP_WHO 'active'
查询某个用户的连接: SP_WHO 'mba' -- SP_WHO 'loginName'
查询最大连接数:SELECT @@MAX_CONNECTIONS

格式化

日期格式化

-- SQL SERVER 日期格式化/时间格式化
Select CONVERT(varchar(100), GETDATE(), 120) -- 2006-05-16 10:57:49
Select CONVERT(varchar(100), GETDATE(), 121) -- 2006-05-16 10:57:49.700
Select CONVERT(varchar(100), GETDATE(), 112) -- 20060516
Select CONVERT(varchar(100), GETDATE(), 20) -- 2006-05-16 10:57:47
Select CONVERT(varchar(100), GETDATE(), 21) -- 2006-05-16 10:57:47.157
Select CONVERT(varchar(100), GETDATE(), 25) -- 2006-05-16 10:57:47.250
Select replace(replace(replace(CONVERT(varchar(100), GETDATE(), 21),'-',''),' ','_'),':','') -- 20211109_214340.473
Select CONVERT(varchar(100), GETDATE(), 23) -- 2006-05-16
Select LEFT(CONVERT(varchar(100), GETDATE(), 112),6) -- 200605
Select convert(int,LEFT(CONVERT(varchar(100), GETDATE(), 112),6)) -- 200605 int

定时执行和延迟执行

WAITFOR TIME '22:00'; -- 等待时间到'22:00'
-- 到了'22:00'才执行这里的代码

WAITFOR DELAY '01:10:12'; -- 延时执行
-- 过01:10:12后执行这里的代码

MySQL

本章节参考文章:

字段值的大小写由mysql的校对规则来控制。提到校对规则,就不得不说字符集。字符集是一套符号和编码,校对规则是在字符集内用于比较字符的一套规则。 一般而言,校对规则以其相关的字符集名开始,通常包括一个语言名,并且以_ci(大小写不敏感)、_cs(大小写敏感)或_bin(二元)结束 。
比如 utf8字符集,如下表:

  • utf8_bin:utf8_bin将字符串中的每一个字符用二进制数据存储,区分大小写。
  • utf8_general_ci:utf8_genera_ci不区分大小写,ci为case insensitive的缩写,即大小写不敏感。
  • utf8_general_cs:utf8_general_cs区分大小写,cs为case sensitive的缩写,即大小写敏感。

注意:本文中所有用[]包裹的内容是可选的,<>包裹的内容是必填参数,比如语法格式是CREATE DATABASE [IF NOT EXISTS] <数据库名>,可以写成CREATE DATABASE mydb;或者CREATE DATABASE IF NOT EXISTS mydb;

基础知识

前置知识

  • MySQL的大小写数据库名、表名、列名、别名规则-Linux:
    • 数据库名与表名是严格区分大小写的
    • 表的别名是严格区分大小写的
    • 列名与列的别名在所有的情况下均是忽略大小写的
    • 字段内容默认情况下是大小写不敏感的。
  • MySQL的大小写数据库名、表名、列名、别名规则-Windows:
    • 大小写不敏感,所有表名和数据库名都会变成小写

设置表名不区分大小写,然后重启: set global lower_case_table_names=on;。这样查询表"users"可以使用select * from usersselect * from Usersselect * from USERS都可以
my.cnf 是MySQL 的配置文件,修改之前记得先备份:vi /etc/my.cnf

因为历史遗留问题,MySQL 中的 utf8 编码并不是真正的 UTF-8,而是阉割版的,最长只有3个字节。当遇到占4个字节的 UTF-8 编码,例如 emoji 字符或者复杂的汉字,会导致存储异常。从 5.5.3 开始,MySQL 开始用 utf8mb4 编码来实现完整的 UTF-8,其中 mb4 表示 most bytes 4,最多占用4个字节。从 8.0 之后,将会在某个版本开始用 utf8mb4 作为默认字符编码。

在Linux和Windows平台。
MySQL在Linux下数据库名、表名、列名、别名大小写规则是这样的:
   1、数据库名与表名是严格区分大小写的;
   2、表的别名是严格区分大小写的;
   3、列名与列的别名在所有的情况下均是忽略大小写的;
   4、变量名也是严格区分大小写的;

而Windows下的MySQL却是大小写不敏感的,所有表名和数据库名都会变成小写。

区分大小写的几种方法:

  1. 查询时区分大小写,只需在需要区分查询的字段前加上关键字BINARY: select * from tb_user where BINARY username ='user';
  2. 建表时使用BINARY关键字给指定字段设置查询和排序..等操作时区分大小写
CREATE TABLE `tb_user1` (
	`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户id',
	`username` VARCHAR(50) BINARY  NOT NULL COMMENT '用户名',
	PRIMARY KEY (`id`)
) ENGINE = INNODB CHARSET = utf8mb4 COMMENT '用户表';
  1. 建表时给整个表的所有字符字段区分大小写,将COLLATE的值设置为区分大小写,以bin结尾的就是区分大小写,以ci结尾的就是不区分大小写:
CREATE TABLE `tb_user2` (
    `id` BIGINT (20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户id',
    `username` VARCHAR (50) NOT NULL COMMENT '用户名',
    `info` VARCHAR (100) NOT NULL COMMENT '详情描述',
    PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8_bin COMMENT = '用户表';

show collation; -- 查看所有mysql所支持的所有COLLATE
select version() from dual; -- 查询MySQL版本
SHOW CHARACTER set; -- 查看支持的字符集方法1
SELECT * FROM information_schema.character_sets; -- 查看支持的字符集方法2
SHOW COLLATION LIKE 'utf8%'; -- 查看相关字符集的校对规则

ai表示accent insensitivity,也就是“不区分音调”,排序时e,è,é,ê和ë之间没有区别。
而ci表示case insensitivity,也就是“不区分大小写”,排序时p和P之间没有区别。
uft8mb4 表示用 UTF-8 编码方案,每个字符最多占4个字节。

collation其实是用来排序的规则。对于mysql中那些字符类型的列,如VARCHAR,CHAR,TEXT类型的列,都需要有一个COLLATE类型来告知mysql如何对该列进行排序和比较。简而言之,COLLATE会影响到ORDER BY语句的顺序,会影响到WHERE条件中大于小于号筛选出来的结果,会影响DISTINCTGROUP BYHAVING语句的查询结果。mysql建索引的时候,如果索引列是字符类型,也会影响索引创建,只不过这种影响我们感知不到。总之,凡是涉及到字符类型比较或排序的地方,都会和COLLATE有关。

操作数据库

创建数据库

语法格式:
CREATE DATABASE [IF NOT EXISTS] <数据库名>
[[DEFAULT] CHARACTER SET <字符集名>]
[[DEFAULT] COLLATE <校对规则名>];

语法说明:

  • []中的内容是可选的
  • <数据库名>: 创建数据库的名称。MySQL 的数据存储区将以目录方式表示 MySQL 数据库,因此数据库名称必须符合操作系统的文件夹命名规则,不能以数字开头,尽量要有实际意义。注意在 MySQL 中不区分大小写。
  • IF NOT EXISTS: 在创建数据库之前进行判断,只有该数据库目前尚不存在时才能执行操作。此选项可以用来避免数据库已经存在而重复创建的错误。
    +[DEFAULT] CHARACTER SET: 指定数据库的字符集。指定字符集的目的是为了避免在数据库中存储的数据出现乱码的情况。如果在创建数据库时不指定字符集,那么就使用系统的默认字符集。
  • [DEFAULT] COLLATE: 指定字符集的默认校对规则。

utf8mb4对应的排序字符集有 utf8mb4_unicode_ci 、 utf8mb4_general_ci ,推荐使用 utf8mb4_unicode_ci
例子: CREATE DATABASE IF NOT EXISTS fcj_db_prod DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_bin;

删除数据库

删除数据库的语法格式为: DROP DATABASE [IF EXISTS] <数据库名>;

查询数据库信息

  • 查询数据的定义声明L: SHOW CREATE DATABASE test_db;
  • 查看所有数据库: show databases;
  • 查看当前使用的数据库: select database();
  • 查看数据库使用端口: show variables like 'port';
  • 查看数据库中的所有表: show tables;show tables from <db_name>;
  • 查看数据库编码: show variables like 'character%';, 只要保证以下采用的编码方式一样,就不会出现乱码问题( character_set_filesystem 、character_set_system 、 character_sets_dir 除外)。
    • character_set_client: 客户端请求数据的字符集
    • character_set_connection: 从客户端接收到数据,传输数据时使用的字符集
    • character_set_server: 数据库服务器的默认字符集
    • character_set_database: 数据库的字符集
    • character_set_results: 结果集的字符集
    • character_set_filesystem: 把操作系统上的文件名转化成此字符集,即把 character_set_client 转换 character_set_filesystem, 默认值为binary是不做任何转换的
    • character_set_system: 存储系统元数据的字符集,总是 utf8,不需要设置,创建数据库时指定字符集为 utf8mb4
    • character_sets_dir:

修改数据库信息

用 ALTER DATABASE 来修改已经被创建或者存在的数据库的相关参数。修改数据库的语法格式为:
ALTER DATABASE <数据库名> { [ DEFAULT ] CHARACTER SET <字符集名> | [ DEFAULT ] COLLATE <校对规则名> }
比如: ALTER DATABASE test_db DEFAULT CHARACTER SET gb2312 DEFAULT COLLATE gb2312_chinese_ci;

语法说明:

  • ALTER DATABASE 用于更改数据库的全局特性。
  • 使用 ALTER DATABASE 需要获得数据库 ALTER 权限。
  • 数据库名称可以忽略,此时语句对应于默认数据库。
  • CHARACTER SET 子句用于更改默认的数据库字符集。

操作表

创建表

语法: CREATE TABLE <table_name> (column_name1 column_type1, column_name2 column_type2);

CREATE TABLE IF NOT EXISTS `runoob_tbl`(
   `runoob_id` INT UNSIGNED AUTO_INCREMENT,
   `runoob_title` VARCHAR(100) NOT NULL,
   `runoob_author` VARCHAR(40) NOT NULL,
   `submission_date` DATE,
   PRIMARY KEY ( `runoob_id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 说明: 
-- 如果你不想字段为 NULL 可以设置字段的属性为 NOT NULL, 在操作数据库时如果输入该字段的数据为NULL ,就会报错。
-- AUTO_INCREMENT定义列为自增的属性,一般用于主键,数值会自动加1。
-- PRIMARY KEY关键字用于定义列为主键。 您可以使用多列来定义主键,列间以逗号分隔。

ENGINE 设置存储引擎,CHARSET 设置编码。

删除表

drop table students;

查询表信息

  • 列出表的字段信息/查看表结构: show columns from <table_name>;desc <table_name>;
  • 查看数据表当时创建表的语句: show create table <table_name>;

修改表信息

  • 增添表字段: alter table 表名 add 列名 类型/约束,例如alter table students add brithday datetime default '2011-11-11 11:11:11';
  • 删除表字段: alter table students drop brith;
  • 查询表字段: show columns from <table_name>;desc <table_name>;
  • 修改表字段:
    • 使用modify修改字段类型: alter table 表名 modify 列名 类型及约束,例如alter table students modify brithday date default '2011-11-11';
    • 使用change修改字段名或字段类型: alter table 表名 change 原列名 新列名 类型及约束,例如alter table students change brithday brith date default '2011-11-11';

change和modify的区别

  • change: 可以更改字段名和字段类型 (每次都要把新列名和旧列名写上, 即使两个列名没有更改,只是改了类型)
  • modify: 只能更改列属性 只需要写一次列名, 比change 省事点

操作数据

增添数据

  • 新增单条数据
    • 方式1: insert into students values (0,'小乔',18,180.00,'女',2);
    • 方式2: insert into students(name,age,high,gender) values('张飞',20,190.00,'女');
  • 新增多条数据
    • 方式1: insert into students values(0,'孙尚香',18,180.00,'女',2),(1,'孙悟空',15,170.00,'男',2);
    • 方式2: insert into students(name,age,high,gender) values(0,'孙尚香',18,180.00,'女',2),(1,'孙悟空',15,170.00,'男',2);

删除数据

delete from students where id=4;

查询数据

select distinct * from 表名 where … group by … having … order by … limit start,count

修改数据

update students set age=20 where id=5;

15000 字的 SQL 语句大全

转载自链接:cnblogs.com/liuqifeng/p/9148831.html

基础

  • 创建数据库: CREATE DATABASE database-name
  • 删除数据库: drop database dbname
  • 备份sql server
--- 创建 备份数据的 device  
USE master  
EXEC sp_addumpdevice 'disk', 'testBack', 'c:\mssql7backup\MyNwind_1.dat'  

--- 开始 备份  
BACKUP DATABASE pubs TO testBack 
  • 创建新表: create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)
  • 参考旧表创建结构一模一样的新表: create table tab_new like tab_old
  • 参考旧表中的某些字段来创建新表: create table tab_new as select col1,col2… from tab_old definition only
  • 删除表: drop table tabname
  • 新增字段/增加一个列:Alter table tabname add column col type
  • 添加主键:Alter table tabname add primary key(col)
  • 删除主键:Alter table tabname drop primary key(col)
  • 创建索引:create [unique] index idxname on tabname(col….)
  • 删除索引:drop index idxname(注:索引是不可更改的,想更改必须删除重新建)
  • 创建视图:create view viewname as select statement
  • 删除视图:drop view viewname
  • 几个简单的基本的sql语句
    • 选择: select * from table1 where 范围
    • 插入: insert into table1(field1,field2) values(value1,value2)
    • 删除: delete from table1 where 范围更新:update table1 set field1=value1 where 范围
    • 查找: select * from table1 where field1 like ’%value1%’ ---like的语法很精妙,查资料
    • 排序: select * from table1 order by field1,field2 [desc]
    • 总数: select count as totalcount from table1
    • 求和: select sum(field1) as sumvalue from table1
    • 平均: select avg(field1) as avgvalue from table1
    • 最大: select max(field1) as maxvalue from table1
    • 最小: select min(field1) as minvalue from table1
  • 几个高级查询运算词
    • UNION 运算符: UNION 运算符通过组合其他两个结果表(例如 TABLE1 和 TABLE2)并消去表中任何重复行而派生出一个结果表。当 ALL 随 UNION 一起使用时(即 UNION ALL),不消除重复行。两种情况下,派生表的数据行是 TABLE1 和 TABLE2 两个表并集的结果。
    • EXCEPT 运算符: EXCEPT运算符通过包括所有在 TABLE1 中但不在 TABLE2 中的行并消除所有重复行而派生出一个结果表。当 ALL 随 EXCEPT 一起使用时 (EXCEPT ALL),不消除重复行。
    • INTERSECT 运算符: INTERSECT运算符通过只包括 TABLE1 和 TABLE2 中都有的行并消除所有重复行而派生出一个结果表。当 ALL随 INTERSECT 一起使用时 (INTERSECT ALL),不消除重复行。
      注:使用运算词的几个查询结果行必须是一致的。
  • left (outer) join: 左外连接(左连接),结果集几包括连接表的匹配行,也包括左连接表的所有行。 比如: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
  • right (outer) join: 右外连接(右连接),结果集既包括连接表的匹配连接行,也包括右连接表的所有行。
  • full/cross (outer) join: 全外连接,不仅包括符号连接表的匹配行,还包括两个连接表中的所有记录。
  • group by: 分组,一张表,一旦分组后,查询后只能得到组相关的信息,比如: count,sum,max,min,avg。注意:在SQLServer中分组时不能以text,ntext,image类型的字段作为分组依据;在selecte统计函数中的字段,不能和普通的字段放在一起;
  • 分离数据库: sp_detach_db;
  • 附加数据库:sp_attach_db 后接表名,附加需要完整的路径名
  • 修改数据库的名称: sp_renamedb 'old_name', 'new_name'

提升

  • 复制表(只复制结构,源表名:a 新表名:b) (Access数据库可用)
    • 方法1:select * into b from a where 1<>1(仅用于SQlServer)
    • 方法2:select top 0 * into b from a
  • 拷贝表(拷贝数据,源表名:a 目标表名:b) (Access数据库可用) : insert into b(a, b, c) select d,e,f from b;
  • 跨数据库之间表的拷贝(具体数据使用绝对路径) (Access数据库可用)
    insert into b(a, b, c) select d,e,f from b in ‘具体数据库’ where 条件,例子:..from b in '"&Server.MapPath(".")&"\data.mdb" &"' where..
  • 子查询(表名1:a 表名2:b)
    select a,b,c from a where a IN (select d from b ) 或者: select a,b,c from a where a IN (1,2,3)
  • 显示文章、提交人和最后回复时间
    select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b
  • 外连接查询(表名1:a 表名2:b)
    select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
  • 在线视图查询(表名1:a )
    select * from (SELECT a,b,c FROM a) T where t.a > 1;
  • between的用法,between限制查询数据范围时包括了边界值(含头不含尾?),not between不包括。
    • select * from table1 where time between time1 and time2
    • select a,b,c, from table1 where a not between 数值1 and 数值2
  • in 的使用方法
    select * from table1 where a [not] in (‘值1’,’值2’,’值4’,’值6’)
  • 两张关联表,删除主表中已经在副表中没有的信息
    delete from table1 where not exists ( select * from table2 where table1.field1=table2.field1 )
  • 四表联查问题:
    select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....
  • 日程安排提前五分钟提醒: select * from 日程安排 where datediff('minute',f开始时间,getdate())>5
  • 一条sql 语句搞定数据库分页
    select top 10 b.* from (select top 20 主键字段,排序字段 from 表名 order by 排序字段 desc) a,表名 b where b.主键字段 = a.主键字段 order by a.排序字段
    数据库分页:
    declare @start int,@end int @sql nvarchar(600) set @sql=’select top’+str(@end-@start+1)+’+from T where rid not in(select top’+str(@str-1)+’Rid from T where Rid>-1)’ exec sp_executesql @sql,注意:在top后不能直接跟一个变量,所以在实际应用中只有这样的进行特殊的处理。Rid为一个标识列,如果top后还有具体的字段,这样做是非常有好处的。因为这样可以避免 top的字段如果是逻辑索引的,查询的结果后实际表中的不一致(逻辑索引中的数据有可能和数据表中的不一致,而查询时如果处在索引则首先查询索引)
  • 前10条记录: select top 10 * form table1
  • 选择在每一组b值相同的数据中对应的a最大的记录的所有信息(类似这样的用法可以用于论坛每月排行榜,每月热销产品分析,按科目成绩排名,等等.): select a,b,c from tablename ta where a=(select max(a) from tablename tb where tb.b=ta.b)
  • 包括所有在 TableA中但不在 TableB和TableC中的行并消除所有重复行而派生出一个结果表 :(select a from tableA ) except (select a from tableB) except (select a from tableC)
  • 随机取出10条数据: select top 10 * from tablename order by newid()
  • 随机选择记录: select newid()
  • 删除重复记录
  1. delete from tablename where id not in (select max(id) from tablename group by col1,col2,...)
  2. select distinct * into temp from tablename
    delete from tablename
    insert into tablename select * from temp
    评价:这种操作牵连大量的数据的移动,这种做法不适合大容量但数据操作
  3. 例如:在一个外部表中导入数据,由于某些原因第一次只导入了一部分,但很难判断具体位置,这样只有在下一次全部导入,这样也就产生好多重复的字段,怎样删除重复字段

alter table tablename--添加一个自增列add column_b int identity(1,1) delete from tablename where column_b not in(select max(column_b) from tablename group by column1,column2,...)alter table tablename drop column column_b

  • 列出数据库里所有的表名: select name from sysobjects where type='U' -- U代表用户
  • 列出表里的所有的列名:select name from syscolumns where id=object_id('TableName')
  • 列示type、vender、pcs字段,以type字段排列,case可以方便地实现多重选择,类似select 中的case。
    select type,sum(case vender when 'A' then pcs else 0 end),sum(case vender when 'C' then pcs else 0 end),sum(case vender when 'B' then pcs else 0 end) FROM tablename group by type
    显示结果:
    type vender pcs
    电脑 A 1
    电脑 A 1
    光盘 B 2
    光盘 A 2
    手机 B 3
    手机 C 3
  • (慎用)初始化表table1/清空表中的数据/重置表为创建的初识状态:TRUNCATE TABLE <表名>
  • 选择从10到15的记录: select top 5 * from (select top 15 * from table order by id asc) table_别名 order by id desc

技巧

  • 1=1,1=2的使用,在SQL语句组合时用的较多
    “where 1=1” 是表示选择全部“where 1=2”全部不选,
    如:if @strWhere !='' beginset @strSQL = 'select count(*) as Total from [' + @tblName + '] where ' + @strWhereendelse beginset @strSQL = 'select count(*) as Total from [' + @tblName + ']' end
    我们可以直接写成
    set @strSQL = 'select count(*) as Total from [' + @tblName + '] where 1=1 安定 '+ @strWhere
  • 收缩数据库
    --重建索引
    DBCC REINDEX
    DBCC INDEXDEFRAG
    --收缩数据和日志
    DBCC SHRINKDB
    DBCC SHRINKFILE
  • 压缩数据库
    dbcc shrinkdatabase(dbname)
  • 转移数据库给新用户以已存在用户权限
    exec sp_change_users_login 'update_one','newname','oldname'
    go
  • 检查备份集: RESTORE VERIFYONLY from disk='E:\dvbbs.bak'
  • 修复数据库
ALTER DATABASE [dvbbs] SET SINGLE_USER  
GO

DBCC CHECKDB('dvbbs',repair_allow_data_loss) WITH TABLOCK  
GO

ALTER DATABASE [dvbbs] SET MULTI_USER  
GO
  • 日志清除
SET NOCOUNT ON  
DECLARE @LogicalFileName sysname,@MaxMinutes INT,@NewSize INT
USE tablename -- 要操作的数据库名  
SELECT  @LogicalFileName = 'tablename_log', -- 日志文件名  
@MaxMinutes = 10, -- Limit on time allowed to wrap log.  
	@NewSize = 1  -- 你想设定的日志文件的大小(M)
Setup / initialize

DECLARE @OriginalSize int

SELECT @OriginalSize = size   
FROM sysfiles  
WHERE name = @LogicalFileName

SELECT 'Original Size of ' + db_name() + ' LOG is ' +   
CONVERT(VARCHAR(30),@OriginalSize) + ' 8K pages or ' +   
CONVERT(VARCHAR(30),(@OriginalSize*8/1024)) + 'MB'  
FROM sysfiles  
WHERE name = @LogicalFileName

CREATE TABLE DummyTrans (DummyColumn char (8000) not null)
DECLARE @Counter INT,@StartTime DATETIME,@TruncLog   VARCHAR(255)  
SELECT @StartTime = GETDATE(),@TruncLog = 'BACKUP LOG ' + db_name() + ' WITH TRUNCATE_ONLY'
DBCC SHRINKFILE (@LogicalFileName, @NewSize)  
EXEC (@TruncLog)
-- Wrap the log if necessary.  
WHILE @MaxMinutes > DATEDIFF (mi, @StartTime, GETDATE()) -- time has not expired  
AND @OriginalSize = (SELECT size FROM sysfiles WHERE name = @LogicalFileName)    
AND (@OriginalSize * 8 /1024) > @NewSize    
BEGIN -- Outer loop.

	SELECT @Counter = 0  
		WHILE   ((@Counter < @OriginalSize / 16) AND (@Counter < 50000))  
		BEGIN -- update  
			INSERT DummyTrans VALUES ('Fill Log') DELETE DummyTrans  
			SELECT @Counter = @Counter + 1  
		END  
	EXEC (@TruncLog)    
END

SELECT 'Final Size of ' + db_name() + ' LOG is ' +  
	CONVERT(VARCHAR(30),size) + ' 8K pages or ' +   
	CONVERT(VARCHAR(30),(size*8/1024)) + 'MB'  
	FROM sysfiles   
	WHERE name = @LogicalFileName  
DROP TABLE DummyTrans  
SET NOCOUNT OFF
  • 更改某个表
    exec sp_changeobjectowner 'tablename','dbo'
  • 存储更改全部表
CREATE PROCEDURE dbo.User_ChangeObjectOwnerBatch  
@OldOwner as NVARCHAR(128),  
@NewOwner as NVARCHAR(128)  
AS
DECLARE @Name    as NVARCHAR(128)  
DECLARE @Owner   as NVARCHAR(128)  
DECLARE @OwnerName   as NVARCHAR(128)
DECLARE curObject CURSOR FOR   
select 'Name'    = name,  
   'Owner'    = user_name(uid)  
from sysobjects  
where user_name(uid)=@OldOwner  
order by name
OPEN   curObject  
FETCH NEXT FROM curObject INTO @Name, @Owner  
WHILE(@@FETCH_STATUS=0)  
BEGIN       
if @Owner=@OldOwner   
begin  
   set @OwnerName = @OldOwner + '.' + rtrim(@Name)  
   exec sp_changeobjectowner @OwnerName, @NewOwner  
end  
-- select @name,@NewOwner,@OldOwner
FETCH NEXT FROM curObject INTO @Name, @Owner  
END
close curObject  
deallocate curObject  
GO
  • SQL SERVER中直接循环写入数据
declare @i int  
set @i=1  
while @i<30  
begin  
    insert into test (userid) values(@i)  
    set @i=@i+1  
end  

案例:
有如下表,要求就裱中所有沒有及格的成績,在每次增長0.1的基礎上,使他們剛好及格:
|Name|scor|
|Zhangshan|80|
|Lishi|59|
|Wangwu|50|
|Songquan|69|

while((select min(score) from tb_table)<60) 
begin
update tb_table set score =score*1.01
where score<60
if  (select min(score) from tb_table)>60
  break
 else
    continue
end

数据开发-经典

  • 按姓氏笔画排序:Select * From TableName Order By CustomerName Collate Chinese_PRC_Stroke_ci_as //从少到多
  • 数据库加密
    • select encrypt('原始密码')
    • select pwdencrypt('原始密码')
    • select pwdcompare('原始密码','加密后密码') = 1--相同;否则不相同 encrypt('原始密码')
    • select pwdencrypt('原始密码')
    • select pwdcompare('原始密码','加密后密码') = 1--相同;否则不相同
  • 取回表中字段:
declare @list varchar(1000),  
@sql nvarchar(1000)   
select @list=@list+','+b.name from sysobjects a,syscolumns b where a.id=b.id and a.name='表A'  
set @sql='select '+right(@list,len(@list)-1)+' from 表A'   
exec (@sql)
  • 查看硬盘分区: EXEC master..xp_fixeddrives
  • 比较A,B表是否相等:
if (select checksum_agg(binary_checksum(*)) from A)  
     =  
    (select checksum_agg(binary_checksum(*)) from B)  
print '相等'  
else  
print '不相等'
  • 杀掉所有的事件探察器进程:
DECLARE hcforeach CURSOR GLOBAL FOR SELECT 'kill '+RTRIM(spid) FROM master.dbo.sysprocesses  
WHERE program_name IN('SQL profiler',N'SQL 事件探查器')  
EXEC sp_msforeach_worker '?'
  • 开头到N条记录: Select Top N * From 表
  • N到M条记录(要有主索引ID) Select Top M-N * From 表 Where ID in (Select Top M ID From 表) Order by ID Desc
  • N到结尾记录Select Top N * From 表 Order by ID Desc
  • 例1:一张表有一万多条记录,表的第一个字段 RecID 是自增长字段, 写一个SQL语句, 找出表的第31到第40个记录。
    • select top 10 recid from A where recid not in(select top 30 recid from A)
    • 分析:如果这样写会产生某些问题,如果recid在表中存在逻辑索引。
    • select top 10 recid from A where……是从索引中查找,而后面的select top 30 recid from A则在数据表中查找,这样由于索引中的顺序有可能和数据表中的不一致,这样就导致查询到的不是本来的欲得到的数据。解决方案:
      • 用order by select top 30 recid from A order by ricid 如果该字段不是自增长,就会出现问题
      • 在那个子查询中也加条件:select top 30 recid from A where recid>-1
  • 例2:查询表中的最后以条记录,并不知道这个表共有多少数据,以及表结构。
    set @s = 'select top 1 * from T where pid not in (select top ' + str(@count-1) + ' pid from T)' print @s exec sp_executesql @s
  • 获取当前数据库中的所有用户表
    select Name from sysobjects where xtype='u' and status>=0
  • 获取某一个表的所有字段
select name from syscolumns where id=object_id('表名')
-- 或者(两种方式的效果相同)
select name from syscolumns where id in (select id from sysobjects where type = 'u' and name = '表名')
  • 查看与某一个表相关的视图、存储过程、函数: select a.* from sysobjects a, syscomments b where a.id = b.id and b.text like '%表名%'
  • 查看当前数据库中所有存储过程: select name as 存储过程名称 from sysobjects where xtype='P'
  • 查询用户创建的所有数据库
select * from master..sysdatabases D where sid not in(select sid from master..syslogins where name='sa')  
-- 或者
select dbid, name AS DB_NAME from master..sysdatabases where sid <> 
  • 查询某一个表的字段和数据类型: select column_name,data_type from information_schema.columns where table_name = '表名'
  • 不同服务器数据库之间的数据操作
--创建链接服务器
exec sp_addlinkedserver 'ITSV ', ' ', 'SQLOLEDB ', '远程服务器名或ip地址 '
exec sp_addlinkedsrvlogin 'ITSV ', 'false ',null, '用户名 ', '密码 '

--查询示例
select * from ITSV.数据库名.dbo.表名

--导入示例
select * into 表 from ITSV.数据库名.dbo.表名

--以后不再使用时删除链接服务器
exec sp_dropserver 'ITSV ', 'droplogins '

--连接远程/局域网数据(openrowset/openquery/opendatasource)
--1、openrowset
--查询示例
select * from openrowset( 'SQLOLEDB ', 'sql服务器名 '; '用户名 '; '密码 ',数据库名.dbo.表名)

--生成本地表
select * into 表 from openrowset( 'SQLOLEDB ', 'sql服务器名 '; '用户名 '; '密码 ',数据库名.dbo.表名)

--把本地表导入远程表
insert openrowset( 'SQLOLEDB ', 'sql服务器名 '; '用户名 '; '密码 ',数据库名.dbo.表名) select * from 本地表

--从远程表更新本地表
update b set b.列A=a.列A from openrowset( 'SQLOLEDB ', 'sql服务器名 '; '用户名 '; '密码 ',数据库名.dbo.表名)as a inner join 本地表 b on a.column1=b.column1

--openquery用法需要创建一个连接
--首先创建一个连接创建链接服务器
exec sp_addlinkedserver 'ITSV ', ' ', 'SQLOLEDB ', '远程服务器名或ip地址 '

--查询
select * FROM openquery(ITSV, 'SELECT * FROM 数据库.dbo.表名 ')

--把本地表导入远程表
insert openquery(ITSV, 'SELECT * FROM 数据库.dbo.表名 ') select * from 本地表

--更新本地表
update b set b.列B=a.列B FROM openquery(ITSV, 'SELECT * FROM 数据库.dbo.表名 ') as a inner join 本地表 b on a.列A=b.列A

--3、opendatasource/openrowset
SELECT   * FROM   opendatasource( 'SQLOLEDB ', 'Data Source=ip/ServerName;User ID=登陆名;Password=密码 ' ).test.dbo.roy_ta

--把本地表导入远程表
insert opendatasource( 'SQLOLEDB ', 'Data Source=ip/ServerName;User ID=登陆名;Password=密码 ').数据库.dbo.表名 select * from 本地表

SQL Server基本函数

  • 字符串函数 长度与分析用
    • datalength(Char_expr) 返回字符串包含字符数,但不包含后面的空格
    • substring(expression,start,length) 取子串,字符串的下标是从“1”,start为起始位置,length为字符串长度,实际应用中以len(expression)取得其长度
    • right(char_expr,int_expr) 返回字符串右边第int_expr个字符,还用left于之相反
    • isnull( *check*_*expression* , *replacement_value* )如果check_expression为空,则返回replacement_value的值,不为空,就返回check_expression字符操作类
    • Sp_addtype自定义数据类型,例如:EXEC sp_addtype birthday, datetime, 'NULL' set nocount {on|off}

使返回的结果中不包含有关受 Transact-SQL 语句影响的行数的信息。如果存储过程中包含的一些语句并不返回许多实际的数据,则该设置由于大量减少了网络流量,因此可显著提高性能。SET NOCOUNT 设置是在执行或运行时设置,而不是在分析时设置。

SET NOCOUNT 为 ON 时,不返回计数(表示受 Transact-SQL 语句影响的行数)。
SET NOCOUNT 为 OFF 时,返回计数

常识

  • 在SQL查询中:from后最多可以跟多少张表或视图:256
  • 在SQL语句中出现 Order by,查询时是,先排序,后取
  • 在SQL中,一个字段的最大容量是8000,而对于nvarchar(4000),由于nvarchar是Unicode码。

SQLServer2000同步复制技术实现步骤

预备工作

  • 发布服务器,订阅服务器都创建一个同名的windows用户,并设置相同的密码,做为发布快照文件夹的有效访问用户
    1. 管理工具
    2. 计算机管理
    3. 用户和组
    4. 右键用户
    5. 新建用户
    6. 建立一个隶属于administrator组的登陆windows的用户(SynUser)
  • 在发布服务器上,新建一个共享目录,做为发布的快照文件的存放目录,操作:
    1. 我的电脑--D:\ 新建一个目录,名为: PUB
    2. 右键这个新建的目录
    3. 属性--共享
    4. 选择"共享该文件夹"
    5. 通过"权限"按纽来设置具体的用户权限,保证第一步中创建的用户(SynUser) 具有对该文件夹的所有权限
    6. 确定
  • 设置SQL代理(SQLSERVERAGENT)服务的启动用户(发布/订阅服务器均做此设置)
    1. 开始--程序--管理工具--服务
    2. 右键SQLSERVERAGENT
    3. 属性--登陆--选择"此账户"
    4. 输入或者选择第一步中创建的windows登录用户名(SynUser)
    5. "密码"中输入该用户的密码
  • 设置SQL Server身份验证模式,解决连接时的权限问题(发布/订阅服务器均做此设置)
    1. 打开企业管理器
    2. 右键SQL实例--属性
    3. 安全性--身份验证
    4. 选择"SQL Server 和 Windows"
    5. 确定
  • 在发布服务器和订阅服务器上互相注册
    1. 打开企业管理器
    2. 右键SQL Server组
    3. 新建SQL Server注册...
    4. 下一步--可用的服务器中,输入你要注册的远程服务器名 --添加
    5. 下一步--连接使用,选择第二个"SQL Server身份验证"
    6. 下一步--输入用户名和密码(SynUser)
    7. 下一步--选择SQL Server组,也可以创建一个新组
    8. 下一步--完成
  • 对于只能用IP,不能用计算机名的,为其注册服务器别名(此步在实施中没用到)(在连接端配置,比如,在订阅服务器上配置的话,服务器名称中输入的是发布服务器的IP)
    1. 开始--程序--Microsoft SQL Server--客户端网络实用工具
    2. 别名--添加
    3. 网络库选择"tcp/ip"--服务器别名输入SQL服务器名
    4. 连接参数--服务器名称中输入SQL服务器ip地址
    5. 如果你修改了SQL的端口,取消选择"动态决定端口",并输入对应的端口号

正式配置

  • 配置发布服务器
    打开企业管理器,在发布服务器(B、C、D)上执行以下步骤:
    (1) 从[工具]下拉菜单的[复制]子菜单中选择[配置发布、订阅服务器和分发]出现配置发布和分发向导
    (2) [下一步] 选择分发服务器 可以选择把发布服务器自己作为分发服务器或者其他sql的服务器(选择自己)
    (3) [下一步] 设置快照文件夹
    采用默认\servername\Pub
    (4) [下一步] 自定义配置
    可以选择:是,让我设置分发数据库属性启用发布服务器或设置发布设置
    否,使用下列默认设置(推荐)
    (5) [下一步] 设置分发数据库名称和位置 采用默认值
    (6) [下一步] 启用发布服务器 选择作为发布的服务器
    (7) [下一步] 选择需要发布的数据库和发布类型
    (8) [下一步] 选择注册订阅服务器
    (9) [下一步] 完成配置

  • 创建出版物
    发布服务器B、C、D上
    (1)从[工具]菜单的[复制]子菜单中选择[创建和管理发布]命令
    (2)选择要创建出版物的数据库,然后单击[创建发布]
    (3)在[创建发布向导]的提示对话框中单击[下一步]系统就会弹出一个对话框。对话框上的内容是复制的三个类型。我们现在选第一个也就是默认的快照发布(其他两个大家可以去看看帮助)
    (4)单击[下一步]系统要求指定可以订阅该发布的数据库服务器类型,
    SQLSERVER允许在不同的数据库如 orACLE或ACCESS之间进行数据复制。
    但是在这里我们选择运行"SQL SERVER 2000"的数据库服务器
    (5)单击[下一步]系统就弹出一个定义文章的对话框也就是选择要出版的表
    注意: 如果前面选择了事务发布 则再这一步中只能选择带有主键的表
    (6)选择发布名称和描述
    (7)自定义发布属性 向导提供的选择:
    是 我将自定义数据筛选,启用匿名订阅和或其他自定义属性
    否 根据指定方式创建发布 (建议采用自定义的方式)

(8)[下一步] 选择筛选发布的方式
(9)[下一步] 可以选择是否允许匿名订阅
1)如果选择署名订阅,则需要在发布服务器上添加订阅服务器
方法: [工具]->[复制]->[配置发布、订阅服务器和分发的属性]->[订阅服务器] 中添加
否则在订阅服务器上请求订阅时会出现的提示:改发布不允许匿名订阅
如果仍然需要匿名订阅则用以下解决办法
[企业管理器]->[复制]->[发布内容]->[属性]->[订阅选项] 选择允许匿名请求订阅
2)如果选择匿名订阅,则配置订阅服务器时不会出现以上提示

(10)[下一步] 设置快照 代理程序调度
(11)[下一步] 完成配置
当完成出版物的创建后创建出版物的数据库也就变成了一个共享数据库
有数据
srv1.库名..author有字段:id,name,phone,
srv2.库名..author有字段:id,name,telphone,adress
要求:
srv1.库名..author增加记录则srv1.库名..author记录增加
srv1.库名..author的phone字段更新,则srv1.库名..author对应字段telphone更新
--/
--大致的处理步骤
--1.在 srv1 上创建连接服务器,以便在 srv1 中操作 srv2,实现同步
exec sp_addlinkedserver 'srv2','','SQLOLEDB','srv2的sql实例名或ip'
exec sp_addlinkedsrvlogin 'srv2','false',null,'用户名','密码'
go
--2.在 srv1 和 srv2 这两台电脑中,启动 msdtc(分布式事务处理服务),并且设置为自动启动
。我的电脑--控制面板--管理工具--服务--右键 Distributed Transaction Coordinator--属性--启动--并将启动类型设置为自动启动
go
--然后创建一个作业定时调用上面的同步处理存储过程就行了
企业管理器
--管理
--SQL Server代理
--右键作业
--新建作业
--"常规"项中输入作业名称
--"步骤"项
--新建
--"步骤名"中输入步骤名
--"类型"中选择"Transact-SQL 脚本(TSQL)"
--"数据库"选择执行命令的数据库
--"命令"中输入要执行的语句: exec p_process
--确定
--"调度"项
--新建调度
--"名称"中输入调度名称
--"调度类型"中选择你的作业执行安排
--如果选择"反复出现"
--点"更改"来设置你的时间安排
然后将SQL Agent服务启动,并设置为自动启动,否则你的作业不会被执行
设置方法:

我的电脑--控制面板--管理工具--服务--右键 SQLSERVERAGENT--属性--启动类型--选择"自动启动"--确定.
--3.实现同步处理的方法2,定时同步
--在srv1中创建如下的同步处理存储过程

create proc p_process as--更新修改过的数据update b set name=i.name,telphone=i.telphonefrom srv2.库名.dbo.author b,author iwhere b.id=i.id and(b.name <> i.name or b.telphone <> i.telphone)--插入新增的数据insert srv2.库名.dbo.author(id,name,telphone)select id,name,telphone from author iwhere not exists(select * from srv2.库名.dbo.author where id=i.id)--删除已经删除的数据(如果需要的话)delete bfrom srv2.库名.dbo.author bwhere not exists(select * from author where id=b.id)go


-END-

Q.E.D.


做一个热爱生活的人