数据库相关及SQL语句(MySQL和SqlServer)基础

以下是我自己开发的总结,欢迎指正。

0.概括

sql语句的大小写问题,要根据数据库的大小写敏感配置而决定,以下随意。

数据库建模软件PowerDesigner要熟练使用,了解物理模型生成建表sql和对数据库进行逆向工程建模,会操作即可。

sqlserver中注意事项:

★表名之前加 dbo  如: select id from dbo.usertable  开发时最好都加上 dbo

因为 dbo 是 database owner(数据库所有者) 的缩写。对应于创建该数据库的登录用户,即所有的数据库的dbo都对应sa账户。
用户权限所致。如果你用SA登录,查询本服务器里的数据库是不用加DBO的。
但如果你做跨服务器查询时就要用到DBO。 如 select * from 远程服务器.数据库名.dbo.table1

sqlserver跨服务器查询,有时间探讨 https://www.cnblogs.com/tylerflyn/p/8339895.html                                       https://www.cnblogs.com/vinsonLu/p/4456027.html

可以把开发者理解为 用户,dbo 理解为数据库中的某个角色,不同的用户可以绑定相同的角色或不同的角色,而不同的角色有不同的权限。

★查询语句也就是select语句的表名之后加  with(nolock)  如: select id from dbo.usertable with(nolock)

临时表无法使用,需要注意。

指定允许脏读,内容很多,有时间探讨  https://www.cnblogs.com/kerrycode/p/3946268.html

★数据库配置大小写敏感等

★事务与锁  https://www.cnblogs.com/knowledgesea/p/3714417.html

mysql中注意事项:

暂未记录,只需注意 一些sql写法上与在 sqlserver中有区别,不注意会出错。

★muysql无 dbo 和 with(nolock)写法。

★时间函数:mysql是 now()    sqlserver是  getdate()

★数据库配置大小写敏感等

★判断为空函数,mysql是 ifnull(值,'')   sqlserver是  isnull(值,'')

★mysql中无if else语句控制流程,if else只能在存储过程中使用。可用case when替代,不过效果不一定好。

★查看mysql数据库关于表名称是否是大小写敏感的:

show VARIABLES like 'lower_case_table_names'

Unix下默认为0,也就是大小写敏感的;Windows下默认为1,不敏感;macOS默认为2,存储区分大小写,但是在查询时会转换为小写。

--show variables 是查看系统变量及其值

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

   4、变量名也是严格区分大小写的;

MySQL在Windows下都不区分大小写,不过可以设置字段属性BINARY,以区分查询时字段值区分大小写。

ALTER TABLE `tablename` MODIFY COLUMN `cloname` VARCHAR(45) BINARY;

1.常用

最常用的就是增删改查,有复杂的sql语句也是对应复杂的业务,但无非也是使用一些特殊的函数和语法及优化sql。

增:

sqlserver

--单条插入
insert into dbo.UserTable(UserId,TrueName) values(1,'test');
--批量插入
insert into dbo.UserTable(UserId,TrueName) values
(1,'test1'),
(2,'test2');
--判断是否存在,再插入。 也可以用 if not exists
declare @infor nvarchar(10), @newid bigint;
if exists(select userid from dbo.UserTable where UserId=1)
begin
    set @infor = '已存在';
    select @infor infor;
end
else
begin
 insert into dbo.UserTable(UserId,TrueName) values(1,'test');
 --插入语句执行后,得到相关的最新id ,有几种方法,如下
 set @newid = @@IDENTITY;
end

★插入语句同时返回最新Id几种写法:

--用output inserted(已插入临时表).主键id,可以返回新Id

--由于output inserted.id只能返回结果,不能由变量接收直接做其他sql语句的条件,所以一般不用

Insert into AAA(Name) output inserted.AId values('123')

--全局参数,连在插入语句下,可返回新插入的id

set @NewId = @@identity

--下面也可以得到插入后的Id

select @NewId = IDENT_CURRENT('AAA') 

Select @NewId = SCOPE_IDENTITY()

它们的区别

★-- ident_current('表名')   取表的最后编号,注意如果在高并发下,可能会取的不是预期的结果

