前几天提问解答了自定义函数中不能使用临时表的问题(已加分结贴):
http://topic.csdn.net/u/20080416/15/1ce087cd-a02f-40ac-a863-f5fe2bb11e9c.html?272833094
可是在函数调用时有出现了问题,发现该函数不能以子查询出现在查询中:
函数调用
select min(DB) from dbo.Getdb('0200-35259250 ','3230-00601010  ')
结果
5100
函数作为子查询调用
select (select min(DB) from Getdb(A.MD001,A.MD003))
from BOMMD A where MD003='3230-00601010  ' and MD001='1300-00601105       '
结果
Msg 170, Level 15, State 1, Line 1
第 1 行: '.' 附近有语法错误。请高手解答,谢谢.

解决方案 »

  1.   


    /*
    标题:分解字符串并查询相关数据
    作者:爱新觉罗.毓华 
    时间:2008-03-18
    地点:广东深圳
    说明:通过使用函数等方法分解字符串查询相关数据。问题:通过分解一个带某种符号分隔的字符串在数据库中查找相关数据。
    例如 @str = '1,2,3',查询下表得到记录1,4,5,6
    ID TypeID
    1  1,2,3,4,5,6,7,8,9,10,11,12
    2  2,3 
    3  3,7,8,9 
    4  2,6 
    5  4,5
    6  6,7 
    */
    -----------------------------
    create table tb (ID int , TypeID varchar(30)) 
    insert into tb values(1 , '1,2,3,4,5,6,7,8,9,10,11,12') 
    insert into tb values(2 , '2,3') 
    insert into tb values(3 , '3,7,8,9') 
    insert into tb values(4 , '2,6') 
    insert into tb values(5 , '4,5')
    insert into tb values(6 , '6,7')
    go
    -----------------------------
    --如果仅仅是一个,如@str = '1'.
    declare @str as varchar(30)
    set @str = '1'
    select * from tb where charindex(',' + @str + ',' , ',' + TypeID + ',') > 0
    select * from tb where ',' + TypeID + ',' like '%,' + @str + ',%'
    /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    (所影响的行数为 1 行)
    */-----------------------------
    --如果包含两个,如@str = '1,2'.
    declare @str as varchar(30)
    set @str = '1,2'
    select * from tb where charindex(',' + left(@str , charindex(',' , @str) - 1) + ',' , ',' + typeid + ',') > 0 or 
      charindex(',' + substring(@str , charindex(',' , @str) + 1 , len(@str)) + ',' , ',' + typeid + ',') > 0
    select * from tb where ',' + typeid + ',' like '%,' + left(@str , charindex(',' , @str) - 1) + ',%' or 
      ',' + typeid + ',' like '%,' + substring(@str , charindex(',' , @str) + 1 , len(@str)) + ',%'
    /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    2           2,3
    4           2,6
    (所影响的行数为 3 行)
    */-------------------------------------------
    --如果包含三个或四个,用PARSENAME函数来处理.
    declare @str as varchar(30)
    set @str = '1,2,3,4'
    select * from tb where 
      charindex(',' + parsename(replace(@str , ',' , '.') , 4) + ',' , ',' + typeid + ',') > 0 or
      charindex(',' + parsename(replace(@str , ',' , '.') , 3) + ',' , ',' + typeid + ',') > 0 or
      charindex(',' + parsename(replace(@str , ',' , '.') , 2) + ',' , ',' + typeid + ',') > 0 or
      charindex(',' + parsename(replace(@str , ',' , '.') , 1) + ',' , ',' + typeid + ',') > 0 
    select * from tb where 
      ',' + typeid + ',' like '%,' + parsename(replace(@str , ',' , '.') , 4) + ',%' or
      ',' + typeid + ',' like '%,' + parsename(replace(@str , ',' , '.') , 3) + ',%' or
      ',' + typeid + ',' like '%,' + parsename(replace(@str , ',' , '.') , 2) + ',%' or
      ',' + typeid + ',' like '%,' + parsename(replace(@str , ',' , '.') , 1) + ',%'
    /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    2           2,3
    3           3,7,8,9
    4           2,6
    5           4,5
    (所影响的行数为 5 行)
    */---------------------------------------
    --如果超过四个,则只能使用函数或动态SQL来分解并查询数据。
    /*
    名称:fn_split函数.
    功能:实现字符串分隔功能的函数
    */
    create function dbo.fn_split(@inputstr varchar(8000), @seprator varchar(10))
    returns @temp table (a varchar(200))
    as 
    begin
      declare @i int
      set @inputstr = rtrim(ltrim(@inputstr))
      set @i = charindex(@seprator , @inputstr)
      while @i >= 1
      begin
        insert @temp values(left(@inputstr , @i - 1))
        set @inputstr = substring(@inputstr , @i + 1 , len(@inputstr) - @i)
        set @i = charindex(@seprator , @inputstr)
      end
      if @inputstr <> '\'
      insert @temp values(@inputstr)
      return 
    end
    go--调用
    declare @str as varchar(30)
    set @str = '1,2,3,4,5'select distinct m.* from tb m,
    (select * from dbo.fn_split(@str,',')) n
    where charindex(',' + n.a + ',' , ',' + m.typeid + ',') > 0drop table tb
    drop function dbo.fn_split /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    2           2,3
    3           3,7,8,9
    4           2,6
    5           4,5
    (所影响的行数为 5 行)
    */------------------------------------------
    --使用动态SQL的语句。
    declare @str varchar(200)
    declare @sql as varchar(1000)
    set @str = '1,2,3,4,5'
    set @sql = 'select ''' + replace(@str , ',' , ''' as id union all select ''')
    set @sql = @sql + ''''
    set @sql = 'select distinct a.* from tb a , (' + @sql + ') b where charindex(' + ''','' + b.id + ' + ''',''' + ' , ' + ''','' + a.typeid + ' + ''',''' + ') > 0 '
    exec (@sql)
    /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    2           2,3
    3           3,7,8,9
    4           2,6
    5           4,5
    (所影响的行数为 5 行)
    */看后半部分的:--调用
    declare @str as varchar(30)
    set @str = '1,2,3,4,5'select distinct m.* from tb m,
    (select * from dbo.fn_split(@str,',')) n
    where charindex(',' + n.a + ',' , ',' + m.typeid + ',') > 0
      

  2.   

    自定义Getdb是依据传入的参数最顶层主件品号和元件品号获取该元件品号当前层主件品号的工单单别
    比如:
    C001->B001.....->A001 
    函数得到B001的工单单别为5100
      

  3.   


    --少了个对象的所有者dbo
    select (select min(DB) from dbo.Getdb(A.MD001,A.MD003)) 
    from BOMMD A where MD003='3230-00601010' and MD001='1300-00601105'     
      

  4.   

    函数意思不说,大家看看这几个查询
    1.函数单独调用
    select min(DB) from dbo.Getdb('1300-00601105       ','3230-00601010  ')
    结果:
    5100
    2.所使用的查询
    select MD001,MD003
    from BOMMD where MD001='1300-00601105       ' and MD003='3230-00601010  ' 
    结果
    MD001      MD003
    1300-00601105        3230-00601010       
    3.函数作为上面查询的子查询
    select A.*,(select min(DB) from dbo.Getdb(A.MD001,A.MD003)) AS t
    from BOMMD A where MD001='1300-00601105       ' and MD003='3230-00601010  ' 
    结果
    Msg 170, Level 15, State 1, Line 1
    第 1 行: '.' 附近有语法错误。这不是很奇怪吗?
      

  5.   

    ALTER FUNCTION [dbo].[Getdb](@part1 varchar(20),@part2 varchar(20))
    RETURNS @t table(reno int,P1 CHAR(20),P2 CHAR(20),DB CHAR(4))
    AS
    BEGIN
    declare @i int
    set @i=1
    insert into @t
    select @i as reno,@part1 as P1,MD003 as P2,MC005 as DB
    from BOMMD A
    left join BOMMC B on A.MD001=B.MC001
    where MD001=@part1while @@ROWCOUNT>0 
    begin
        set @i=@i+1
        insert into @t
        select @i,@part1,MD003,MC005
        from @t A
        left join BOMMD B on A.P2=B.MD001
        left join BOMMC C on B.MD001=C.MC001
        where A.reno=@i-1 and not(B.MD001 is null)
    end
    delete @t where P2<>@part2
    RETURN 
    end
      

  6.   

    select min(DB) from dbo.Getdb(A.MD001,A.MD003)没看到你的getdb是什么函数 ,与临时表有什么 关系
    我想: 你要的是min(db),
    为什么 不函数直接返回出条件下(MD001,MD003)下的最小db这样调的方法就是select dbo.getdb(mdoo1,mdoo3)
    from BOMMD
    where MD001='1300-00601105' and MD003='3230-00601010' 
      

  7.   

    改成如下:ALTER FUNCTION [dbo].[Getdb](@part1 varchar(20),@part2 varchar(20)) 
    RETURNS varchar(4)@t table(reno int,P1 CHAR(20),P2 CHAR(20),DB CHAR(4)) 
    AS 
    BEGIN 
    declare @i int 
    declare @t table(reno int,P1 CHAR(20),P2 CHAR(20),DB CHAR(4)) 
    set @i=1 
    insert into @t 
    select @i as reno,@part1 as P1,MD003 as P2,MC005 as DB 
    from BOMMD A 
    left join BOMMC B on A.MD001=B.MC001 
    where MD001=@part1 while @@ROWCOUNT>0  
    begin 
        set @i=@i+1 
        insert into @t 
        select @i,@part1,MD003,MC005 
        from @t A 
        left join BOMMD B on A.P2=B.MD001 
        left join BOMMC C on B.MD001=C.MC001 
        where A.reno=@i-1 and not(B.MD001 is null) 
    end 
    delete @t where P2 <>@part2 
    declare @mindb varchar(4)
    select @mindb = min(db) from @tRETURN  @mindb
    end
    调用:
    select dbo.getdb(mdoo1,mdoo3)
    from BOMMD
    where MD001='1300-00601105' and MD003='3230-00601010' 
      

  8.   

    ALTER FUNCTION [dbo].[Getdb](@part1 varchar(20),@part2 varchar(20)) 
    RETURNS varchar(4)
    AS 
    BEGIN 
    declare @i int 
    declare @t table(reno int,P1 CHAR(20),P2 CHAR(20),DB CHAR(4)) 
    set @i=1 
    insert into @t 
    select @i as reno,@part1 as P1,MD003 as P2,MC005 as DB 
    from BOMMD A 
    left join BOMMC B on A.MD001=B.MC001 
    where MD001=@part1 while @@ROWCOUNT>0  
    begin 
        set @i=@i+1 
        insert into @t 
        select @i,@part1,MD003,MC005 
        from @t A 
        left join BOMMD B on A.P2=B.MD001 
        left join BOMMC C on B.MD001=C.MC001 
        where A.reno=@i-1 and not(B.MD001 is null) 
    end 
    delete @t where P2 <>@part2 
    declare @mindb varchar(4)
    select @mindb = min(db) from @tRETURN  @mindb
    end
      

  9.   

    这样调的方法就是 
    SQL codeselect dbo.getdb(mdoo1,mdoo3)
    from BOMMD
    where MD001='1300-00601105' and MD003='3230-00601010' 
      

  10.   


    因为Getb返回的可能有多条记录,在函数中对多条记录删除留下一条?
    我实际的需求是这样的:
    需要从请购明细表上反映出每一个采购件都用在哪个工作中心.
    分析如下:
    请购单有记录订单号,由订单号可追溯成品编号
    BOM表有记录主件工单别,工单别可反映工作中心所以就写了函数依据请购明细表每行的成品编码及采购件编码,到BOM表进行循环查找,获取该采购件在该成品中的位置并返回工单别.