How to search a given text in a table in sql server - sql

I want to search a text in a table without knowing its attributes.
Example : I have a table Customer,and i want to search a record which contains 'mohit' in any field without knowing its column name.

You are looking for Full Text Indexing
Example using the Contains
select ColumnName from TableName
Where Contains(Col1,'mohit') OR contains(col2,'mohit')
NOTE - You can convert the above Free text query into dynamic Query using the column names calculated from the sys.Columns Query
Also check below
FIX: Full-Text Search Queries with CONTAINS Clause Search Across Columns
Also you can check all Column Name From below query
Select Name From sys.Columns Where Object_Id =
(Select Object_Id from sys.Tables Where Name = 'TableName')
Double-WildCard LIKE statements will not speed up the query.

If you wanna make a full search on the table, you must surely be knowing the structure of the table. Considering the table has fields id, name, age, and address, then your SQL Query should be like:
SELECT * FROM `Customer`
WHERE `id` LIKE '%mohit%'
OR `name` LIKE '%mohit%'
OR `age` LIKE '%mohit%'
OR `address` LIKE '%mohit%';

Mohit, I'm glad you devised the solution by yourself.
Anyway, whenever you again face an unknown table or database, I think it will be very welcome the code snippet I just posted here.
Ah, one more thing: the answers given did not addressed your problem, did they?

Related

Full text search VS Fuzzy Search based on many columns

