5

通过以下脚本,我得到了数据库中的所有存储过程:

SELECT sm.id, OBJECT_NAME(sm.id) AS object_name, sm.text
FROM syscomments AS sm
JOIN sysobjects AS so ON sm.id = so.id
WHERE (so.status >= 0) AND (so.xtype = 'P')

我想为每个存储过程获取一行。表 syscomments 中的文本字段是 nvarchar 4000。因此一个方法可能存储在多个寄存器中。问题是我有超过 15000 个字符的存储过程。

识别使用多条记录的 SP

SELECT sm.id, COUNT(sm.colid) AS Cantidad
INTO #SPrepeated
FROM  syscomments AS sm INNER JOIN
      sysobjects AS so ON sm.id = so.id
WHERE (so.status >= 0) AND (so.xtype = 'P') AND (so.category = 0)
GROUP BY sm.id, so.name
HAVING   (COUNT(sm.colid) > 1)

SELECT sm.id, OBJECT_NAME(sm.id) AS object_name, sm.text
into #Tresult
FROM syscomments AS sm
JOIN sysobjects AS so ON sm.id = so.id
JOIN #SPrepeated as spr ON so.id = spr.id
WHERE (so.status >= 0) AND (so.xtype = 'P')

select * from #Tresult

drop table #Tresult
drop table #SPrepeated

#TResult我有所有在表中有多个记录的存储过程syscomments。鉴于结果可能超过 8000 个字符,如何将它们分组并连接到每个过程的单个记录中?

4

3 回答 3

3

如果您被迫使用 SQL Server 2000,您几乎必须使用textorntext字段来分别超过 4000/8000 个字符的nvarchar限制varchar

您不能在textntext字段上使用常规字符串命令,这使它变得一团糟。

如果您真的希望每个存储过程都在一行中,您可以尝试以下操作。

下面的代码是可憎的,没有两种方法。我接受了您的基本查询,并使用游标READTEXTUPDATETEXT,在一行中创建了存储过程列表。代码中的注释应该有望帮助确定我正在尝试做什么。

这还没有经过 100% 的测试,所以如果有任何问题,请告诉我。

-- Gonzalo's original code --
SELECT sm.id, COUNT(sm.colid) AS Cantidad
INTO #SPrepeated
FROM  syscomments AS sm INNER JOIN
      sysobjects AS so ON sm.id = so.id
WHERE (so.status >= 0) AND (so.xtype = 'P') AND (so.category = 0)
GROUP BY sm.id, so.name
HAVING   (COUNT(sm.colid) > 1)

SELECT sm.id, sm.colid, OBJECT_NAME(sm.id) AS object_name, 
    cast(sm.text as ntext) as [text]
into #Tresult
FROM syscomments AS sm
JOIN sysobjects AS so ON sm.id = so.id
JOIN #SPrepeated as spr ON so.id = spr.id
WHERE (so.status >= 0) AND (so.xtype = 'P')

-- Create our #TresultSingle temporary table structure --    
SELECT TOP 1 [id], object_name, cast([text] as ntext) as [text]
INTO #TresultSingle
FROM #Tresult

-- Clear out the table, ready to insert --        
TRUNCATE TABLE #TresultSingle

DECLARE @id int, @previd int, @colid int, @objectname nvarchar(4000), 
    @text nvarchar(4000)
DECLARE @ptrval varbinary(16), @offset int
SET @text = ''

-- Begin cursor, and start praying --   
DECLARE ResultCursor CURSOR
FOR 
SELECT [id], colid, [object_name], [text]
FROM #Tresult
ORDER BY [id], colid

OPEN ResultCursor

FETCH NEXT FROM ResultCursor
INTO @id, @colid, @objectname, @text

INSERT INTO #TresultSingle
SELECT @id, @objectname, @text

