搜索存储过程和视图但忽略注释

时间:2017-10-12 23:40:07

标签: sql-server tsql

我有一个查询

select 
    definition 
from 
    sys.objects so 
join 
    sys.sql_modules ssmsp on so.[object_id] = ssmsp.[object_id]
where 
    so.type in ('v', 'p')
where 
    definition like '%exec%'

在填充记录时,也会从评论中填充。如何避免过滤评论?

有没有解决方案?

由于

2 个答案:

答案 0 :(得分:0)

我认为在单个查询中几乎不可能实现这一目标。

请记住[定义]没有格式,没有换行符等。代码是一行(复制一行并将其粘贴到编辑器中)。

如果评论以--开头,那么它会在哪里结束?你无从知晓。

使用/*会更容易一些,因为您可以找到相应的*/,但搜索字符串的多次出现仍然会增加复杂性。

使用PATINDEX并指定一个区分大小写的排序规则(如果您有一个不区分大小写的数据库),您可能会有更多的运气,例如,您知道只希望出现EXEC而不是"执行"例如WHERE patindex('%EXEC%',defintion COLLATE SQL_Latin1_General_CP1_CS_AS) > 0

答案 1 :(得分:0)

首先是快速varchar(max)字符串" splitter"。以下是Jeff Moden delimitedSplit8K的黑客版本。

IF OBJECT_ID('dbo.DelimitedSplit2B','IF') IS NOT NULL DROP FUNCTION dbo.DelimitedSplit2B;
GO
CREATE FUNCTION dbo.DelimitedSplit2B
(
  @pString    varchar(max), 
  @pDelimiter char(1)
)
RETURNS TABLE WITH SCHEMABINDING AS RETURN
WITH L1(N) AS 
(
  SELECT N 
  FROM (VALUES 
   (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
   (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
   (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
   (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
   (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
   (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
   (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
   (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
   (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
   (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),
   (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t(N)
), --216 values
 cteTally(N) AS 
(
  SELECT 0 UNION ALL
  SELECT TOP (DATALENGTH(ISNULL(@pString,1))) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
  FROM L1 a CROSS JOIN L1 b CROSS JOIN L1 c
  --2,176,782,336 rows: enough to handle  2,147,483,647 characters (the varchar(max) limit)
), 
cteStart(N1) AS 
(
  SELECT t.N+1
  FROM cteTally t
  WHERE (SUBSTRING(@pString,t.N,1) = @pDelimiter OR t.N = 0)
)
SELECT
  ItemNumber = ROW_NUMBER() OVER(ORDER BY s.N1),
  Item = SUBSTRING(@pString,s.N1,ISNULL(NULLIF((LEAD(s.N1,1,1)
           OVER (ORDER BY s.N1) - 1),0)-s.N1,DATALENGTH(ISNULL(@pString,1))))
FROM cteStart s;

接下来搜索您的DDL的功能

create function dbo.SearchObjectDDLFor (@searchstring varchar(100), @maxLen int)
returns table as return
select objectName, lineNumber, lineText
from
(
  select 
    objectName    = ss.[name]+'.'+so.[name], 
    lineNumber    = itemnumber,
    lineText      = substring(t.item, 1, isnull(nullif(charindex('--', t.item),0)-1, 8000)),
    isLongComment =
    sum
    ( -- this will assign a 1 for everything 
      case when t.item like '/*%' then 1 
           when t.item like '*/%'then -1 
           else 0 end
    ) over (partition by so.[name] order by itemnumber)
  from sys.objects so
  join sys.sql_modules ssmsp on so.[object_id] = ssmsp.[object_id]
  join sys.schemas ss on so.schema_id = ss.schema_id
  cross apply dbo.delimitedSplit2B(definition, char(10))
  cross apply (values (rtrim(ltrim(replace(item,char(13),''))))) t(item)
  where so.type in ('v', 'p')
  and len(definition) < isnull(@maxLen,100000) -- character limit is @maxLen (100K default)
) splitLines
where isLongComment = 0 and lineText not like '--%' and lineText <> '*/'
and   lineText like '%'+@searchstring+'%';

此功能:

  1. 接受要搜索的输入字符串(@searchstring)
  2. 将对象拆分为行
  3. 仅返回不属于评论
  4. 的行部分
  5. 过滤在步骤3中为包含@searchstring的行创建的行,并返回ObjectName(。),行号和文本。
  6. <强>注意事项:

    1. 我只是快速地把它扔到一起,原谅任何错误

    2. 接受[n] varchar(max)的t-sql拆分器会很慢。 CLR分离器可能会更快但我们不会谈论数百万行。也就是说,您可以通过使用@maxLen过滤行数来加快速度。 @maxlen说&#34;忽略和具有更多@maxLen行数的对象。&#34;当为null时,它将搜索长达100K行的对象(但这可以调整)。

    3. 此功能可以解决评论所看到的评论情况&#34; - &#34;字符串中的任何位置:以及评论嵌套在&#34; / &#34;之间的情况。和&#34; \在不同的行上。 一些需要更多编码来抑制评论的场景包括:

    4. select col1, /* skipping col2 for now */ col3, col4
      

      /*********
      comments here
      *********/
      

      <强>示例:

      select * from dbo.SearchObjectDDLFor('nocount', NULL);
      select * from dbo.SearchObjectDDLFor('nocount', 2000);
      

      结果将类似于:

      enter image description here