MySQL - Como verificar um valor em todas as colunas

11

Estou curioso, existe uma boa maneira de pesquisar todas as colunas para um determinado valor? Para meus propósitos, não precisa ser nada rápido, é apenas uma coisa única e não quero realmente digitar todos os nomes de campos. É exatamente o que farei por enquanto, mas acho que certamente há uma maneira melhor.

Gostaria de transformar isso:

SELECT * FROM table WHERE col1 = 'val' OR col2 = 'val' OR col3 = 'val';

nisso:

SELECT * FROM table WHERE * = 'val'

... ou melhor ainda (embora eu duvide muito ...)

SELECT * FROM table WHERE * like '%val%'

Achei isso , que parece meio não muito próximo, mas não estou encontrando nada mais perto:

SELECT whatever WHERE col1,col2 IN ((val1, val2), (val1, val2), ...)

A diferença é que ele pesquisa uma seleção de colunas pelos valores especificados, enquanto eu estou tentando pesquisar TODAS as colunas por um único valor.

Não é importante, porém, como eu disse mais do que tudo, estou apenas curioso

donutguy640
fonte

Respostas:

23

O SQL não fornece uma boa maneira de fazer isso, porque provavelmente não é um bom design de tabela ter N colunas que possam ter valores no mesmo domínio. Isso é potencialmente um caso de "grupos de repetição" como se você tiver colunas phone1, phone2, phone3, ... phoneN.

Se você tiver um número de colunas com o mesmo domínio lógico de valores, pode ser um caso em que é um atributo com vários valores (como o exemplo dos telefones). A maneira padrão de armazenar atributos com vários valores é como várias linhas em outra tabela, com uma referência à linha a que pertencem na tabela principal.

Se você fizer isso, precisará procurar apenas o valor específico em uma coluna da tabela dependente.

SELECT t.* FROM mytable AS t
JOIN phones AS p ON t.primaryKey = p.refKey 
WHERE p.phone = ?
Bill Karwin
fonte
11
E se, por qualquer motivo, você não puder alterar o layout da tabela, escreva uma visualização que represente os dados nesse formato e, em seguida, consulte-a.
CodeCaster 16/09/19
10
Não, basta alterar o layout da tabela. É isso aí. Estou cansado da desculpa "não posso mudar isso". Eu não aceito mais isso. É hora de aprender como mudar as coisas.
Bill Karwin
15

Quanto mais você se aproxima disso, usando IN:

SELECT * FROM table WHERE 'val' IN (col1, col2, ..., colN) ;

Você ainda precisa escrever todas as colunas que deseja verificar.
E não é diferente da ORexpressão que você tem, nem no desempenho nem no contrário. Esta é apenas uma maneira diferente e equivalente de escrever a expressão, com um pouco menos de caracteres.

ypercubeᵀᴹ
fonte
3

