Mysql query search a string in all columns of a table - mysql

I wonder how I can mount a SQL as portable as possible to query for all columns of a table for a specific phrase, like:
Table
ID | Name | text | Date | Author | Status
1 | Augusto Weiand | Test text | 2010-01-01 | Deividi | 1
Query
SELECT *
FROM table
WHERE columns LIKE '%augusto%2010%text%"
I did not put enough detail, excuse me, I like to make a dynamic SQL, where I do not need to specify the columns with 'AND' or 'OR', as it is possible to do in Postgres:
Select *
From table
Where table::text ~~ '%augusto%2010%text%'

Here is how you would concatenate the values in dynamic SQL:
set #Pattern = '%augusto%';
select #q := concat('select * from Table1 ',
'where concat(', group_concat(column_name), ', "") like "', #Pattern, '"'
)
from information_schema.columns c
where table_name = 'Table1';
prepare st from #q;
execute st;
deallocate prepare st;
Of course, dynamic SQL is not particularly portable. The idea would work in most databases. The code would look different.
Tested and working here.
And finally, you can do this with variable substitution (which is the better approach):
select #q := concat('select * from Table1 ',
'where concat(', group_concat(column_name), ', "") like ?'
)
from information_schema.columns c
where table_name = 'Table1';
set #p = '%augusto%';
prepare st from #q;
execute st using #p;
deallocate prepare st;
Also tested (;-).

It's doable, although I strongly suggest you look into full-text search for efficiency;
To avoid looking for all patterns in all fields one by one, you can just concat and search in that;
SELECT *
FROM (SELECT id,CONCAT(name,'|',text,'|',date,'|',author,'|',status) txt
FROM Table1) a
WHERE txt LIKE '%augusto%'
AND txt LIKE '%2010%'
AND txt LIKE '%text%';
Note that no indexing will help you here, since you're searching in a calculated column. On the other hand, since you're searching with a leading wildcard %searchterm, you won't get much help from indexes even if searching field by field :)
An SQLfiddle to test with.

try this
Select * FROM table WHERE text LIKE "%text%"
OR date LIKE "%2010%"
OR Name LIKE "%augusto%"
if you want them all together then use AND
Select * FROM table WHERE text LIKE "%text%"
AND date LIKE "%2010%"
AND Name LIKE "%augusto%"

you can use this store procedure to search a text in all column in table
CREATE PROCEDURE dbo.sp_FindStringInTable #stringToFind VARCHAR(100),
#schema
sysname, #table sysname
AS
BEGIN TRY
DECLARE #sqlCommand varchar(max) = 'SELECT * FROM [' + #schema + '].[' +
#table + '] WHERE '
SELECT #sqlCommand = #sqlCommand + '[' + COLUMN_NAME + '] LIKE ''' +
#stringToFind + ''' OR '
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = #schema
AND 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
Execute it like this
EXEC sp_FindStringInTable '%searchword%','schema_name', 'tablename'

Related

Truncate in multiple tables

I'm trying to create a way for me to apply truncate across multiple tables at the same time.
I tried the following code:
SELECT CONCAT('TRUNCATE TABLE ',table_schema,'.',TABLE_NAME, ';')
FROM INFORMATION_SCHEMA.TABLES
WHERE table_schema in ('mytable1','mytable2','mytable3');
More unsuccessfully, it is not truncating the tables.
Does anyone know of any way to do this?
DECLARE #CODE NVARCHAR(MAX) = '', #XML XML
SET #XML = STUFF((
SELECT ' ' + data.CODE_DELETE
FROM (
SELECT CONCAT ('TRUNCATE TABLE ', table_schema, '.', TABLE_NAME, '') AS CODE_DELETE
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME IN ('CITY', 'WORKERS')
) [data]
FOR XML PATH('')
), 1, 1, '')
SET #CODE = CAST(#XML AS VARCHAR(MAX))
SELECT #CODE
EXECUTE sp_executesql #CODE;
the variable #XML is to be able to convert the rows into a single value, then we must convert the sql code to varchar in order to execute it with
EXECUTE sp_executesql #CODE;
you can see the code that will be executed if you do this:
SELECT #CODE
city ​​and workers are tables that I have in my database, if you look I change table_schema by TABLE_NAME in the WHERE clause.
Please use transaction to do it if you want to keep it atomic.
START TRANSACTION;
// Your truncate statements;
COMMIT;