★-- @@IDENTITY 和SCOPE_IDENTITY 返回在当前会话中的任何表内所生成的最后一个标识值。但是,SCOPE_IDENTITY 只返回插入到当前作用域中的值;@@IDENTITY 不受限于特定的作用域。

例如,有两个表 T1 和 T2,并且在 T1 上定义了 INSERT 触发器。当将某行插入 T1 时,触发器被激发,并在 T2 中插入一行。 该方案演示了两个作用域:在 T1 上的插入,以及在 T2 通过触发器的插入。

假设 T1 和 T2 都有标识列,@@IDENTITY 和 SCOPE_IDENTITY 将在 T1 上的 INSERT 语句的最后返回不同的值。@@IDENTITY 将返回在当前会话中的任何作用域内插入的最后一个标识列的值。这是在 T2 中插入的值。SCOPE_IDENTITY() 将返回在 T1 中插入的 IDENTITY 值。这是在同一个作用域内发生的最后的插入。如果在任何 INSERT 语句作用于作用域中的标识列之前调用 SCOPE_IDENTITY() 函数,则该函数将返回空值。

如果语句和事务失败,它们会更改表的当前标识,从而使标识列中的值出现不连贯现象。即使未提交试图向表中插入值的事务,也永远无法回滚标识值。例如,如果因 IGNORE_DUP_KEY 冲突而导致 INSERT 语句失败,表的当前标识值仍然会增加。

mysql

mysql中sql语句没有declare用法,只在事务中才有declare.不过mysql可以用set @变量名 定义用户变量。

--插入语句后,得到最新id mysql中无法用--注释 这里是为了说明
set @newid := @@identity;
select @newid;

--单条插入和批量插入与sqlserver一样

删:

sqlserver

delete from dbo.usertable where id =1;

update dbo.usertable set status=0 where id = 1;

mysql

--与sqlserver一样

改:

sqlserver

update dbo.usertable set name='newname', age=22, gender=0 where userid = 1;

mysql

--与sqlserver一样

查:

sqlserver

--分页查询:0 与 10 由开发时参数决定
select top(10) t.*
from( 

    --分页行号
    select ROW_NUMBER() over (order by ut.userid desc) rownum
            ,ut.UserId
            ,ut.TrueName
    from dbo.UserTable ut with(nolock)
) t 
where t.rownum > 0

--连表查询优化可放在from外面如下,有时也必要放在from里面
select top(10) t.* 
            ,(
            --for xml path 用法 多条记录返回一个值字段 如下 查用户的文章
                ISNULL( 
                        (
                            select et.Title+','
                            from EssayTable et with(nolock)
                            where et.UserId = ut.userid
                            for xml path('')
                        ) ,''
                )
            ) essays
from(
    select ROW_NUMBER() over (order by ut.userid desc) rownum
        ,ut.UserId
        --时间格式 也可不使用该函数
        ,CONVERT(VARCHAR(20),ut.EndTime,120) AS EndTime
    from dbo.UserTable ut with(nolock)
) t
where t.rownum > 0

--查询前50%的记录

select top 50percent * from dbo.usertable

mysql

mysql 无 for xml path写法,不过有分组写法可以达到相同功能。

mysql也无 row_number() 行号函数,不过有替代方案。

select @rowNo:=@rowNo + 1 as RowNum , t.* 
from (select @rowNo:=0) b
            , (
                    select  
                                     ar.id
                                    , ar.name

                                     --查找角色的所有权限信息 多条权限记录合并成一个值字段,以封号;隔开不同记录
                                    , ifnull(( select group_concat(ac.permissionsid,',',pms.name separator ':') 
                                                    from adminpermissionsclaims as ac
                                                    left join permissions as pms on pms.id=ac.permissionsid
                                                    where ac.roleid=ar.id group by ac.roleid

                                         ),'') as permissions
                    from adminrole as ar
            ) t 
limit 0,10;

--查询半小时以内的数据  minute可为hour

SELECT COUNT(0) FROM sms WHERE UserId=@UserId AND CreationTime >= DATE_ADD( now(), INTERVAL -30 MINUTE )

--case when 可替代if else 不过case when只能返回一个字段的值,当需要很多字段,效果不好

