SQL basic

更新 : 2019-06-01

modify json 

refer : 

https://docs.microsoft.com/en-us/sql/relational-databases/json/json-data-sql-server?view=sql-server-2017

https://docs.microsoft.com/en-us/sql/t-sql/functions/json-modify-transact-sql?view=sql-server-2017

update klc2.dbo.Questions set audio = JSON_MODIFY(audio, '$.type', 'Audio');

mutiple JSON_MODIFY(JSON_MODIFY() ...) 做法是嵌套...

 

读取 array 

 declare @json nvarchar(max) =   
  N'{"monday":[],"tuesday":[14,15,16,17,18,19,20,21],"wednesday":[12,13,14,15,16,17,18,19,20,21],"thursday":[14,15,16,17,18,19,20,21],"friday":[10,11,12,13,14,15,16,17,18,19,20,21],"saturday":[9,10,11,12,13,14,15,16,17,18,19,20],"sunday":[]}';

  select * into #dailyHour from openjson(@json);
  while (select count(*) from #dailyHour) > 0
  begin
    declare @dayOfWeek nvarchar(max);
    declare @hours nvarchar(max);
    declare @startHour int;
    declare @endHour int;
    select top 1 @dayOfWeek = [key], @hours = value from #dailyHour;
    
    select top 1 @startHour = value from openjson(@hours) order by [key];
    select top 1 @endHour = value from openjson(@hours) order by cast([key] as int) desc; -- 要 cast 哦
    if(@hours != '[]') 
    begin
        print(@dayOfWeek);
        print(@startHour);
        print(@endHour);
    end 
    delete from #dailyHour where [key] = @dayOfWeek;
  end
  drop table #dailyHour;

 

 

 

 

 

 

orderby date nulls first 

sql  server 不支持 null first or last 的 语法, 需要用 case 来完成 

entity 的写法是 

orderby(n => n.time == null) 

生成出来的语句大概是  CASE WHEN ([Extent1].[time] IS NULL) THEN cast(1 as bit) ELSE cast(0 as bit) END AS [C1], 

原理就是在 order by 的时候动态创建一个 boolean column 先 orderby 它. 

可惜 odata 并不支持这个方法, 可以用 compute column 来解决. 

ALTER TABLE [dbo].[CalendarEvents] ADD haveTime AS CASE WHEN (time IS NULL) THEN cast(0 as bit) ELSE cast(1 as bit) END PERSISTED;

调用是 $orderby : "date, haveTime desc, time" 

 

 

nvarchar(MAX) vs ntext 

不要用 ntext 了, nvarchar(N) N 必须小于 4000, 如果 charater 有可能大于 4000 就放 MAX 

max 的话 sql 会用类似 text 的方式去处理的. 

 

index 需要 column 小于 900 bytes, nvachar 就是 450 字就 max 了. vachar 就 900咯.

 

 

Compute column 

不能子表哦 

PERSISTED 的话会在 insert, update 时同步 属于 reccalc on change 模式 

没有PERSISTED  则属于 getter 模式

ALTER TABLE [dbo].[Exams] ADD mark AS (CAST(totalCorrectAnswer AS FLOAT) / totalQuestion * 100) PERSISTED;

 

 

sql transaction isolation level

脏读,重复读,幻读

default is read commited, 防止脏读, 意思是 transaction update row 时, 这个 row 是不允许读的,transaction 写时会锁 

通常做 update,post,delete 时如果依赖其它数据, 我们就会选择使用更高级别的 Repeatable read 

意思是我重复读一条依赖的数据, 它在 transaction 的过程中永远是同一个值, transaction 读时会锁.

不过呢 Repeatable read 只是锁 row, 如果你依赖 row count 那么可能你需要锁更大的范围, 那么就是 Serializable 了 

锁越大就越容易出现死锁,读的效率也慢, 所以小心使用. 

2019-06-18 补上细节

set transaction isolation level repeatable read;
set transaction isolation level serializable;
begin transaction tran1

select * from test where name = '55';

commit

什么时候应该使用 repeat 或 serial 呢

就是当我们依赖一些数据作为验证的时候,比如你从数据库拿一个值来判断用户是否可以 insert 资料, 结果就在你检查的瞬间

数据被修改了,这就会导致你的判断错误,除了判断还有可能我们依赖数据来做计算,这样就可能会算错了. 

所以这时候就可以使用 repeat read 这样就可以确保我们在执行完事情的时候,当下是正确的计算。

需要注意的是 repeat read 只是锁了一行. 没有人可以对那个 row 进行更新,但是这不代表你的数据不会被影响. 

比如 

select name from table where name = 'abc';

这是返回了 3 个数据. 你使用这 3 个数据做东西. 

没有人可以修改这 3 个数据... 但是呢, 你的 where 却不安全. 

如果其他人 insert ... (name) values ('abc') .. 你的算法又错了. 

或者 update set name = 'abc' where id ... 

所以如果你的 where 是 unique 的话就没事儿, 如果不是的话就要小心了

这时候要安全的话就要使用 serial 

它可以阻止 insert 和 update ..

serial 要小心的用, where 的 column 最好是放上 index

比如 

select name from table where name = 'abc'; 

拿到一行, id = 1, name = abc 

如果 name 不是 index 的话, 那么整个表就锁掉了

update table set age = 11 where Id = 5  

这句完全没有影响到你的 update 也无法 run .. 

所以要加上 index 给 name 

那么 sql 会变聪明, 上面那个 update 是可以运行的. 估计是通过 index 来判断.

死锁是这样发生的 

a 锁表 table1

b 锁表 table1

a update 表 table1, 被 b 锁了, 等待

b update 表 table1 , 也被 a 锁了, 等待...

这样就锁死了 .

一旦死算, 第一个 update 的人赢.. 后面的就 error,这样就解锁了. sql 发现死锁是蛮快的. 

 

总结就是 : 

如果依赖数据来做计算, 验证等,那么就需要锁. 

如果 where 的条件是 unique 比如 where id =.. where email =... 

那么用 repeat read 就很安全了

如果不是..unique 那么尽量加上 index 在 where 的 column 让 sql 聪明一点. 

 

 

check trans open 

SELECT * FROM sys.sysprocesses WHERE open_tran = 1

unique with filter null 

CREATE UNIQUE NONCLUSTERED INDEX[UNIQUE_Characters_Teacher_contactEmail] ON[dbo].[Characters]([Teacher_contactEmail] ASC) WHERE([Teacher_contactEmail] IS NOT NULL);

foreign relation cascade delete or set null

ALTER TABLE [dbo].[ExamDatas] DROP CONSTRAINT [FK_dbo.ExamDatas_dbo.Questions_questionId];

ALTER TABLE [dbo].[ExamDatas]  WITH CHECK ADD  CONSTRAINT [FK_dbo.ExamDatas_dbo.Questions_questionId] FOREIGN KEY([questionId]) REFERENCES [dbo].[Questions] ([Id]) ON DELETE SET NULL;
-- ON DELETE CASCADE;

 

 

 

 

 

check connection 

exec sp_who
exec sp_who2

Or

SELECT 
    DB_NAME(dbid) as DBName, COUNT(dbid) as NumberOfConnections, loginame as LoginName FROM sys.sysprocesses WHERE dbid > 0 GROUP BY dbid, loginame ;

 

 

reset auto increment 

DBCC checkident ('Employees') //check current
DBCC checkident ('Employees', reseed, 0); //reset to 0 , next is 1

 

Function 

从例子学习

drop function dbo.getWorkingDateCount;  --getWorkingDateCount = functionName

CREATE FUNCTION [dbo].[getWorkingDateCount] 
(    
  --这3个是parameter, 名字和类型
  @fromDate  date,  
  @toDate date,
  @publicHolidayStrList nvarchar(500)   
)
RETURNS int  --表明返回类型
AS 
BEGIN
    DECLARE @count INT = 0; --DECLARE 就是var
    WHILE @fromDate <= @toDate --while 就是for loop
    BEGIN
        DECLARE @ipos INT = 0;
        DECLARE @dateName nvarchar(50);
         --赋值一定要写set在前面,
         --CHARINDEX 是 indexOf
         --CONVERT 是 datetime to string , 126 是一个sql对日期格式的代号 refer : https://msdn.microsoft.com/en-us/library/ms187928.aspx
        SET @ipos = CHARINDEX(CONVERT(VARCHAR(10),@fromDate,126), @publicHolidayStrList);
        --DATENAME weekday 返回星期几
        SET @dateName = DATENAME(weekday, @fromDate);
        IF @ipos = 0 and @dateName != 'Saturday' and @dateName !='Sunday'
        BEGIN
            SET @count = @count + 1;
        END    
        SET @fromDate = DATEADD(day,1,@fromDate) --DATEADD = datetime.addDays()
    END;
    RETURN @count; 
END

select dbo.getWorkingDateCount('2015-11-01','2015-11-30','2015-11-07,2015-11-13') as 'date'; 

上面是一个调用来获取工作天数的函数

 

update 和 insert 顾虑并发

insert into DemoProducts (code) 
select top 1 'mk100' from DemoColors 
where DemoColors.ID = 5 and DemoColors.rowVersion = 'xxfx01tAA';

UPDATE p SET p.code = 'mk200' FROM DemoProducts p,DemoColors c WHERE p.ID = 5 and c.ID = 5 and c.rowVersion = '';

 

insert 之后拿 ID 

INSERT [dbo].[DemoProducts]([code])
select 'x' from DemoColors
SELECT [ID]
FROM [dbo].[DemoProducts]
WHERE @@ROWCOUNT > 0 AND [ID] = scope_identity()

用 output 会更好,不止insert,update,delete也通用哦

INSERT DemoProducts (code) 
OUTPUT inserted.code as ttc,inserted.ID 
select 'newCode' from DemoProducts;

refer: https://msdn.microsoft.com/en-us/library/ms177564.aspx

 

Transaction 逻辑

当一个transaction开始后,如果有修改sql, 那么被修改的那一行row会被锁上,其它请求 get,set 涉及到那一行row都会阻塞,直到 tran 结束.

 

查看 database 目前有的 trigger, function, stored procedure 等

SELECT     
    DB_NAME() AS DataBaseName,                  
    dbo.SysObjects.Name AS TriggerName,
    dbo.sysComments.Text AS SqlContent
FROM 
    dbo.SysObjects INNER JOIN 
        dbo.sysComments ON 
        dbo.SysObjects.ID = dbo.sysComments.ID;

 

 

 

 

转载于:https://www.cnblogs.com/keatkeat/p/4963194.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值