WHILE @@FETCH_STATUS = 0
BEGIN
     -- If the ID has changed, create a new record in #TresultSingle --
    IF @id <> @previd
    BEGIN
        INSERT INTO #TresultSingle
        SELECT @id, @objectname, @text
    END
    ELSE
    BEGIN
        -- Get the textpointer of the current @id --
        SELECT @ptrval = TEXTPTR(text) 
        FROM #TresultSingle
        WHERE [id] = @id 

        -- Set our offset for inserting text --
        SET @offset = 4000 * (@colid - 1)

        -- Add the new text to the end of the existing text --
        UPDATETEXT #TresultSingle.text @ptrval @offset 0 @text
    END

    SET @previd = @id

    FETCH NEXT FROM ResultCursor
    INTO @id, @colid, @objectname, @text
END

CLOSE ResultCursor
DEALLOCATE ResultCursor

SELECT * FROM #TresultSingle

DROP TABLE #TresultSingle
drop table #Tresult
drop table #SPrepeated
于 2012-11-13T14:23:59.363 回答
2

即使@LittleBobbyTables 的解决方案工作正常(还没有测试,所以我只是假设它可以),这不会返回 SP 的全文:

在 EM 和 SSMS 中,SELECT 根据提到的选项截断结果。无论任何选项如何,PRINT 也会截断 8000 字节。

我建议从 C# 应用程序而不是在本机 T-SQL 中调用 SELECT 语句。

于 2012-11-13T16:36:04.330 回答
0

我按照@devio 的建议从应用程序中调用了 SELECT 语句,它运行良好(文本字段没有被截断)。@LittleBobbyTables 建议的脚本是该问题的解决方案,只需稍作修改,因为第一条记录被连接两次相同的字符串。

解决方案

-- Gonzalo's original code --
SELECT sm.id, COUNT(sm.colid) AS Cantidad
INTO #SPrepeated
FROM  syscomments AS sm INNER JOIN
  sysobjects AS so ON sm.id = so.id
WHERE (so.status >= 0) AND (so.xtype = 'P') AND (so.category = 0)
GROUP BY sm.id, so.name
HAVING   (COUNT(sm.colid) > 1)

SELECT sm.id, sm.colid, OBJECT_NAME(sm.id) AS object_name, 
    cast(sm.text as ntext) as [text]
into #Tresult
FROM syscomments AS sm
JOIN sysobjects AS so ON sm.id = so.id
JOIN #SPrepeated as spr ON so.id = spr.id
WHERE (so.status >= 0) AND (so.xtype = 'P')


-- LittleBobbyTables code

-- Create our #TresultSingle temporary table structure --    
SELECT TOP 1 [id], object_name, cast([text] as ntext) as [text]
INTO #TresultSingle
FROM #Tresult

-- Clear out the table, ready to insert --        
TRUNCATE TABLE #TresultSingle

DECLARE @id int, @previd int, @colid int, @objectname nvarchar(4000), 
    @text nvarchar(4000)
DECLARE @ptrval varbinary(16), @offset int
SET @text = ''
set @previd = 0;

-- Begin cursor, and start praying --   
DECLARE ResultCursor CURSOR
FOR 
SELECT [id], colid, [object_name], [text]
FROM #Tresult
ORDER BY [id], colid

OPEN ResultCursor

FETCH NEXT FROM ResultCursor
INTO @id, @colid, @objectname, @text

WHILE @@FETCH_STATUS = 0
BEGIN
-- If the ID has changed, create a new record in #TresultSingle --
IF @id <> @previd
BEGIN
    INSERT INTO #TresultSingle
    SELECT @id, @objectname, @text
END
ELSE
BEGIN
        -- Get the textpointer of the current @id --
        SELECT @ptrval = TEXTPTR(text) 
        FROM #TresultSingle
        WHERE [id] = @id 

        -- Set our offset for inserting text --
        SET @offset = 4000 * (@colid - 1)
        -- Add the new text to the end of the existing text --
        UPDATETEXT #TresultSingle.text @ptrval @offset 0 @text
    END

    SET @previd = @id

    FETCH NEXT FROM ResultCursor
    INTO @id, @colid, @objectname, @text
END

CLOSE ResultCursor
DEALLOCATE ResultCursor

SELECT * FROM #TresultSingle

DROP TABLE #TresultSingle
drop table #Tresult
drop table #SPrepeated
于 2012-11-13T19:16:47.407 回答