Você precisa fazer isso em duas etapas, primeiro gere o sql (assumindo que sua tabela seja chamada T no esquema S:

select concat(' SELECT * FROM t WHERE ''a'' in ('
             , GROUP_CONCAT(COLUMN_NAME)
             , ')')
from INFORMATION_SCHEMA.columns 
where table_schema = 's' 
  and table_name = 't'
  and DATA_TYPE IN ('char','varchar');

Agora você pode executar essa sequência. Observe que você deve citar o 'a' com extra '. Se você colocar isso por exemplo em um procedimento, poderá preparar e executar a sequência que foi gerada.

Eu testei com:

create table t (a char(3), b varchar(5), c int);
insert into t(a,b) values ('a','b'),('b','c'),('c','c');    

A consulta gerada onde:

SELECT * FROM t WHERE 'a' in (a,b)

e executar isso resulta em:

a   b   c
---------
a   b   
Lennart
fonte
1

Parece que já faz um ano desde que eu perguntei isso, mas eu tropecei no que parece ser a coisa exata que eu estava procurando! Não é uma instrução SQL, como eu estava antecipando, mas faz o que eu estava querendo.

No MySQL Workbench, você pode clicar com o botão direito do mouse na tabela ou no esquema e escolher Pesquisar Dados da Tabela.menu de contexto do esquema

donutguy640
fonte
0

Tente este:

select
    *
from
    _table_
where
    concat('.', col1, '.', col2, '.', col3, '.') like "%.search_value.%";

Isso pressupõe que não há .na sua sequência de pesquisa. Se você não pode garantir isso, talvez possa usar um “caractere separador” diferente.

Anon0012398193
fonte
11
Você poderia explicar por que sua solução funciona, por favor? As respostas apenas de código não são vistas como uma boa resposta aqui.
George.Palacios
isso não funciona. por exemplo, se a pesquisa contiver %ou _ou qualquer coluna contiver.
Jasen
11
@ Jason Você pode escapar dos caracteres especiais e usar um separador diferente.
Anon0012398193
@ George.Palacios - o que você acha incerto?
Anon0012398193
escolher o separador correto pode ser muito difícil. esta abordagem é muito difícil de fazer direito
Jasen
0

A solução mais simples é fazer

mysqldump ... --skip-extended-insert db table | grep 'val'

A menos que o val seja algo comum na sintaxe sql.

jkavalik
fonte
Espero que você esteja zombando de mim, pois a alternativa é que você pensou que isso seria útil.
donutguy640
11
Definitivamente não sou. É uma maneira válida de encontrar algo se você não souber "onde" está na tabela db /. O grep retornará as linhas inteiras (incluindo o nome da tabela) onde o valor está presente. Não é SQL e não é muito útil se você deseja processar a saída programaticamente, mas é simples e bastante rápido.
Jkavalik 19/09/19
-2

Tente isto.

SELECT *
FROM table
WHERE CONCAT(col1,' ',col2,' ',col3)="val val val";

CONCAT () é usado para separar os valores da coluna, da mesma forma que aqui você pode separar sua coluna com espaço para especificar o melhor resultado dentro da função e verificar o valor da string separada com espaço e o resultado está na sua mão.

Deepak
fonte
-3

É possível usar o banco de dados information_schema, basicamente listaremos todas as colunas de uma tabela específica e usaremos GROUP_CONCAT para listá-las como uma linha e depois alimentá-las em uma instrução IN.

select * from db.table where 'value' in (select GROUP_CONCAT(COLUMN_NAME) from INFORMATION_SCHEMA.columns where table_schema = 'db' and table_name = 'table');

Isso retornará uma linha apenas se 'value' estiver presente em todas as colunas.

Rodie
fonte
11
Você quer dizer if 'value' is present in any of the columns? Além disso, você pode adicionar um predicado para tipos de string como: `e DATA_TYPE IN ('char', 'varchar')`
Lennart
11
Isso fará isso e cumpre o objetivo do OP de evitar nomear explicitamente as colunas. Não é um curinga, mas o GROUP_CONCAT no esquema de informações é tão bom quanto um curinga de todos os nomes de colunas.
tbrookside
2
Estou tendo problemas para fazer isso funcionar. Substituí db e table pelos meus nomes de esquema e tabela. Existe mais alguma coisa que serve como espaço reservado para nomes reais? Além disso, tentei a declaração interna por conta própria e estou percebendo que CONCATOS os nomes das colunas, em vez dos dados de uma linha. É isso que você pretendia?
donutguy640
4
Com todo o respeito, isso está errado. Sua consulta irá comparar 'valor' com os nomes das colunas, não com o conteúdo . Eu tenho que dar um voto negativo.
Bill Karwin
4
Mais precisamente, isso comparará a string 'value' com a string que é uma lista de nomes de colunas separados por vírgula - essencialmente o mesmo que where 'value' in ('col1,col2,col3…').
Andriy M