在不指定所有列名的情况下应用所有列?

Posted

技术标签:

【中文标题】在不指定所有列名的情况下应用所有列?【英文标题】:Apply like over all columns without specifying all column names? 【发布时间】:2012-01-11 06:22:15 【问题描述】:

我发现自己处于一个不熟悉的数据库中,每个表都有大量列。我知道我在寻找什么数据,但我不知道它位于哪一列,需要使用like 才能找到我需要的确切数据(并且必须对多组重复此任务数据)。

有没有办法像笛卡尔选择一样应用?

下面应该解释我想做的更好一点(即使它在语法上很荒谬):

select 
    *
from    
    a_table
where   
    * like '%x%'

编辑

请注意,我不打算在任何报告中使用笛卡尔选择 - 此处的目的是帮助我识别需要放入查询中的相关列并帮助我熟悉数据库.

【问题讨论】:

这是一个有趣的问题。我的背景是使用 bash 命令,所以我想通过 (1) grep 然后 (2) awk 获取数据。以这种方式,您 grep 很多(甚至太多),然后使用额外的 grep 或 awk 语句进行过滤。我很惊讶 SQL 没有内置的“grep”功能。 【参考方案1】:

通常 - 它不可能以合理的方式(不挖掘数据库元数据),但如果你知道列的名称,你可以使用这样的技巧:

select 
    YourTable.*
FROM YourTable
JOIN
( 
    select 
      id, 
      ISNULL(column1,'')+ISNULL(Column2,'')+...+ISNULL(ColumnN,'') concatenated
      FROM YourTable
) T ON T.Id = YourTable.Id
where   t.concatenated like '%x%'

如果您搜索单词 - 使用 FTS 功能,因为上层查询是性能杀手

【讨论】:

性能在这里不是问题,因为我是开发数据库的唯一用户,这是一项一次性任务,但请注意 如果是这样 - 那么或动态查询 - 你甚至不必知道列名或我的变体 花了我一点时间来理解你在这里做什么,但现在我喜欢这个解决方案。赞赏!【参考方案2】:

here 也有类似的讨论。

没有直接的方法,你必须这样做:

SELECT Name, Age, Description, Field1, Field2
FROM MyTable
WHERE Name LIKE 'Something%' OR Description LIKE 'Something%' OR Field1 LIKE 'Something%' OR Field2 LIKE 'Something%'

该论坛中发布的解决方案之一是,它使用动态 SQL:

CREATE PROCEDURE TABLEVIEWSEARCH @TABLENAME        VARCHAR(60),@SEARCHSTRING VARCHAR(50)
-- EXEC TABLEVIEWSEARCH 'GMACT','demo'
-- EXEC TABLEVIEWSEARCH 'TABLEORVIEW','TEST'
AS
SET NOCOUNT ON
DECLARE @SQL      VARCHAR(500),
@COLUMNNAME       VARCHAR(60)

CREATE TABLE #RESULTS(TBLNAME VARCHAR(60),COLNAME VARCHAR(60),SQL VARCHAR(600))
SELECT 
  SYSOBJECTS.NAME AS TBLNAME,
  SYSCOLUMNS.NAME AS COLNAME,
  TYPE_NAME(SYSCOLUMNS.XTYPE) AS DATATYPE
  INTO #TMPCOLLECTION
    FROM SYSOBJECTS
      INNER JOIN SYSCOLUMNS ON SYSOBJECTS.ID=SYSCOLUMNS.ID
    WHERE SYSOBJECTS.NAME = @TABLENAME
    AND TYPE_NAME(SYSCOLUMNS.XTYPE) IN ('VARCHAR','NVARCHAR','CHAR','NCHAR')
    ORDER BY TBLNAME,COLNAME