set @uplinecount := (
select count(0) from uplinearea where RelationId=1 and type=1);

select (
    case when @uplinecount<>0 then 
        (select GROUP_CONCAT(upa.PrvId,':',upa.PrvName,':',upa.CityId,':',upa.CityName SEPARATOR ',') from uplinearea as upa where RelationId=1 and type=1
        GROUP BY upa.RelationId)   --由于只能有一个字段的值,所以只好把多个字段合并
    else
        (select GROUP_CONCAT(offa.PrvId,':',offa.PrvName,':',offa.CityId,':',offa.CityName SEPARATOR ',') from offlinearea as offa where RelationId=1 and type=1
        GROUP BY offa.RelationId)
    end
) as areaname

--合并多个字段的函数  concat_ws('-',upa.prvname,upa.cityname)   (分隔符,字段1,字段2)

select  (
                                                    case when upa.prvId<=0&&upa.cityid<=0 then '全国'
                                                    when upa.prvid>0&&upa.cityid<=0 then (upa.prvname)
                                                    when upa.prvid>0&&upa.cityid>0 then concat_ws('-',upa.prvname,upa.cityname)
                                                    else '无'
                                                    end
                                                ) as areaname,
                                                upa.prvid,
                                                upa.cityid
                                        from uplinearea upa where relationid=@relationid and type=@type

2.sqlserver特殊语法及函数使用、存储过程

举得起放得下叫举重,举得起放不下叫负重。头要有勇气,抬头要有底气。学习要加,骄傲要减,机会要乘,懒惰要除。
人生三难题:思,相思,单相思。

if-else写法  print写法  try-catch写法  while写法:

if exists(select name from sys.sysdatabases where name = 'TaskTracker')
begin
    print '数据库存在'
end
else begin
    print '数据库不存在'
end

--try-catch写法

begin try
    --这里写sql语句
end try
begin catch
    --记录错误信息
    select ERROR_MESSAGE()
end catch

--while写法

declare @i int=0, @num int=10, @oldtime datetime=getdate();
while @i < @num
begin
    print @i;
    set @i +=1;
end

go命令的作用:

执行多条语句用封号;隔开就好了。如果只是执行一条语句,有没有GO都一样。如果多条语句之间用GO分隔开就不一样了,每个被GO分隔的语句都是一个单独的事务,一个语句执行失败不会影响其它语句执行。

查看sql语句的执行时间:

declare @d datetime;
set @d=getdate();

Select * FROM [dbo].[EmployeeTable]   --这里写sql语句

select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())

添加字段,修改字段类型,修改字段名称:

★--用户表增加 (添加时间 字段) 
Alter TABLE dbo.UserTable ADD AddTime DateTime NOT NULL DEFAULT(GETDATE());

★--用户表名称字段,修改类型
Alter TABLE dbo.UserTable Alter COLUMN NickName nvarchar(50)

★--修改字段名
-- EXEC sp_rename 'dbo.UserTable.[Gender]','NewGender','COLUMN' 

--移除字段
-- Alter Table dbo.UserTable drop Column Likes

--增加状态字段 Status(0删除 1正常)
Alter Table dbo.UserTable Add Status tinyint NOT NULL

--增加个人描述
ALTER TABLE dbo.UserTable Add Description nvarchar(100)

建表、建库语句:

--建库

USE master
GO
IF EXISTS(SELECT * FROM SYSDATABASES WHERE NAME='RealyUse')
    BEGIN
        SELECT '数据库已存在'
    END
ELSE
    BEGIN
        CREATE DATABASE RealyUse
        ON PRIMARY(
            name="RealyUse_data", --主数据文件名
            filename="G:\MyGit\RealuUseItNETCOREdbfile\RealyUse_data.mdf", --主数据库存储位置
            size=3mb, --主数据文件初始大小
            maxsize=1024mb, --主数据文件最大大小,不写就是无限制
            filegrowth=1mb --增量
        )
        LOG ON(
            name="RealyUse_log", --日志文件
            filename="G:\MyGit\RealuUseItNETCOREdbfile\RealyUse_log.ldf", --日志文件存储位置
            size=1mb, --日志文件初始大小
            filegrowth=10% --增长率10%
        )
        SELECT '数据库不存在,已新建'
    END

