领导要求查询一下某个记录表中是否存在循环担保的问题,也就是如下的内容:
贷款人        担保人
  A                  B
  C                  D
  B                  C
  D                  F
  F                  E
  E                  A
B为A担保,C为B担保,D为C担保,F为D担保,E为F担保,A为F担保,这样就形成了一个循环,总记录大约有170多万行,想用SQL来作查询,但是不知道如何做才对,请高手能帮帮我,明天一早就要交给领导,在线等。

解决方案 »

  1.   

    参考一下
    --2.自定义函数--检测某个编码出发,是否被循环引用
    create function f_chkid(@id int)
    returns bit --循环,返回1,否则返回0
    as
    begin
     declare @re bit,@pid int
     
     set @re=0 --检测
     select @pid=pid from tb where id=@id
     while @@rowcount>0
     begin
      if @pid=@id
      begin
       set @re=1
       goto lbErr
      end
      select @pid=pid from tb where id=@pid
     endlbErr:
     return(@re)
    end
    go
      

  2.   

    看看这个就知道了
    http://blog.csdn.net/zjcxc/archive/2003/12/29/20073.aspx
      

  3.   


    --前提:表中要有标识列或者行号 如测试表
    use tempdb;
    go
    create table dbo.tb

      id int identity(1,1),
      dk varchar(2) not null,
      db varchar(2) not null
    )
    insert into dbo.tb values('A','B'),
     ('C','D'),
     ('B','C'),
     ('D','F'),
     ('F','E'),
     ('E','A');
    go
    alter function f_chkid(@dk varchar(1))
    returns bit --循环,返回1,否则返回0
    as
    begin
     declare @re bit,@db varchar(1),@dk1 varchar(1);  
     set @re=0;
     set @dk1=@dk;
     --检测
     select @db=db from dbo.tb where dk=@dk
     while @@rowcount>0
     begin
      if @db<>@dk 
         begin
            if (select max(id)from dbo.tb where dk=@dk1)=(select max(id)from dbo.tb)
    break;
    set @dk1=@db
    select @db=db from dbo.tb where dk=@dk1
     end
      else
     begin
    set @re=1
    goto lbErr
     end
     end
     lbErr:
        return(@re)
    end
    go
    select dk,db,
          (case dbo.f_chkid(dk)when 1 then 'yes' else 'no' end)as jg
    from dbo.tb
    /**
    dk   db   jg
    ---- ---- ----
    A    B    yes
    C    D    no
    B    C    no
    D    F    no
    F    E    no
    E    A    no(6 行受影响)
    **/
      

  4.   

    7楼高手,我没看明白最后的yes和no是什么意思,我最后要生成的表中要能看到从A到A的一个循环,中间是BCDEF,这样才能说明是一个循环担保。
    4楼的高手,我把你的例子运行了一遍了,最后纵向分级显示的时候,如果中国那个纵列里最后再有一个中国也就是:中国、江苏、苏州、中国这样子,就差不多达到我的目的了。但是如果只是如我问题中是两列的话,我也需要再加一个ID列吗?
      

  5.   

    用id是好习惯,是为了保证记录行唯一的标识,如果你用名字当然也可以,这个例子是用id做关联做个测试给你看看,如果你父关系一定要用名字也是可以的,不过从可扩展性上面来看差一点,比如万一改名字了会引起维护的麻烦create table tb(
    id int identity(1,1) not null constraint PK_tb primary key clustered,
    pid int,name varchar(20))
    insert tb  select 6,'中国'
    union all select 0,'美国'
    union all select 0,'加拿大'
    union all select 1,'北京'
    union all select 1,'上海'
    union all select 1,'江苏'
    union all select 6,'苏州'
    union all select 7,'常熟'
    union all select 6,'南京'
    union all select 6,'无锡'
    union all select 2,'纽约'
    union all select 2,'旧金山'GOcreate function f_chkid(@id int)
    returns bit --循环,返回1,否则返回0
    as
    begin
     declare @re bit,@pid int
     
     set @re=0 --检测
     select @pid=pid from tb where id=@id
     while @@rowcount>0
     begin
      if @pid=@id
      begin
       set @re=1
       goto lbErr
      end
      select @pid=pid from tb where id=@pid
     endlbErr:
     return(@re)
    end
    GOSELECT dbo.f_chkid(1)
    DROP TABLE tb
    DROP FUNCTION f_chkid注意id位1的那个中国的父级关系我设的是6
    查询结果位1也就是存在循环嵌套
    不知道你说的是这个意思吗 测试一下看看 呵呵
      

  6.   


    --是这结果吗?
    use tempdb;
    go
    create table dbo.tb

      id int identity(1,1),
      dk varchar(2) not null,
      db varchar(2) not null
    )
    insert into dbo.tb values('A','B'),
                             ('C','D'),
                             ('B','C'),
                             ('D','F'),
                             ('F','E'),
                             ('E','A');
    go
    create function f_chkid(@dk varchar(1))
     returns   varchar(1000)
    as
    begin
         declare @db varchar(1);
         declare @str varchar(1000),@dk1 varchar(1); 
         set @dk1=@dk;
         set @str=@dk1
         --检测
         select @db=db from dbo.tb where dk=@dk
         while @@rowcount>0
         begin
          if @db<>@dk 
             begin
                if (select max(id)from dbo.tb where dk=@dk1)=(select max(id)from dbo.tb)
                    break;
                set @dk1=@db
                set @str=@str+@dk1
                select @db=db from dbo.tb where dk=@dk1
             end
          else
                goto lbErr
         end
         lbErr:
            return(@str+@db)
    end
    go
    select dk,
           left(dbo.f_chkid(dk),len(dbo.f_chkid(dk))-1)as zj,
           RIGHT(dbo.f_chkid(dk),1)as dkend,
           (case when dk=RIGHT(dbo.f_chkid(dk),1)then 'yes' else 'no' end)as jg
    from dbo.tb
    /**
    dk   zj          dkend jg
    ---- ----------- ----- ----
    A    BCDFE       A     yes
    C    DFE         A     no
    B    CDFE        A     no
    D    FE          A     no
    F    E           A     no
    E    E           A     no(6 行受影响)**/
      

  7.   


    --这结果?
    /**
    dk   zj
    ---- ----------
    A    ABCDFEA
    C    CDFEA
    B    BCDFEA
    D    DFEA
    F    FEA
    E    EA(6 行受影响) /**
      

  8.   

    并没有游标呀,你说的是自定义函数吗?当然你也可以写proc,基本一样
      

  9.   

    我的意思就是能不能用最简单的SQL语句实现,因为我们单位有个自己的系统,只能用最简单的SQL语句。
      

  10.   

    你的意思是只用一句select?那个有难度 因为要嵌套调用,2005或许有办法,2000...
      

  11.   


    我家里和单位的SQL都是2005,但是单位自用的系统连creater都说是错误的语法,哭的心都有了
      

  12.   

    恩 csdn规定 只可给18楼的人分数,其他一律为0
    好吧 当我没说
    当然可以分着加的 呵呵
      

  13.   

    嘿嘿,贪心一点,如果有只用select查询的方法就更好了:)
      

  14.   


    看来单独的select语句是没戏了…………
      

  15.   

    哭了,单位该死的系统不让用函数,就连create都不让用啊
      

  16.   


    出现问题了,当我把字母换成中文之后,查到的dk和db那里,只有一个字母,而不是中文
      

  17.   

    你改把类型改成varchar(100)或者nvarchar
      

  18.   

    纯理论就复杂点,现实中就简单点
    就当是多层BOM,你查询,超过20层就当是循环喽
    **现实中会有这么复杂的担保么??
      

  19.   

    单位的系统别说cte了,连create都不让用
      

  20.   

    ....跑到这里来问了啊 LZ..
    没有cte 没有函数 很难做哦