这是游标的合适情况吗?

时间:2009-10-15 15:26:26

标签: tsql sql-server-2000

我有以下脚本:

SELECT left(SHI.FSOKEY, 6) AS [SoNo]
,      substring(SHI.FSOKEY, 7, 3) AS [So Item]
,      right(SHI.FSOKEY, 3) AS [So Rels]
,      QAL.FCLOT AS [LotSerial]

FROM shmast SHM
     INNER JOIN shitem SHI
     ON SHM.FSHIPNO = SHI.FSHIPNO
     INNER JOIN qalotc QAL
     ON SHM.FSHIPNO = Left(QAL.FCUSEINDOC, 6)
        AND substring(QAL.FCUSEINDOC, 7, 6) = SHI.FITEMNO

这会产生如下所示的输出:

SoNo      So Item  SoRels  LotSerial
123456      1      001     ABCD
123456      1      001     AMOH
123456      1      001     POWK
123456      1      001     IUIL
123456      1      002     ABCE

我想通过SoNo,SoItem,SoRels进行分组并获取每个LotSerial的列表。所以,我的输出看起来像这样:

SoNo      So Item  SoRels  LotSerial
123456      1      001     ABCD, AMOH, POWK, IUIL
123456      1      002     ABCE

我需要这样做,我可以将此信息提取回基于SoNo,SoItem,SoRels的主查询。

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:5)

一如既往,尽可能避免使用游标。您的场景非常适合用户定义的功能。我为这个例子简化了你的模式。本质上,我们将与逗号匹配的序列连接到用户定义函数中的变量,然后重新调整结果。如果可以使用Null值,则可能需要添加Coalesce

的用法
create table SO (SONO int)
insert into SO values (1)
insert into SO values (2)
insert into SO values (3)


create table SOCHILD 
(SONO int, SerialNo varchar(10))
insert into SOCHILD values (1, 'ABCD')
insert into SOCHILD values (1, 'EFGH')
insert into SOCHILD values (1, 'IJKL')
GO
create function fx_GetSerials(@SONO int)
returns varchar(1000) as
Begin
    Declare @ret varchar(1000)
    set @ret = ''
    Select @ret = @ret + SerialNo + ','
    from SOCHILD where SONO = @SONO
    if (len(@ret) > 0) 
        set @Ret = left(@ret, len(@ret) -1)
    return @ret 
End 
GO
select dbo.Fx_GetSerials(1)
drop function fx_GetSerials 
Drop table SO
Drop table SOCHILD

结果 ABCD,EFGH,IJKL

答案 1 :(得分:2)

@cmsjr beat me to it with his answer这也是一样的。我以不同的方式构建字符串,并有一个完整的工作示例。

试试这个:

CREATE TABLE YourTable  (SoNo int, SoItem int, SoRels char(3),  LotSerial char(4))
go
INSERT INTO YourTable VALUES (123456,1,'001','ABCD')
INSERT INTO YourTable VALUES (123456,1,'001','AMOH')
INSERT INTO YourTable VALUES (123456,1,'001','POWK')
INSERT INTO YourTable VALUES (123456,1,'001','IUIL')
INSERT INTO YourTable VALUES (123456,1,'002','ABCE')
go
CREATE FUNCTION LotSerial_to_CVS(@SoNo int, @SoItem int, @SoRels char(3))
RETURNS varchar(2000) AS
BEGIN
    DECLARE @cvs varchar(2000)
    SELECT @cvs=ISNULL(@cvs+', ','')+LotSerial
        FROM YourTable
        WHERE SoNo=@SoNo AND SoItem=@SoItem AND SoRels=@SoRels
    RETURN @cvs
END
go

SELECT
    SoNo, SoItem, SoRels, dbo.LotSerial_to_CVS(SoNo, SoItem, SoRels)
    FROM YourTable
        GROUP BY SoNo, SoItem, SoRels

输出:

SoNo        SoItem      SoRels 
----------- ----------- ------ -----------------------
123456      1           001    ABCD, AMOH, POWK, IUIL
123456      1           002    ABCE

(2 row(s) affected)

答案 2 :(得分:1)

几乎任何情况下都不需要光标。

您也可以使用XML PATH执行相同的操作。这是一个工作样本:

SET NOCOUNT ON

Declare @MyTable Table
(
    SoNo    VarChar (100),
    SoItem  VarChar (100),
    SoRels  VarChar (100),
    LotSerial   VarChar (100)
)

INSERT INTO @MyTable Values ('123456', '1', '001', 'ABCD')
INSERT INTO @MyTable Values ('123456', '1', '001', 'AMOH')
INSERT INTO @MyTable Values ('123456', '1', '001', 'POWK')
INSERT INTO @MyTable Values ('123456', '1', '001', 'IUIL')
INSERT INTO @MyTable Values ('123456', '1', '002', 'ABCE')

SELECT 
    SoNo, 
    SoItem, 
    SoRels, 
    STUFF ((
        SELECT ', ' + LotSerial 
        FROM @MyTable T1
        WHERE 1=1
            AND T1.SoNo = T2.SoNo
            AND T1.SoItem = T2.SoItem
            And T1.SoRels = T2.SoRels
        FOR XML PATH ('')
    ), 1, 2, '') AS LotSerial
FROM @MyTable T2
GROUP BY SoNo, SoItem, SoRels