I have an Employee table with these columns :
EmployeeId
Fullname
Phone
Department
Team
Function
Manager
I have a form with a search text input, where a user can type one column or all of them there like for example :
a user can search by Fullname only
a user can search by combining the Fullname + Phone + Team
What is the difference between Full text search and Fuzzy Search in SQL Server in this case?
so you have to options :
using full text search :
if the data is huge and you are looking for scalable data search , this method is preferable , however harder to maintain . so I suggest you add a computed column in that table and put and full text index on that:
alter table tablename
add column cmptcolumn as concat_ws(',',EmployeeId,FullName,PhoneNumber,...)
--full text catalog
CREATE FULLTEXT CATALOG catalogName AS DEFAULT;
-- full text index
create full text index on tablename (cmptcolumn)
-- search :
select * from tablename
where contain(cmptcolumn, 'SearchString');
by full text search you can search for synonyms and also words related to each other as well:
select * from tablename
where freetext(cmptcolumn, 'SearchString');
read more about different full text search options here
using search query. witch again you can benefit from computed column or search inside each column separately:
select *
from tablename
where (Fullname like '%'+#fullNameSearchString+'%' or #fullNameSearchString is null)
and (Department = #DepartmentSearchString or #DepartmentSearchString is null)
and ...
while first method is a faster way to search insode strings, second method provides more accurate result . however 'FreeText' looks for meaning of the word as well, in that case it might be slower.
in the second method either way you go ( with or without computed column) , having index on the column(s) in a necessity to improve the performance , however using like '%%' usually can't use index as it should.
create stored procedure and pass column comma separated check this example:
CREATE Procedure [dbo].Create_Sp
#SearchColumn varchar(500)=null
AS
BEGIN
DECLARE #SQL nvarchar(max)
SELECT #SQL = N'select '+#SearchColumn+' from #Employee'
EXECUTE sp_executesql #SQL
End
Well we know that the main difference between fuzzy and full text is "exactly what im looking for" versus "similarities." As that applies to SQL Server and to your example given, is fulltext search on firstname as opposed to mining similarities across three different columns, which might give a lot of noise depending on how clean your data is or how "guided" the end user experience in terms of entering those values is.
With fulltext search on fullname, im pretty sure that its a straight forward answer:
SELECT * FROM tblEmployee WHERE FullName=#FullNamParameter;
With fuzzy search, it can get very gross and nasty, as without clearer understanding of what the UI is doing I am forced to assume we want to check similarities on all parameters for all fields. TO be fairly honest Im pretty sure this query is the absolutel worst but it does demonstrate the idea for you.
SELECT * FROM tblEmployee WHERE FullName LIKE '%'+#Parameter1+'%'
UNION
SELECT * FROM tblEmployee WHERE FullName LIKE '%'+#Parameter2+'%'
UNION
SELECT * FROM tblEmployee WHERE FullName LIKE '%'+#Parameter3+'%'
UNION
SELECT * FROM tblEmployee WHERE Phone LIKE '%'+#Parameter1+'%'
UNION
SELECT * FROM tblEmployee WHERE Phone LIKE '%'+#Parameter2+'%'
UNION
SELECT * FROM tblEmployee WHERE Phone LIKE '%'+#Parameter3+'%'
UNION
SELECT * FROM tblEmployee WHERE Team LIKE '%'+#Parameter1+'%'
UNION
SELECT * FROM tblEmployee WHERE Team LIKE '%'+#Parameter2+'%'
UNION
SELECT * FROM tblEmployee WHERE Team LIKE '%'+#Parameter3+'%'
A very good solution is searloc. It is a CLR library with zero dependencies and with many features.
It supports full text search, phonetic match for all languages, keyboard match, fuzzy search, multi columns search, and many others.
And the most important it is very fast, it needs just a few milliseconds for millions of records.

Firebird: Using SQL to search all fields?

I have a SQL query that is going to be used to search fields that are most likely going to change a lot. I.e More fields will be added. How can I write a sql query using a simple like that will search across al fields without explicitly specifying the fields?
Something like:
select * from MYTABLE where CONCAT(*) like '%mySearchTerm%';
Is there an easy way to do this?
I think the only way in Firebird is to use calculated field which concats the fields you want to search:
create table T (
foo varchar(24) not null,
bar varchar(24) not null,
...
SearchField varchar(1024) generated always as (foo || '##' || bar)
)
select * from T where SearchField like '%mySearchTerm%';
So each time youre altering the table (adding or dropping an field) you also have to change the calculated field, but the query would remain the same.
But this has some impact on perfomance as you're doing concat you really don't need...
If you have much records and fields in the table and need high performance, I suggest you to search about Full Text Index ou Full Text Search for Firebird.
It is not a native feature. But there are some third party solutions.
See this link: http://www.firebirdfaq.org/faq328/

Full-Text Catalog unable to search Primary Key

I have create this little sample Table Person.
The Id is a primary key and is identity = True
Now when I try to create a FullText Catalog, I'm unable to search for the Id.
If I follow this wizard, I'll end up with a Catalog, where its only possible to search for a persons name. I would really like to know, how I can make it possible to do a fulltext search for both the Id and Name.
edit
SELECT *
FROM [TestDB].[dbo].[Person]
WHERE FREETEXT (*, 'anders' );
SELECT *
FROM [TestDB].[dbo].[Person]
WHERE FREETEXT (*, '1' );
I would like them to return the same result, the first returns id = 1 name = Anders, while the second query don't return anything.
edit 2
Looks like the problem is in using int, but is it not possible to trick FullText to support it?
edit 3
Created a view where I convert the int to a nvarchar. CONVERT(nvarchar(50), Id) AS PersonId this did make it possible for me to select that column, when creating the Full Text Catalog, but It still won't let me find it searching for the Id.
From reading your question, I am not sure that you understand the purpose of a full-text index. A full-text index is intended to search TEXT (one or more columns) on a table. And not just as a replacement for:
SELECT *
FROM table
WHERE col1 LIKE 'Bob''s Pizzaria%'
OR col2 LIKE 'Bob''s Pizzaria%'
OR col3 LIKE 'Bob''s Pizzaria%'
It also allows you to search for variations of "Bob's Pizzaria" like "Bobs Pizzeria" (in case someone misspells Pizzeria or forgot to put in the ' or over-zealous anti-SQL-injection code stripped the ') or "Robert's Pizza" or "Bob's Pizzeria" or "Bob's Pizza", etc. It also allows you to search "in the middle" of a text column (char, varchar, nchar, nvarchar, etc.) without the dreaded "%Bob%Pizza%" that eliminates any chance of using a traditional index.
Enough with the lecture, however. To answer your specific question, I would create a separate column (not a "computed column") "IdText varchar(10)" and then an AFTER INSERT trigger something like this:
UPDATE t
SET IdText = CAST(Id AS varchar(10))
FROM table AS t
INNER JOIN inserted i ON i.Id = t.Id
If you don't know what "inserted" is, see this MSDN article or search Stack Overflow for "trigger inserted". Then you can include the IdText column in your full-text index.
Again, from your example I am not sure that a full-text index is what you should use here but then again your actual situation might be something different and you just created this example for the question. Also, full-text indexes are relatively "expensive" so make sure you do a cost-benefit analysis. Here is a Stack Overflow question about full-text index usage.
Why not just do a query like this.
SELECT *
FROM [TestDB].[dbo].[Person]
WHERE FREETEXT (*, '1' )
OR ID = 1
You can leave off the "OR ID = 1" part if by first checking if the search term is a number.

Forcing a datatype in MS Access make table query

I have a query in MS Access which creates a table from two subqueries. For two of the columns being created, I'm dividing one column from the first subquery into a column from the second subquery.
The datatype of the first column is a double; the datatype of the second column is decimal, with scale of 2, but I want the second column to be a double as well.
Is there a way to force the datatype when creating a table through a standard make-table Access query?
One way to do it is to explicitly create the table before putting anything into it.
Your current statement is probably like this:
SELECT Persons.LastName,Orders.OrderNo
INTO Persons_Order_Backup
FROM Persons
INNER JOIN Orders
ON Persons.P_Id=Orders.P_Id
WHERE FirstName = 'Alistair'
But you can also do this:
----Create NewTable
CREATE TABLE NewTable(FirstName VARCHAR(100), LastName VARCHAR(100), Total DOUBLE)
----INSERT INTO NewTableusing SELECT
INSERT INTO NewTable(FirstName, LastName, Total)
SELECT FirstName, LastName,
FROM Person p
INNER JOIN Orders o
ON p.P_Id = o.P_Id
WHERE p.FirstName = 'Alistair'
This way you have total control over the column types. You can always drop the table later if you need to recreate it.
You can use the cast to FLOAT function CDBL() but, somewhat bizarrely, the Access Database Engine cannot handle the NULL value, so you must handle this yourself e.g.
SELECT first_column,
IIF(second_column IS NULL, NULL, CDBL(second_column))
AS second_column_as_float
INTO Table666
FROM MyTest;
...but you're going to need to ALTER TABLE to add your keys, constraints, etc. Better to simply CREATE TABLE first then use INSERT INTO..SELECT to populate it.
You can use CDbl around the columns.
An easy way to do this is to create an empty table with the correct field types and then to an Append-To query and Access will automatically convert the data to the destination field.
I had a similar situation, but I had a make-table query creating a field with NUMERIC datatype that I wanted to be short text.
What I did (and I got the idea from Stack) is to create the table with the field in question as Short Text, and at the same time build a delete query to scrub the records. I think it's funny that a DELETE query in access doesn't delete the table, just the records in it - I guess you have to use a DROP TABLE function for that, to purge a table...
Then, I converted my make-table query to an APPEND query, which I'd never done before... and I just added the running of the DELETE query to my process.
Thank you, Stack Overflow !
Steve
I add a '& ""' to the field I want to make sure are stored as text, and a ' *1 ' (as in multiplying the amount by 1) to the fields I want to store as numeric.
Seems to do the trick.
To get an Access query to create a table with three numeric output fields from input numeric fields, (it kept wanting to make the output fields text fields), had to combine several of the above suggestions. Pre-establish an empty output table with pre-defined output fields as integer, double and double. In the append query itself, multiply the numeric fields by one. It worked. Finally.

How to implement a Keyword Search in MySQL?

I am new to SQL programming.
I have a table job where the fields are id, position, category, location, salary range, description, refno.
I want to implement a keyword search from the front end. The keyword can reside in any of the fields of the above table.
This is the query I have tried but it consist of so many duplicate rows:
SELECT
a.*,
b.catname
FROM
job a,
category b
WHERE
a.catid = b.catid AND
a.jobsalrange = '15001-20000' AND
a.jobloc = 'Berkshire' AND
a.jobpos LIKE '%sales%' OR
a.jobloc LIKE '%sales%' OR
a.jobsal LIKE '%sales%' OR
a.jobref LIKE '%sales%' OR
a.jobemail LIKE '%sales%' OR
a.jobsalrange LIKE '%sales%' OR
b.catname LIKE '%sales%'
For a single keyword on VARCHAR fields you can use LIKE:
SELECT id, category, location
FROM table
WHERE
(
category LIKE '%keyword%'
OR location LIKE '%keyword%'
)
For a description you're usually better adding a full text index and doing a Full-Text Search (MyISAM only):
SELECT id, description
FROM table
WHERE MATCH (description) AGAINST('keyword1 keyword2')
SELECT
*
FROM
yourtable
WHERE
id LIKE '%keyword%'
OR position LIKE '%keyword%'
OR category LIKE '%keyword%'
OR location LIKE '%keyword%'
OR description LIKE '%keyword%'
OR refno LIKE '%keyword%';
Ideally, have a keyword table containing the fields:
Keyword
Id
Count (possibly)
with an index on Keyword. Create an insert/update/delete trigger on the other table so that, when a row is changed, every keyword is extracted and put into (or replaced in) this table.
You'll also need a table of words to not count as keywords (if, and, so, but, ...).
In this way, you'll get the best speed for queries wanting to look for the keywords and you can implement (relatively easily) more complex queries such as "contains Java and RCA1802".
"LIKE" queries will work but they won't scale as well.
Personally, I wouldn't use the LIKE string comparison on the ID field or any other numeric field. It doesn't make sense for a search for ID# "216" to return 16216, 21651, 3216087, 5321668..., and so on and so forth; likewise with salary.
Also, if you want to use prepared statements to prevent SQL injections, you would use a query string like:
SELECT * FROM job WHERE `position` LIKE CONCAT('%', ? ,'%') OR ...
I will explain the method i usally prefer:
First of all you need to take into consideration that for this method you will sacrifice memory with the aim of gaining computation speed.
Second you need to have a the right to edit the table structure.
1) Add a field (i usually call it "digest") where you store all the data from the table.
The field will look like:
"n-n1-n2-n3-n4-n5-n6-n7-n8-n9" etc.. where n is a single word
I achieve this using a regular expression thar replaces " " with "-".
This field is the result of all the table data "digested" in one sigle string.
2) Use the LIKE statement %keyword% on the digest field:
SELECT * FROM table WHERE digest LIKE %keyword%
you can even build a qUery with a little loop so you can search for multiple keywords at the same time looking like:
SELECT * FROM table WHERE
digest LIKE %keyword1% AND
digest LIKE %keyword2% AND
digest LIKE %keyword3% ...
You can find another simpler option in a thread here: Match Against.. with a more detail help in 11.9.2. Boolean Full-Text Searches
This is just in case someone need a more compact option. This will require to create an Index FULLTEXT in the table, which can be accomplish easily.
Information on how to create Indexes (MySQL): MySQL FULLTEXT Indexing and Searching
In the FULLTEXT Index you can have more than one column listed, the result would be an SQL Statement with an index named search:
SELECT *,MATCH (`column`) AGAINST('+keyword1* +keyword2* +keyword3*') as relevance FROM `documents`USE INDEX(search) WHERE MATCH (`column`) AGAINST('+keyword1* +keyword2* +keyword3*' IN BOOLEAN MODE) ORDER BY relevance;
I tried with multiple columns, with no luck. Even though multiple columns are allowed in indexes, you still need an index for each column to use with Match/Against Statement.
Depending in your criterias you can use either options.
I know this is a bit late but what I did to our application is this. Hope this will help someone tho. But it works for me:
SELECT * FROM `landmarks` WHERE `landmark_name` OR `landmark_description` OR `landmark_address` LIKE '%keyword'
OR `landmark_name` OR `landmark_description` OR `landmark_address` LIKE 'keyword%'
OR `landmark_name` OR `landmark_description` OR `landmark_address` LIKE '%keyword%'