Mysql UNION with dynamic query

i have the following problem. I inherited a software that uses a database prefix for every customer.
All tables have the same structure and columns. For a data migration to new version i want to union all these tables
and set a customer foreign key instead and get rid of all the subtables. i'm looking for a way to create
a view for this task because i also want to stay backwards compatible for now.
I found this dynamic query which seems to do what i want
but i can't execute on my mysql server. I assume it was written for another sql server.
The table name structure is (about 80 customer tables):
customer1_faxe
customer2_faxe
customer3_faxe
customer4_faxe
...
How would you approach this problem?
DECLARE #SelectClause VARCHAR(100) = 'SELECT *'
,#Query VARCHAR(1000) = ''
SELECT #Query = #Query + #SelectClause + ' FROM ' + TABLE_NAME + ' UNION ALL '
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '%_faxe'
SELECT #Query = LEFT(#Query, LEN(#Query) - LEN(' UNION ALL '))
EXEC (#Query)
This query is using SQL Server syntax. You need something like this:
declare #SelectClause varchar(8000);
declare #Query varchar(8000);
set #SelectClause = 'SELECT *';
SELECT #Query := group_concat(#SelectClause, ' FROM ', TABLE_NAME SEPARATOR ' UNION ALL ')
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '%_faxe';
prepare stmt from #Query;
execute stmt;
Note that the group_concat() with separator simplifies the logic.

copy entire row (without knowing field names)

Using SQL Server 2008, I would like to duplicate one row of a table, without knowing the field names. My key issue: as the table grows and mutates over time, I would like this copy-script to keep working, without me having to write out 30+ ever-changing fields, ugh.
Also at issue, of course, is IDENTITY fields cannot be copied.
My code below does work, but I wonder if there's a more appropriate method than my thrown-together text string SQL statement?
So thank you in advance. Here's my (yes, working) code - I welcome suggestions on improving it.
Todd
alter procedure spEventCopy
#EventID int
as
begin
-- VARS...
declare #SQL varchar(8000)
-- LIST ALL FIELDS (*EXCLUDE* IDENTITY FIELDS).
-- USE [BRACKETS] FOR ANY SILLY FIELD-NAMES WITH SPACES, OR RESERVED WORDS...
select #SQL = coalesce(#SQL + ', ', '') + '[' + column_name + ']'
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'EventsTable'
and COLUMNPROPERTY(OBJECT_ID('EventsTable'), COLUMN_NAME, 'IsIdentity') = 0
-- FINISH SQL COPY STATEMENT...
set #SQL = 'insert into EventsTable '
+ ' select ' + #SQL
+ ' from EventsTable '
+ ' where EventID = ' + ltrim(str(#EventID))
-- COPY ROW...
exec(#SQL)
-- REMEMBER NEW ID...
set #EventID = ##IDENTITY
-- (do other stuff here)
-- DONE...
-- JUST FOR KICKS, RETURN THE SQL STATEMENT SO I CAN REVIEW IT IF I WISH...
select EventID = #EventID, SQL = #SQL
end
No, there isn't any magic way to say "SELECT all columns except <foo>" - the way you're doing it is how you'll have to do it (the hack in the other answer aside).
Here is how I would alter your code, with these changes (some are hyperlinked so you can read my opinion about why):
use sys.columns over INFORMATION_SCHEMA.COLUMNS
use nvarchar instead of varchar
use scope_identity instead of ##identity
use sp_executesql instead of exec
use stuff instead of coalesce
use SET NOCOUNT ON
add semi-colons
use the schema prefix
use QUOTENAME since it's safer than '[' + ... + ']'
ALTER PROCEDURE dbo.spEventCopy
#EventID INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += ',' + QUOTENAME(name)
FROM sys.columns
WHERE [object_id] = OBJECT_ID('dbo.EventsTable')
AND is_identity = 0;
SET #sql = STUFF(#sql, 1, 1, '');
SET #sql = N'INSERT dbo.EventsTable(' + #sql + ')
SELECT ' + #sql + ' FROM dbo.EventsTable
WHERE EventID = ' + CONVERT(VARCHAR(12), #EventID) + ';';
EXEC sp_executesql #sql;
SELECT #EventID = SCOPE_IDENTITY();
-- do stuff with the new row here
SELECT EventID = #EventID, SQL = #SQL;
END
If you know the what your identity column is called (and it won't be the column changing), you could do this:
SELECT * INTO #dummy FROM EventsTable where EventID = #EventID;
ALTER TABLE #dummy
DROP COLUMN MyIdentityColumn
INSERT EventsTable SELECT * FROM #dummy
DROP TABLE #dummy
Since a table can only every have one identity column, specifying that in the query shouldn't limit you too much.
As Aaron Bertrand points out, there are risks associated with this approach. Please read the discussion in the comments below.

Something equivalent to "SELECT * FROM (SELECT table_name FROM...)"?

This query runs, but it produces the name of a table as a result, rather than actually selecting from that table.
SELECT T.*
FROM (SELECT tablename
FROM ListOfTables
WHERE id = 0) AS T
where ListOfTables contains id=0, tablename='some_table', I want to return the same result set as if I had written this directly:
SELECT * FROM some_table
Is there a native way to do this in MySQL 5, or do I have to do in in the application?
To do this in MySQL, you need to create a prepared statement which you can only create from a user variable:
SELECT #tn := tablename FROM ListOfTables WHERE id = 0;
SET #qs = CONCAT('SELECT * FROM ', #tn);
PREPARE ps FROM #qs;
EXECUTE ps;
You need to use dynamic SQL to get this result (the below code assumes SQL Server, I can't speak for other RDBMS').
declare #tableName varchar(100)
declare #query varchar(500)
select #tableName = tablename
from ListOfTables
where id = 0
select #query = 'select * from ' + #tableName
exec (#query)
Almost the same as #Shark's answer, except you also quote the name of the table to avoid syntax errors.
-- Using variables just for better readability.
DECLARE #Name NVARCHAR(4000)
DECLARE #Query NVARCHAR(4000)
-- Get the relevant data
SET #Name = QUOTENAME(SELECT tablename FROM ListOfTables WHERE id=0)
-- Build query
SET #Query = 'SELECT * FROM ' + #Schema + '.' + #Name + ''
-- execute it.
EXEC(#Query)

Lower case column names when using SELECT

I'm using the Kohana framework and I need to convert column names to lowercase. I don't have control of the db table structure. I want to do the following:
SELECT LOWER(*) FROM .....
but MYSQL does not like that. Whats the proper way of outputting the lower case column names if I don't know what the column names will be?
Found here http://dev.mysql.com/doc/refman/5.0/en/columns-table.html
SELECT LOWER(COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'Table'
Below you can see both MSSQL and MySQL syntax for creating a dynamic query using the column results from the query above.
MSSQL Syntax
DECLARE #ColumnNames [nvarchar](1024)
SELECT #ColumnNames = COALESCE(#ColumnNames + ', ', '') + LOWER(COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Table'
DECLARE #Sql [nvarchar](1024) = 'SELECT ' + #ColumnNames + ' FROM Table ' --Remember to put spaces after SELECT and before FROM
EXEC(#Sql)
With this you are dynamically building your query and then executing it.
MySQL Syntax
SELECT #ColumnNames := GROUP_CONCAT(LOWER(COLUMN_NAME))
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Table';
SET #Sql = CONCAT('SELECT ', #ColumnNames, ' FROM Table ');
PREPARE stmt1 FROM #Sql;
EXECUTE stmt1;