--建表

USE master
GO
IF EXISTS(SELECT * FROM sys.SYSDATABASES WHERE NAME='RealyUse')
    BEGIN
        USE RealyUse
        IF EXISTS(SELECT name FROM sys.sysobjects WHERE xtype='u' AND name='UserTable')
            BEGIN
                SELECT 'UserTable用户表已存在'
            END
        ELSE
            BEGIN
                CREATE TABLE [UserTable](
                    UserId bigint PRIMARY KEY NOT NULL IDENTITY(1,1) , --用户Id 主键
                    NickName nvarchar(20) NOT NULL , --昵称
                    TrueName nvarchar(20) NOT NULL , --真实姓名
                    Gender tinyint NOT NULL --性别 0未知 1男 2女
                )
                SELECT 'UserTable用户表不存在,已新建了'
            END
    END
ELSE
    BEGIN
        SELECT '数据库RealyUse不存在,无法创建UserTable用户表,请先创建数据库'
    END

关联查询:

https://www.cnblogs.com/rainman/archive/2013/04/27/3046124.html#m1

一些系统表的操作:

★--查看数据库所有字段类型
select * from systypes

★--查询数据库所有用户表的名字  s为系统表

select name from SYSOBJECTS WHERE xtype='u'

★--查询某张表的所有信息

select * from sysbojects where name ='表'

★--查询某张表的所有字段的名字

SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='表'

  字段的数据类型,把  COLUMN_NAME  改为 DATA_TYPE

  字段的数据长度范围限制,把  COLUMN_NAME  改为 CHARACTER_MAXIMUM_LENGTH

加密函数、用户自定义函数:

insert into testone(name) values(
  HASHBYTES('sha1','test')  --对test值加密再存入数据库
)

--查询name='test'的记录是否存在

select * from testone where name=HASHBYTES('sha1','test')

★sqlserver自定义函数, https://www.cnblogs.com/csdbfans/p/3514538.html

--创建自己的加密函数 dbo.MD5 名字自取

create function dbo.MD5(@src varchar(255)) returns varchar(255)
as begin
    declare @md5 varchar(34)
    set @md5 = sys.fn_VarBinToHexStr(hashbytes('md5',@src));
    --return substring(@md5 , 11 , 16) --16位
    return substring(@md5 , 3 , 32) --32位
end

--比较内置和自定义的区别

select dbo.MD5('123');
select HASHBYTES('md5','123');

根据name返回table(dbo.testone)的全部数据 自定义函数

CREATE FUNCTION selectAByName( @a varchar(36) ) RETURNS TABLE --返回数据是table
AS
RETURN(
    SELECT * FROM dbo.testone WHERE name = @a
)

--调用

不能直接使用如 selectAById('123')

而是 SELECT * FROM selectAById('123')

会发现上面的这个函数中只能传入字段值,表名是固定好的,不能以参数传入,想要表名也可以以参数传入,看下面的存储过程。

存储过程使用:

★存储过程优点:

1.存储过程加快系统运行速度,存储过程只在创建时编译,以后每次执行时不需要重新编译。
2.存储过程可以封装复杂的数据库操作,简化操作流程,例如对多个表的更新,删除等。
3.可实现模块化的程序设计,存储过程可以多次调用,提供统一的数据库访问接口,改进应用程序的可维护性。
4.存储过程可以增加代码的安全性,对于用户不能直接操作存储过程中引用的对象,SQL  Server可以设定用户对指定存储过程的执行权限。
5.存储过程可以降低网络流量,存储过程代码直接存储于数据库中,在客户端与服务器的通信过程中,不会产生大量的T_SQL代码流量

★存储过程缺点:
1.数据库移植不方便,存储过程依赖与数据库管理系统, SQL Server 存储过程中封装的操作代码不能直接移植到其他的数据库管理系统中。
2.不支持面向对象的设计,无法采用面向对象的方式将逻辑业务进行封装,甚至形成通用的可支持服务的业务逻辑框架.
3.代码可读性差,不易维护。不支持集群。

