web-dev-qa-db-fra.com

Appliquer comme sur toutes les colonnes sans spécifier tous les noms de colonne?

Je me suis trouvé dans une position où je travaille une base de données inconnue qui a un grand nombre de colonnes pour chaque table. J'ai une idée des données que je recherche, mais je ne sais pas dans quelle colonne elle se trouve et je dois utiliser like pour localiser les données dont j'ai besoin (et répéter cette tâche pour plusieurs ensembles de données. ).

Y at-il un moyen d'appliquer comme sur une sélection cartésienne?

Ce qui suit devrait expliquer ce que j'aimerais faire un peu mieux (même si c'est syntaxiquement ridicule):

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

modifier

Notez que je n'ai pas l'intention d'utiliser une sélection cartesion dans les rapports. Son objectif est de m'aider à identifier les colonnes pertinentes que je devrais insérer dans mes requêtes et de me familiariser avec la base de données.

19
Michael A

Généralement - ce n'est pas possible de manière raisonnable ( sans creuser dans les métadonnées de la base de données ), mais si vous connaissez le nom des colonnes, vous pouvez utiliser l'astuce suivante:

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%'

OU

si vous recherchez des mots - utilisez les capacités FTS, car la requête supérieure est un performance killer

15
Oleg Dok

Il y a une discussion similaire ici

Il n'y a pas de moyen direct et vous devez le faire de cette manière:

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

L'une des solutions postées sur ce forum était la suivante: l'utilisation de SQL dynamique:

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

J'ai testé cela sur une table d'employés contenant les données suivantes:

enter image description here

Exécuter la déclaration suivante 

EXEC TABLEVIEWSEARCH2 'employee','2'

abouti à:

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

Je pensais pouvoir donner un autre exemple de cela en action, car le tableau Emp ci-dessus ne contient qu'un champ dans lequel il cherchait les données.

Ceci est une table de tâches d'une base de données todo: enter image description here

Recherche de la phrase en: (cellules surlignées où les données correspondent)

EXEC TABLEVIEWSEARCH2 'task','en'

enter image description here

7
Animesh

Non, ce n'est pas possible avec SQL. Cela serait également considéré comme une mauvaise pratique, même si je peux voir le cas d'utilisation dans votre scénario. Votre meilleur choix est de le rédiger dans votre langue préférée en récupérant une liste de tous les noms de colonnes, puis en exécutant une requête distincte avec un élément similaire à chaque colonne ou une seule requête volumineuse combinant l'ensemble:

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

ou des requêtes distinctes:

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

select
    *
from 
    a 
where 
    a.column_2 like '%blah%'
4
Walter Heck

Vous pouvez essayer quelque chose comme ceci, mais si votre table est vraiment grosse, vous pourriez avoir des problèmes car cela va créer un XML de votre table entière et ensuite interroger le XML pour la chaîne de recherche. La sortie est le nom de la colonne où se trouve la chaîne.

;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%'

http://data.stackexchange.com/stackoverflow/query/58934/new

3
Mikael Eriksson

Merci Nanda :)

voici mon script allégé:

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)

il utilise: - sql dynamique - un curseur - métadonnées de base de données

2
tristan3fish
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 

- alors appel par ceci

EXEC sp_FindStringInTable 'yoursearchitem', 'tablename'
0
asalam345