【问题标题】:Dynamically search columns for given table动态搜索给定表的列
【发布时间】:2012-07-01 13:39:43
【问题描述】:

我需要为我正在构建的 java 应用程序创建一个搜索,用户可以在其中根据他们当前正在查看的表和他们提供的搜索词搜索 SQL 数据库。一开始我打算做这样简单的事情:

SELECT * FROM <table name> WHERE CAST((SELECT COLUMN_NAME 
  FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '<table name>') 
  AS VARCHAR) LIKE '%<search term>%'

但是该子查询返回多个结果,因此我尝试创建一个过程来遍历给定表中的所有列,并将任何相关字段放入结果表中,如下所示:

CREATE PROC sp_search
    @tblname VARCHAR(4000),
    @term VARCHAR(4000)
AS
    SET nocount on
    SELECT COLUMN_NAME 
    INTO #tempcolumns
    FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @tblname

    ALTER TABLE #tempcolumns
    ADD printed BIT,
        num SMALLINT IDENTITY

    UPDATE #tempcolumns
        SET printed = 0

    DECLARE @colname VARCHAR(4000),
        @num SMALLINT
    WHILE EXISTS(SELECT MIN(num) FROM #tempcolumns WHERE printed = 0)
    BEGIN
        SELECT @num = MIN(num) 
            FROM #tempcolumns 
            WHERE printed = 0
        SELECT @colname = COLUMN_NAME 
            FROM #tempcolumns 
            WHERE num = @num
        SELECT * INTO #results FROM @tblname WHERE CAST(@colname AS VARCHAR) 
                    LIKE '%' + @term + '%' --this is where I'm having trouble
        UPDATE #tempcolumns
            SET printed = 1
            WHERE @num = num

    END

    SELECT * FROM #results
GO

这有两个问题:首先是它以某种方式陷入了无限循环,其次我无法从@tblname 中选择任何内容。我也尝试过使用动态 sql,但我不知道如何从中获得结果,或者这是否可能。

这是我在大学时正在做的一项作业,经过数小时的努力,我已经完成了这个任务。有什么办法可以做我想做的事吗?

【问题讨论】:

  • 顺便说一句,不要在没有指定长度的情况下说VARCHARsqlblog.com/blogs/aaron_bertrand/archive/2009/10/09/…
  • 我早先在大小被声明为 1 的地方遇到了这个问题,但我在我现在无用的代码中修复了这个问题。不要让其他人落入那个陷阱!

标签: sql sql-server-2008 tsql stored-procedures dynamic-sql


【解决方案1】:
  1. 您只需搜索实际包含字符串的列,而不是表中的所有列(可能包括整数、日期、GUID 等)。
  2. 您根本不需要#temp 表(当然也不需要##temp 表)。
  3. 您需要使用动态 SQL(尽管我不确定到目前为止这是否是您课程的一部分)。
  4. 我发现它对follow a few simple conventions 有益,您违反了所有这些:
    • 使用PROCEDURE 而不是PROC - 它不是“prock”,而是“存储过程”。
    • use dbo. (or alternate schema) prefix when referencing any object.
    • 将您的过程主体包裹在BEGIN/END
    • 大量使用元音。您是否节省了那么多击键,更不用说时间,说@tblname 而不是@tablename@table_name?我不是在为特定的惯例而战,但以牺牲可读性为代价来保存字符在 70 年代失去了它的魅力。
    • 不要对存储过程使用sp_ 前缀——这个前缀在SQL Server 中有特殊的含义。为它的作用命名过程。它不需要前缀,就像我们知道它们是表一样,即使没有 tbl 前缀。如果您确实需要一个前缀,请使用另一个前缀,例如 usp_proc_,但我个人认为该前缀不会为您提供任何您还没有的信息。
    • 由于表是使用 Unicode 存储的(您的某些列可能也是),您的参数应该是 NVARCHAR,而不是 VARCHAR。而且标识符的上限为 128 个字符,因此没有理由支持 @tablename 超过 257 个字符。
    • terminate statements with semi-colons.
    • use the catalog views instead of INFORMATION_SCHEMA - 虽然后者是您的教授可能教过并可能期望的。
CREATE PROCEDURE dbo.SearchTable
    @tablename NVARCHAR(257),
    @term      NVARCHAR(4000)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @sql NVARCHAR(MAX);

    SET @sql = N'SELECT * FROM ' + @tablename + ' WHERE 1 = 0'; 

    SELECT @sql = @sql + ' 
      OR ' + c.name + ' LIKE ''%' + REPLACE(@term, '''', '''''') + '%'''
    FROM 
      sys.all_columns AS c
    INNER JOIN 
      sys.types AS t
      ON c.system_type_id = t.system_type_id
      AND c.user_type_id = t.user_type_id
    WHERE 
      c.[object_id] = OBJECT_ID(@tablename)
      AND t.name IN (N'sysname', N'char', N'nchar', 
        N'varchar', N'nvarchar', N'text', N'ntext');

    PRINT @sql;

    -- EXEC sp_executesql @sql;
END
GO

当您对它正在输出您所追求的 SELECT 查询感到满意时,注释掉 PRINT 并取消注释 EXEC

【讨论】:

  • 哇,这很有帮助。我的 SQL 课程不是很深入,但你给了我很好的信息。我们没有被教导去做我想做的事情,所以谷歌几乎是我所有这些的来源。我只是尝试使用另一个临时表来创建一个包含给定表中所有列的表变量,但我失败了。我会给你的代码一个镜头。编辑:它第一次完美运行。非常感谢!我会在我的文档中添加一个链接。
【解决方案2】:

您会进入无限循环,因为即使没有匹配项,EXISTS(SELECT MIN(num) FROM #tempcolumns WHERE printed = 0) 也会始终返回一行 - 您需要改为 EXISTS (SELECT * ....

要使用动态 SQL,您需要为要运行的 SQL 语句构建一个字符串 (varchar),然后使用 EXEC 调用它

例如:

 declare @s varchar(max)
 select @s = 'SELECT * FROM mytable '
 Exec (@s)

【讨论】:

  • 感谢您指出为什么会发生无限循环,并修复了它。关于动态 SQL,正如我在我的 OP 中所说,我之前尝试过。现在我得到这个:“无效的对象名称'#results'。”
  • 是的 - 您需要使用您的 @tblName 变量构建一个字符串来执行该命令。即: exec ('select * from ' + @tblName)
  • 我已经这样做了,我从@tblname 获取数据并放入一个名为#results 的临时表中,我显然无法访问该表。我正在考虑使用 sp_executesql,因为它似乎能够做我想做的事情。也许我不理解你。
  • 即使我使用##results 而不是#results,它仍然无法正常工作。我不断收到同样的错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-11
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多