依赖数据库管理系统,移植性差等 我暂时只能了解这么深。

★申明一个查询的存储过程  感觉跟创建函数差不多

create proc searchName(@name varchar(36))
as
--此时表名还不能以参数传入
select * from dbo.testone where name = @name

--搞好后,执行

exec searchName '123'   此操作等价于 ==》 select * from dbo.testone where name = '123'

★申明一个插入的存储过程

create proc insertName(@name varchar(36))
as 
insert into dbo.testone(name) values(@name)

--搞好后,执行

exec insertName '567'  此操作等价插入操作

其他存储过程类似这种写法,如删除等。除了查询外,其他都是返回受影响的行数。

但到此还是会发现表名不能为参数 --比如下面这样不行

create proc deleteAByName(
    @tname char(20),
    @id varchar(36)
)
as
delete from @tname where Id = @id

★想要存储过程 表名也能为参数 设置,需类似下面这样这样,存储过程不针对哪一张表,不同的表也可以复用

create proc selectFromT(@tname char(20) , @name varchar(20))
as
    declare @sqlstr nvarchar(2000);
begin
    set @sqlstr = N'select * from '+@tname+' where name= '+@name;
    --动态执行sql  =>  Execute sp_executesql  sqlstring
    execute sp_executesql @sqlstr;
end

--搞好后,调用

exec selectFromT 'testone','567';   --可知运行成功了,可能存在数据类型的错误。单引号转义 两个单引号表示一个单引号

上面某一句其实应该为:(如果字段是int则不需要改)

set @sqlstr = N'select * from '+@tname+' where name='''+@name+'''';

函数和存储过程的区别:

存储过程可以没有返回值,也可以有多个返回值,适合做批量插入数据、批量更新等。

函数必须有返回值,而且只能有1个,适合做处理数据后返回1个结果

3.sqlserver中的一些字段类型区别

date 和 datetime字段类型的区别:

date类型以YYYY-MM-DD格式存储数据。它允许1000-01-01到9999-12-31之间的值。

datetime类型以YYYY-MM-DD HH:MM:SS格式存储数据。

getdate() 函数可以直接使用,不用 convert() 函数进行转化,因为 数据库会根据字段类型对 getDate()的结果进行裁剪。

char、varchar、nchar、nvarchar字段类型区别:

前面多了 'n' 的,表示存储的是Unicode数据类型的字符。

英文字符只需要一个字节存储就足够了,但汉字众多,需要两个字节存储,英文与汉字同时存在时容易造成混乱,Unicode字符集就是为了解决字符集这种不兼容的问题而产生的,它所有的字符都用两个字节表示,即英文字符也是用两个字节表示。

nchar、nvarchar的长度是在1到4000之间,和char、varchar比较起来,nchar、nvarchar则最多存储4000个字符,不论是英文还是汉字;而char、varchar最多能存储8000个英文,4000个汉字。

可以看出使用nchar、nvarchar数据类型时不用担心输入的字符是英文还是汉字,较为方便,但在存储英文时数量上有些损失。  
所以一般来说,如果含有中文字符,用nchar/nvarchar,如果纯英文和数字,用char/varchar。

4.数据库连接字符串,mysql和sqlserver都可用

--sqlserver

server=liuyan6678\sql2008;database=realyuse;user id=sa;password=123456;max pool size=250;min pool size=10;

server=liuyan6678\sql2008;database=realyuse;user id=sa;password=123456;

server=192.168.60.18,8001;database=realyuse;user id=sa;password=123456;max pool size=250;min pool size=10;

--mysql

server=192.168.50.182;database=familyplatdev;user id=familyplat;password=Familyplat#182;allowuservariables=true;

server=192.168.50.182;database=familyplatdev;user id=familyplat;password=Familyplat#182;

5.sqlserver数据库中常用字段类型与c#中类型对应

查询行号是 bigint ,  c#中可用 int64 或 long 接收。

查询记录数是 int ,   c#中可用 int 或 int32接收。

tinyint   c#可用 byte或int接收

bit         c#可用boolean接收

--其它自行搜索

猜你喜欢

转载自blog.csdn.net/qq_38261174/article/details/100098319