• 分别使用函数及游标实现SQL多行转一列


    有时候在一些系统中我们需要用SQL语句将一对多关系表中的数据以每条记录一行的形式进行显示。本文分别采用函数及游标的方法来实现该功能。
    示例表描述如下
    一张用户表及文档表

    现在想实现如下功能,查询出每个用户及其对应的文档名称的综合,如下结果
    userID                            userName                               DocNames
    1                                    fengyan                            sql基础,asp.net入门
    2                                    eflylab                                     精品美食

    注意到最后一列是类似统计。这就决定不能使用left join做,那样1号用户会出现二行,不是期望的
    其实很多时间需求是需要我们使用SQL完成这样的功能,而不是放在程序里!如果做?
    这里可以写一个函数来完成该功能

    CREATE function f_getUserDocsByUserID(@userID int
    returns varchar(8000
    as 
    begin 
    declare @str varchar(8000
    set @str='' 
    select @str=@str+','+docName from Doc where UserID=@userID 
    if(len(@str)>1)
        
    set @str=right(@str,len(@str)-1
    return(@str
    则相应的查询语句为
    select u.*,study.dbo.f_getUserDocsByUserID(u.userID) as docs from [user] as u
    运行效果

    实现功能,这里仅以很简单的示例,演示了将多行转换成一列的需求,实际中针对docs的结果可能更复杂一些。
    需要相应的变通!

    第二种方式可以使用游标,这对于很多不理解和不会应用游标的朋友来说,可以学习一下!
    --定义结果集表变量
    DECLARE @t TABLE(userID varchar(10),userName varchar(100),DocNames varchar(8000))

    --定义游标并进行合并处理
    DECLARE MyCURSOR CURSOR  
    FOR
    SELECT u.*,d.docName FROM [user] u left join [Doc] d on u.userID=d.userID  order by u.userID

    DECLARE @userID_old int,@userID int,@userName varchar(50),@oldUserName varchar(50),@docName varchar(50),@s varchar(100)
    --打开游标

    OPEN MyCURSOR
    FETCH MyCURSOR INTO @userID,@userName,@docName
    SELECT @userID_old=@userID,@s='',@oldUserName=@userName
    WHILE @@FETCH_STATUS=0    --游标存在数据时循环
    BEGIN
        
    IF @userID=@userID_old    --如果当前记录和上一条用户ID相同,则更改变量@s的值
            SELECT @s=@s+','+@docName
        
    ELSE
        
    BEGIN    --否则 已经是下一位用户了,应该执行添加操作
            --UserID改变的时候添加操作
            INSERT @t VALUES(@userID_old,@oldUserName,STUFF(@s,1,1,''))
            
    --将新的文件名赋值给@s 并且更新@userID_old,@oldUserName
            SELECT @s=','+@docName,@userID_old=@userID,@oldUserName=@userName
        
    END
        
    FETCH MyCURSOR INTO @userID,@userName,@docName
    END
    INSERT @t VALUES(@userID_old,@oldUserName,STUFF(@s,1,1,''))
    CLOSE MyCURSOR
    DEALLOCATE MyCURSOR
    --显示结果
    SELECT * FROM @t

    运行结果如下:

    也达到预期,在这里使用了一条left join查询
    SELECT u.*,d.docName FROM [user] u left join [Doc] d on u.userID=d.userID  order by u.userID
    它的执行结果如下:

    在方法二中使用游标在这个结果表中循环。中间使用一个变量结果表@t将结果存入@t中,最后@t即为所需结果
  • 相关阅读:
    Azkaban的使用
    Azkaban安装
    Kafka 启动失败,报错Corrupt index found以及org.apache.kafka.common.protocol.types.SchemaException: Error reading field 'version': java.nio.BufferUnderflowException
    Kafka 消费者设置分区策略及原理
    Kafka利用Java API自定义生产者,消费者,拦截器,分区器等组件
    zookeeper群起总是有那么几个节点起不来的问题解决
    flume 启动agent报No appenders could be found for logger的解决
    Flume 的监控方式
    Flume 自定义 组件
    Source r1 has been removed due to an error during configuration java.lang.IllegalArgumentException: Required parameter bind must exist and may not be null & 端口无法连接
  • 原文地址:https://www.cnblogs.com/eflylab/p/1234781.html
Copyright © 2020-2023  润新知