DECLARE C1 CURSOR FOR 
SELECT COLNAME FROM #TMPCOLLECTION ORDER BY COLNAME
OPEN C1
FETCH NEXT FROM C1 INTO @COLUMNNAME
WHILE @@FETCH_STATUS <> -1
    BEGIN
        --SET @SQL = 'SELECT ''' + @TABLENAME + ''' AS TABLENAME,''' + @COLUMNNAME + ''' AS COLUMNNAME,* FROM ' + @TABLENAME + ' WHERE ' +  @COLUMNNAME + ' LIKE ''%' + @SEARCHSTRING + '%'''
        SET @SQL = 'IF EXISTS(SELECT * FROM [' + @TABLENAME + '] WHERE [' +  @COLUMNNAME + '] LIKE ''%' + @SEARCHSTRING + '%'') INSERT INTO #RESULTS(TBLNAME,COLNAME,SQL) VALUES(''' + @TABLENAME + ''',''' +  @COLUMNNAME + ''','' SELECT * FROM  [' + @TABLENAME + ']  WHERE [' + @COLUMNNAME + '] LIKE  ''''%' + @SEARCHSTRING + '%'''''') ;'
        PRINT @SQL
        EXEC (@SQL)
FETCH NEXT FROM C1 INTO @COLUMNNAME
    END
CLOSE C1
DEALLOCATE C1

SELECT * FROM #RESULTS

GO
CREATE PROCEDURE TABLEVIEWSEARCH2 @TABLENAME        VARCHAR(60),@SEARCHSTRING VARCHAR(50)
-- EXEC TABLEVIEWSEARCH2 'GMACT','SOURCE'
-- EXEC TABLEVIEWSEARCH2 'TABLEORVIEW','TEST'
AS
BEGIN
SET NOCOUNT ON
DECLARE @FINALSQL      VARCHAR(MAX),
@COLUMNNAMES       VARCHAR(MAX)
SET @FINALSQL = 'SELECT * FROM [' + @TABLENAME + '] WHERE 1 = 2 '
SELECT 
    @FINALSQL = @FINALSQL + ' OR [' + SYSCOLUMNS.NAME + '] LIKE ''%' + @SEARCHSTRING + '%'' '

    FROM SYSCOLUMNS 
    WHERE OBJECT_NAME(id) = @TABLENAME
    AND TYPE_NAME(SYSCOLUMNS.XTYPE) IN ('VARCHAR','NVARCHAR','CHAR','NCHAR')
    ORDER BY COLID

PRINT @FINALSQL
EXEC(@FINALSQL)
END --PROC

我已在包含以下数据的员工表上对此进行了测试:

运行以下语句

EXEC TABLEVIEWSEARCH2 'employee','2'

导致:

2   1   eng2
4   2   dev2
7   3   sup2
9   4   qa2

我想我会提供更多这样的例子,因为上面的 Emp 表只有一个用于搜索数据的字段。

这是来自 todo 数据库的任务表:

搜索短语en:(突出显示数据匹配的单元格)

EXEC TABLEVIEWSEARCH2 'task','en'

【讨论】:

【参考方案3】:

不,这在 SQL 中是不可能的。尽管我可以在您的场景中看到用例,但这也被认为是不好的做法。你最好的办法是用你最喜欢的语言编写脚本,方法是检索所有列名的列表,然后对每列执行一个单独的查询,或者执行一个组合所有列的大型查询:

select
    *
from
    a
where
    a.column_1 like '%blah%' or 
    a.column_2 like '%blah%';

或者,单独的查询:

select
    *
from 
    a 
where 
    a.column_1 like '%blah%'

select
    *
from 
    a 
where 
    a.column_2 like '%blah%'

【讨论】:

【参考方案4】:

您可以尝试这样的方法,但如果您的表真的很大,您可能会遇到一些麻烦,因为它会为您的整个表创建一个 XML,然后在 XML 中查询搜索字符串。输出是找到字符串的列名。

;with C(TableXML) as
(
  select *
  from YourTable
  for xml path('T'), type
)
select distinct T.X.value('local-name(.)', 'sysname') as ColumnName
from C
  cross apply C.TableXML.nodes('/T/*') as T(X)
where T.X.value('.', 'varchar(max)') like '%x%'

https://data.stackexchange.com/***/query/58934/new

【讨论】:

【参考方案5】:

谢谢南达 :)

这是我的精简脚本:

use a_database

declare 
    @TableName as nvarchar(50) = 'a_table',
    @FilterContition as nvarchar(50) = 'like ''%x%''',
    @ColumnName as nvarchar(100),
    @ColumnCursor as cursor,
    @Sql as nvarchar(4000)

set @ColumnCursor = cursor for
    select distinct c.name
    from sys.objects as o
    inner join sys.columns as c
        on o.object_id = c.object_id
    where o.name = @TableName
    and type_name(c.user_type_id) in ('VARCHAR','NVARCHAR','CHAR','NCHAR')

open @ColumnCursor
fetch next from @ColumnCursor into @ColumnName 
set @Sql = 'select * from ' + @TableName + ' where ' + @ColumnName + ' ' + @FilterContition
while @@fetch_status = 0
begin
    fetch next from @ColumnCursor into @ColumnName
    set @Sql = @Sql + ' and ' + @ColumnName + ' ' + @FilterContition
end
close @ColumnCursor
deallocate @ColumnCursor

exec(@Sql)

它使用: - 动态sql - 一个光标 - 数据库元数据

【讨论】:

【参考方案6】:
Create PROCEDURE dbo.sp_FindStringInTable @stringToFind VARCHAR(100), @table sysname 
AS

BEGIN TRY
   DECLARE @sqlCommand varchar(max) = 'SELECT * FROM [' + @table + '] WHERE ' 

   SELECT @sqlCommand = @sqlCommand + '[' + COLUMN_NAME + '] LIKE ''' + @stringToFind + ''' OR '
   FROM INFORMATION_SCHEMA.COLUMNS 
   WHERE TABLE_NAME = @table 
   AND DATA_TYPE IN ('char','nchar','ntext','nvarchar','text','varchar')

   SET @sqlCommand = left(@sqlCommand,len(@sqlCommand)-3)
   EXEC (@sqlCommand)
   PRINT @sqlCommand
END TRY

BEGIN CATCH 
   PRINT 'There was an error. Check to make sure object exists.'
   PRINT error_message()
END CATCH 

--然后通过这个调用

EXEC sp_FindStringInTable 'yoursearchitem', 'tablename'

【讨论】:

【参考方案7】:

一种简单的方法: 1. 从 INFORMATION_SCHEMA.COLUMNS 中选择 COLUMN_NAME 其中 TABLE_NAME = 'your_table'

    将结果复制粘贴到 Excel 工作表单元格 B1 type isnull(在单元格A1中 在单元格 C1 中键入 ,'')+ 在单元格 D1 中键入 =A1&B1&C1 向下拖动单元格 A1、C1 和 D1

    复制粘贴列 D 到 SQL

    添加 select * from your_table where ( 开头

    删除末尾的+ 在末尾添加 ) like '%x%' 执行

Excel 是你的朋友!

【讨论】:

以上是关于在不指定所有列名的情况下应用所有列?的主要内容,如果未能解决你的问题,请参考以下文章

如果我只需要对一列应用不同的函数,是不是可以在不列出所有列的情况下应用 agg 函数

如何在不单独指定所有列的情况下对所有列的 SQL 结果进行排序?

如何在不指定列名的情况下从另一个表更新一个表?

具有可变列名的动态更新语句

在 R 中,如何根据一列的值对所有其他列求和,而不指定列名?

如何在不包含新列名和类型的情况下更改现有 Hive 表中的列注释?