0

我需要为我正在构建的 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,但我不知道如何从中获得结果,或者这是否可能。

这是我在大学做的一项任务,经过数小时的努力,我已经得到了这个结果。有什么办法可以做我想做的事吗?

4

2 回答 2

0

您进入了一个无限循环,因为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)
于 2012-07-01T14:47:34.353 回答
0
  1. 您只需要搜索实际包含字符串的列,而不是表中的所有列(可能包括整数、日期、GUID 等)。
  2. 您根本不需要#temp 表(当然也不需要##temp 表)。
  3. 您需要使用动态 SQL(尽管我不确定到目前为止这是否是您课程的一部分)。
  4. 我发现遵循一些您已经违反的简单约定是有益的:
    • PROCEDURE不使用PROC- 它不是“prock”,而是“存储过程”。
    • 引用任何对象时使用dbo.(或备用模式)前缀
    • 将您的程序主体包裹在BEGIN/中END
    • 大量使用元音。您是否节省了那么多击键,更不用说时间,说@tblname而不是@tablenameor @table_name?我不是在为特定的约定而战,而是以牺牲可读性为代价来保存字符在 70 年代失去了它的魅力。
    • 不要sp_为存储过程使用前缀 - 此前缀在 SQL Server 中具有特殊含义。为它的作用命名过程。它不需要前缀,就像我们知道它们是表一样,即使没有tbl前缀。如果您确实需要一个前缀,请使用另一个前缀,usp_或者proc_,但我个人认为该前缀不会为您提供任何您还没有的信息。
    • 由于表是使用 Unicode 存储的(您的某些列可能也是),您的参数应该是NVARCHAR,而不是VARCHAR. 并且标识符的上限为 128 个字符,因此没有理由支持超过 257 个字符的@tablename.
    • 用分号终止语句
    • 使用目录视图而不是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.

于 2012-07-01T17:30:57.177 回答