• SQL 相关技术点收集贴


    摘要: 不定期、偶尔、添加更新 在网络上看到或者自己开发过程中碰到的 SQL 相关问题

    本文地址:http://www.cnblogs.com/vnii/archive/2012/04/13/2445526.html 

    1.利用EXEC和sp_executesql对传递参数的sql返回执行结果 

    View Code
    Declare @code varchar(20),@type varchar(50),@title varchar(200),@tableName varchar(200)
    Declare @flag int
    Declare @nSql nvarchar(4000)
    Set @flag=0
            
    --Select @flag=id From tableName Where code=@code and type=@type and title=@title
    Set @nSql=N'Select @flag=ID From '+@tableName+' Where Code='''+@code+''' and Type='''+@type+''' and Title='''+@title+''''
            
    --结果返回给@flag,如果存在返回的是第一条符号的ID,否则返回0
    EXEC sp_executesql @nSql,N'@flag int output',@flag output
    print @flag
    
    --------------------------------------------------------------
    
    
    如果有一个存储过程,需要返回结果,可如下
    DECLARE @M1 INT
    EXEC dbo.sp_myProcName ,@M1 OUTPUT
    Print @M1

    2.函数内不能执行SQL,即不能在函数内使用 EXEC 

    3.函数内不能使用newId()、rand()等函数

    4.一个字符串分割函数

    View Code
    -- =============================================
    -- Author:        忧郁的匹格 http://www.cnblogs.com/vnii
    -- Create date: 2012-4-23
    -- Description:    将字符串按照特定字符进行分割成table返回
    --                @content 需要被分割的字符串,@split分隔符,@allowEmpty 是否允许空字符串(1表示允许,其它数字表示排除空字符串)
    -- =============================================
    CREATE FUNCTION [dbo].[fun_splitToTable]
    (
    @content VARCHAR(8000),@split VARCHAR(10),@allowEmpty int=0
    )
    Returns @T TABLE(ID INT,VALUE VARCHAR(8000))
    AS
    BEGIN
        --序号
        DECLARE @ID INT
        SET @ID=1
        --切割的字符串
        DECLARE @VALUE VARCHAR(8000)
        SET @VALUE=''
        
        --第一个分隔符位置
        DECLARE @splitIndex INT
        set @splitIndex=1
        
        --分隔符长度,后续用于计算
        DECLARE @LEN_split INT
        Set @LEN_split=DATALENGTH(@split)
    
        --DECLARE @T TABLE(ID INT,VALUE VARCHAR(4000))
        
        --第一个分隔符的位置
        Set @splitIndex=CHARINDEX(@split,@content)
    
        --是否有分隔符
        WHILE @splitIndex>0
        Begin
        
            --切割的字符串
            SET @VALUE=SUBSTRING(@content,1,@splitIndex-1)
            
            --允许空字符串 或者 切割完成的字符串不为空
            IF @allowEmpty=1 or @VALUE<>''
            Begin
                --添加分割后的内容到表变量
                INSERT INTO @T VALUES(@ID, @VALUE)
                --序号+1
                Set @ID=@ID+1
            End
            
            --删除已经添加的数据,重新给被分割的字符串赋值
            Set @content=SUBSTRING(@content,@splitIndex+@LEN_split,DATALENGTH(@content)-@splitIndex-@LEN_split+1)
            --第一个分隔符的位置
            Set @splitIndex=CHARINDEX(@split,@content)
        End
    
        --切割的字符串
        SET @VALUE=SUBSTRING(@content,1,DATALENGTH(@content))
        
        --允许空字符串 或者 切割完成的字符串不为空
        IF @allowEmpty=1 or @VALUE<>''
        Begin
            --部分分割完成的字符串中没有分隔符时,添加剩余的所有字符串内容到表变量
            INSERT INTO @T VALUES(@ID, @VALUE)
        End
        
        RETURN
    END

    5.获取一个时间范围内的随机时间

    View Code
    -- ====返回规定天数内的一个随机时间=========================================
    -- Author:        忧郁的匹格 http://www.cnblogs.com/vnii
    -- Create date: 2012.4.23
    -- Description:    返回规定时间范围内的一个随机时间
    --                @startTime~@endTime:规定时间范围内
    --                @date 返回的结果随机时间
    -- =============================================
    CREATE PROC PROC_GetRandomTime(@startTime datetime,@endTime datetime,@date datetime output )
    AS
    Begin
        Declare @time datetime,@min int,@max int
        Set @time=getdate()
        Set @min=DATEDIFF(n,@time,@startTime)
        Set @max=DATEDIFF(n,@time,@endTime)
        
        Declare @tmp int
        IF @max<@min
        Begin
            Set @tmp=@max
            Set @max=@min
            Set @min=@tmp
        End
    
        set @date=dateadd(d,0,getdate())
        set @date=dateadd(n    ,Floor(@min+(@max-@min)*rand()),@date)
        set @date=dateadd(s    ,-Floor(60*rand()),@date)
        set @date=dateadd(ms,-Floor(1000*rand()),@date)
        --Select @date
    End
    Go
    
    --declare @result datetime
    --exec PROC_GetRandomTime '2012-4-24','2012-4-23',@result OUTPUT
    --print @result
    Go

    6.获取字符串长度的Len方法和DATALENGTH方法区别:Len计算字符数(对于字符串中尾字符的空格不计入长度内);DATALENGTH计算字符串含有的字节数(对于Varchar类型的字符串计算返回实际字符的字节总数-包括空格,一个汉字两个字节,Char为类型长度)  --另外DATALENGTH支持Text类型的数据,而Len不支持

    View Code
        Declare @v1 varchar(20),@v2 varchar(20),@v3 varchar(20),@v4 varchar(20),@v5 varchar(20),@v6 varchar(20)
        Declare @v7 char(20)
        SET @v1='abcdef好'    --一个汉字两个字节
        SET @v2='abcdef g'
        SET @v3='abcdefg '
        SET @v4='  '
        SET @v5='  abcde'  --开头两个个空格,结尾一个空格,LEN计算了开头的空格
        SET @v6='  abcde ' --开头两个个空格,结尾一个空格,LEN计算了开头的空格,但是结尾的空格排除了
        SET @v7='  abcde ' --@v7是char类型,Len和上面的规则相同,DATALENGTH返回的结果则为类型长度
        SELECT @v1 AS Value, LEN(@v1) AS [LEN], DATALENGTH(@v1) AS [DATALENGTH] --结果:7 7
            Union ALL
        SELECT @v2 AS Value, LEN(@v2) AS [LEN], DATALENGTH(@v2) AS [DATALENGTH] --结果:8 8
            Union ALL
        SELECT @v3 AS Value, LEN(@v3) AS [LEN], DATALENGTH(@v3) AS [DATALENGTH] --结果:7 8
            Union ALL
        SELECT @v4 AS Value, LEN(@v4) AS [LEN], DATALENGTH(@v4) AS [DATALENGTH] --结果:0 2
            Union ALL
        SELECT @v5 AS Value, LEN(@v5) AS [LEN], DATALENGTH(@v5) AS [DATALENGTH] --结果:7 7
            Union ALL
        SELECT @v6 AS Value, LEN(@v6) AS [LEN], DATALENGTH(@v6) AS [DATALENGTH] --结果:7 8
            Union ALL
        SELECT @v7 AS Value, LEN(@v7) AS [LEN], DATALENGTH(@v7) AS [DATALENGTH] --结果:7 20

    7.利用SQL 中的CTE 进行 递归获取数据

    View Code
    --创建测试表
    Create Table tbCTE
    (
        Id int identity(1,1) not null,
        Name varchar(50) null,
        Pid int not null
    )
    Go
    
    --填充数据
    insert into tbCTE(name,pid)
    Select 'top name',0 union all Select 'top name',0
    union all 
    Select 'name1',1 union all Select 'name2',1 union all Select 'name3',1 
    union all 
    Select 'name4',2 union all Select 'name5',2 union all Select 'name6',3 
    union all 
    Select 'name7',6 union all Select 'name8',2 union all Select 'name9',2 
    union all 
    Select 'name10',8 union all Select 'name11',8 union all Select 'name12',12
    Go
    ;
    
    --利用CTE 进行递归
    With tbCTE_Tmp (ID,NAMD,PID,DEEP)
    AS
    (
        --递归出 符合当前本句条件 下的所有类型,Deep 表示深度
        Select Id,Name,Pid,1 AS Deep From tbCTE Where ID=1
        
        Union ALL
        
        --内联tbCTE_Tmp,不能使用外联,Deep+1 表示深度
        Select T1.Id,T1.Name,T1.Pid,T2.Deep+1 AS Deep 
        From tbCTE T1 Inner Join tbCTE_Tmp T2 ON t1.Pid=T2.Id
    )
    Select * From tbCTE_Tmp
    Order By PID
    ;

    结果为:

    8.一句SQL“取得各个部门下排名前三位的销售量”的两种写法比较(当然也可以用循环。。。)

    View Code
    --测试表
    Declare @TempTable Table
    (
        RowId int Identity,--序列 *忧郁的匹格 http://www.cnblogs.com/vnii *
        DepartId int,--部门id
        SealNum int, --销售量
        CreateTime Datetime default getdate() --时间
    )
    
    --测试数据
    Declare @i int
    Set @i=1
    while @i<200
    Begin
        insert into @TempTable(DepartId,SealNum)
        Select 1+RAND()*10,1+RAND()*100
        Set @i=@i+1
    End
    
    --查询方法 1 : 效率好,但是当本例中 同一类型下出现相同的销售量数据SealNum时候,该类型的数据量会多于指定量
    --            (比如,类型为1销售量为98的数据有两条时,类型1就会返回4条数据)
    Select * From @TempTable T
    Where 
    (
        Select COUNT(1) From @TempTable 
        Where DepartId=T.DepartId And SealNum>T.SealNum
        --每条数据对应类型在中相对于同类型的数据,>本数据销售量的记录数 少于3条
    )<3
    Order By DepartId,SealNum Desc
    
    
    
    --查询方法 2 : 相对于方法1,效率低,但是不会出现方法一种多于指定量的情况,反过来就会出现相同销售量的数据"丢失"
    Select * From @TempTable T
    Where RowId in
    (
        Select Top 3 RowId From @TempTable 
        Where DepartId=T.DepartId
        Order By SealNum DESC,RowId DESC
    )
    Order By DepartId,SealNum Desc

    9.查看数据库相关文件

    sp_helpdb 数据库名

    结果为:

    10.数据库还原;参见: http://www.yesky.com/imagesnew/software/tsql/ts_ra-rz_25rm.htm

    View Code
    语法:
    RESTORE DATABASE { database_name | @database_name_var } 
    [ FROM < backup_device > [ ,...n ] ] 
    [ WITH
        [ RESTRICTED_USER ]
        [ [ , ] FILE = { file_number | @file_number } ]
        [ [ , ] PASSWORD = { password | @password_variable } ]
        [ [ , ] MEDIANAME = { media_name | @media_name_variable } ]
        [ [ , ] MEDIAPASSWORD = { mediapassword | @mediapassword_variable } ]
        [ [ , ] MOVE 'logical_file_name' TO 'operating_system_file_name' ]
                [ ,...n ]
        [ [ , ] KEEP_REPLICATION ]
        [ [ , ] { NORECOVERY | RECOVERY | STANDBY = undo_file_name } ]
        [ [ , ] { NOREWIND | REWIND } ]
        [ [ , ] { NOUNLOAD | UNLOAD } ]
        [ [ , ] REPLACE ]
        [ [ , ] RESTART ]
        [ [ , ] STATS [ = percentage ] ] 
    ]
    
    例:
    RESTORE DATABASE Test_BDT FROM DISK = N'D:\abc.bak' WITH  FILE = 1,  NORECOVERY,  NOUNLOAD,  MOVE N'MyDbLogicalName' TO N'F:\sqldata\Test_BDT.mdf',  MOVE N'Test_BDT_log' TO N'F:\Test_BDT_0.ldf',  REPLACE,  STATS = 10

    11.获取数据库备份文件的备份信息;参见:http://www.yesky.com/imagesnew/software/tsql/ts_ra-rz_2i9l.htm

    View Code
    语法:
    RESTORE FILELISTONLY 
    FROM < backup_device > 
    [ WITH
        [ FILE = file_number ]
        [ [ , ] PASSWORD = { password | @password_variable } ]
        [ [ , ] MEDIAPASSWORD = { mediapassword | @mediapassword_variable } ]
        [ [ , ] { NOUNLOAD | UNLOAD } ] 
    ]
    
    < backup_device > ::=
        { 
            { 'logical_backup_device_name' | @logical_backup_device_name_var }
            | { DISK | TAPE } =
                { 'physical_backup_device_name' | @physical_backup_device_name_var } 
        }
    
    例:
    RESTORE FileListOnly 
    FROM disk='e:\Test_BDT.bak' 

    结果为:

     

    12.获取数据库备份文件的首部信息;参见:http://www.yesky.com/imagesnew/software/tsql/ts_ra-rz_5urd.htm

    View Code
    语法:
    RESTORE HEADERONLY 
    FROM < backup_device > 
    [ WITH { NOUNLOAD | UNLOAD }
        [ [ , ] FILE = file_number ]
        [ [ , ] PASSWORD = { password | @password_variable } ]
        [ [ , ] MEDIAPASSWORD = { mediapassword | @mediapassword_variable } ] 
    ]
    
    < backup_device > ::=
        { 
            { 'logical_backup_device_name' | @logical_backup_device_name_var }
            | { DISK | TAPE } =
                { 'physical_backup_device_name' | @physical_backup_device_name_var } 
        }
    
    例:
    RESTORE HEADERONLY 
    FROM disk='e:\Test_BDT.bak' 

    13.获取数据库备份文件的信息组成的结果集 ;参见:http://www.yesky.com/imagesnew/software/tsql/ts_ra-rz_6hkp.htm

    View Code
    语法:
    RESTORE LABELONLY 
    FROM < backup_device > 
    [ WITH { NOUNLOAD | UNLOAD } ]
        [ [ , ] MEDIAPASSWORD = { mediapassword | @mediapassword_variable } ]
    
    < backup_device > ::=
        { 
            { 'logical_backup_device_name' | @logical_backup_device_name_var }
            | { DISK | TAPE } =
                { 'physical_backup_device_name' | @physical_backup_device_name_var } 
        }
    
    例:
    RESTORE LABELONLY
    FROM disk='e:\Test_BDT.bak' 

    14.验证数据库备份文件;参见: http://www.yesky.com/imagesnew/software/tsql/ts_ra-rz_2i9l.htm 

    View Code
    语法:
    RESTORE VERIFYONLY 
    FROM < backup_device > [ ,...n ] 
    [ WITH
        [ FILE = file_number ]
        [ [ , ] { NOUNLOAD | UNLOAD } ]
        [ [ , ] LOADHISTORY ]
        [ [ , ] PASSWORD = { password | @password_variable } ]
        [ [ , ] MEDIAPASSWORD = { mediapassword | @mediapassword_variable } ]
        [ [ , ] { NOREWIND | REWIND } ]
    ]
    
    < backup_device > ::=
        { 
            { 'logical_backup_device_name' | @logical_backup_device_name_var }
            | { DISK | TAPE } =
                { 'physical_backup_device_name' | @physical_backup_device_name_var } 
        }
    
    
    例:
    RESTORE VERIFYONLY
    FROM disk='e:\Test_BDT.bak' 

    15.数据M分配成为N份,且每一份数据都是大小随机

    View Code
        Declare @MaxNum int =500 --需要分配的数据数
        Declare @times int =10 --分配的份数
    
        Declare @randNumTable Table
        (
            Id int identity,
            rate float default(0),
            Num int default(0)
        )
        Declare @i int=0
        While @i<@times
        Begin
            Insert into @randNumTable(rate) Select RAND()
            Set @i=@i+1
        End
        Declare @rateTotal float=1
        Select @rateTotal=SUM(rate) from @randNumTable
        Update @randNumTable Set Num=@MaxNum*Rate/@rateTotal
        Declare @D_value int=0
        Select @D_value=@MaxNum-SUM(num) From @randNumTable
        Select @D_value
        Update @randNumTable Set Num=Num+@D_value Where Id in(Select top 1 Id From @randNumTable order by Num)
        
        Select * From @randNumTable

    16.全角、半角 转换

    View Code
    Create  FUNCTION   [dbo].[fun_ConvertFullHalfWidth]
    ( 
        @str   NVARCHAR(4000),   --要转换的字符串 
        @flag   bit              --转换标志,0转换成半角,1转换成全角 
    )
    RETURNS   nvarchar(4000) 
    AS 
    BEGIN 
        DECLARE   @pat   nvarchar(8),@step   int,@i   int,@spc   int 
        IF   @flag=0 
            SELECT   @pat=N'%[!-~]%',@step=-65248, 
            @str=REPLACE(@str,N'  ',N'   ') 
        ELSE 
            SELECT   @pat=N'%[!-~]%',@step=65248, 
            @str=REPLACE(@str,N'   ',N'  ') 
            SET   @i=PATINDEX(@pat   COLLATE   LATIN1_GENERAL_BIN,@str) 
            WHILE   @i> 0 
                SELECT   @str=REPLACE(@str, 
                SUBSTRING(@str,@i,1), 
                NCHAR(UNICODE(SUBSTRING(@str,@i,1))+@step)) 
                ,@i=PATINDEX(@pat   COLLATE   LATIN1_GENERAL_BIN,@str) 
            RETURN(@str) 
    END 

    17.SQL 控制字符列表对应值

    View Code
    --Tab        char(9)
    --换行        char(10)
    --回车        char(13)
    --双引号    char(34)
    --单引号    char(39)
    
    Select Replace('abc def',' ',CHAR(39))

    18.一些特殊文字的过滤---Private Use Area:E000-F8FF 点此查看

     

     

     

      

     

     

  • 相关阅读:
    我孤独吗?我软弱吗?
    DataGrid 中的 HyperLinkColumn 如何传递多个参数?(未整理)
    C# 获取 MAC地址!
    (文本)文件操作
    ioninfinitescroll实现上拉分页加载更多
    前端面试题:防抖的实现
    vue 传送门功能,实现模态窗口
    前端面试题:节流的实现( 减少一段时间的触发频率)
    vue中的render函数
    ionic5实现tab栏切换效果
  • 原文地址:https://www.cnblogs.com/vnii/p/2445526.html
Copyright © 2020-2023  润新知