Full Text Search Using Multiple Partial Words - sql

I have a sql server database that has medical descriptions in it. I've created a full text index on it, but I'm still figuring out how this works.
The easiest example to give is if there is a description of Hypertensive heart disease
Now they would like to be able to type hyp hea as a search term and have it return that.
So from what I've read it seems like my query needs to be something like
DECLARE #Term VARCHAR(100)
SET #Term = 'NEAR(''Hyper*'',''hea*'')'
SELECT * FROM Icd10Codes WHERE CONTAINS(Description, #Term)
If I take the wild card out for Hypertensive and heart, and type out the full words it works, but adding the wild card in returns nothing.
If it makes any difference I'm using Sql Server 2017

So it was a weird syntax issue that didn't cause an error, but stopped the search from working.
I changed it to
SELECT * FROM Icd10Codes where CONTAINS(description, '"hyper*" NEAR "hea*"')
The key here being I needed double quotes " and not to single quotes. I assumed it was two single quotes, the first to escape the second, but it was actually double quotes. The above query returns the results exactly as expected.

this will work:
SELECT * FROM Icd10Codes where SOUNDEX(description)=soundex('Hyp');
SELECT * FROM Icd10Codes where DIFFERENCE(description,'hyp hea')>=2;

You could try a like statement. You can find a thorough explanation here.
Like so:
SELECT * FROM Icd10Codes WHERE Icd10Codes LIKE '%hyp hea%';
And then instead of putting the String in there just use a variable.
If you need to search for separated partial words, as in an array of search terms, it gets a bit tricky, since you need to dynamically build the SQL statement.
MSSQL provides a few features for full text search. You can find those here. One of them is the CONTAINS keyword:
SELECT column FROM table WHERE CONTAINS (column , 'string1 string2 string3');

For me - this had more mileage.
create a calculated row with fields as full text search.
fullname / company / lastname all searchable.
ALTER TABLE profiles ADD COLUMN fts tsvector generated always as (to_tsvector('english', coalesce(profiles.company, '') || ' ' || coalesce(profiles.broker, '') || ' ' || coalesce(profiles.firstname, '') || ' ' || coalesce(profiles.lastname, '') || ' ' )) stored;
let { data, error } = await supabase.from('profiles')
.select()
.textSearch('fts',str)

Related

how to query some characters in one field?

My database is Oracle 11g.
I want to do a in query in sql. The query criteria is to matched some of the characters of a field:
description
CWLV321900017391;EFHU3832239
CWLV321900017491;ERHU3832239
CWLV321900017591;ERHU3832239
CWLV321900017691;ERHU3832239
My query is like this:
select * from product where description in ('CWLV321900017391', 'CWLV321900017491');
It returns no records in result.
I expect the result like below:
description
CWLV321900017391;EFHU3832239
CWLV321900017491;ERHU3832239
How to get it by SQL?
thanks.
You are using IN to search for a partial string match in the description table. This is not going to return the results, as IN will only match exact values.
Instead, one way to achieve this is to use a LIKE operator with %:
select *
from product
where (description LIKE 'CWLV321900017391%' OR
description LIKE 'CWLV321900017491%');
The % at the end indicates that anything can follow after the specified text.
This will return any description that starts with CWLV321900017391 or CWLV321900017491.
Incidentally, if your search term occurs anywhere in the description field, you will need to use a % at each end of the search term:
description LIKE '%CWLV321900017391%' OR description LIKE '%CWLV321900017491%'
There are various ways to solve it. Here is one:
select * from product
where instr (description, 'CWLV321900017391') > 0
or instr (description, 'CWLV321900017491') > 0;
If you know you're always searching for the start of the description you can use:
select * from product
where substr (description, 1, 16) in ('CWLV321900017391','CWLV321900017491')
Also, there's LIKE or REGEX_LIKE solution. It depends really on what strings you're searching for.
Of course none of these solutions is truly satisfactory, and for large volumes of data may exhibit suck-y performance. The problem is the starting data model violates First Normal Form by storing non-atomic values. Poor data models engender clunky SQL.
You can try below way -
select * from product
where substr(description,1,instr(description,';',1,1)-1) in ('CWLV321900017391', 'CWLV321900017491')
I am opposed to storing multiple values in a delimited string format. There are many better alternatives, but let me assume that you don't have a choice on the data model.
If you are stuck with strings in this format, you should take the delimiters into account. You can do this using like:
where ';' || description || ';' like '%;CWLV321900017391;%'
You can also do something similar with regexp_like() if you want to look for one of several values:
where regexp_like(';' || description || ';',
'(;CWLV321900017391;)|(;CWLV321900017391;)'
)

SQL LIKE Statement with Spaces

Spaces in my phone numbers are causing issues when I am trying to search.
Select * from customers where number LIKE '%02722231%'
This will return records that're LIKE '02722231', but this will not return any records that contain a space e.g. '027 22231'
Can this be done with regular expressions? I need to search 0272542155 and get all records the same including 027 2542155
Try this:
Select * from customers where REPLACE(number, ' ', '') LIKE '%02722231%'

SQL query for records that are substrings of input

Consider a users table that has a column called name which has the following three rows.
Alice
Bob
Carl
I would like to construct a query that returns records in which the name is a substring of the input. For example, if I query for Alice Jackson, I want Alice. If I search for Bobby, I want Bob. But if I search for Car, I want no matches. Sort of a reversed LIKE.
Can this be done? And can it be done using ActiveRecord syntax?
You could do something like (SQL Server syntax):
SELECT name
FROM users
WHERE 'your query' + ' ' LIKE name + ' %';
The following will find Alice:
SELECT name
FROM users
WHERE 'Alice Jackson' + ' ' LIKE name + ' %';
SELECT name
FROM users
WHERE 'Alice' + ' ' LIKE name + ' %';
The following will not find Alice:
SELECT name
FROM users
WHERE 'Ali' + ' ' LIKE name + ' %';
I figured out the syntax for SQLite to do this.
User.where("? LIKE name || '%'", query)
The double pipes are apparently neccesary for concatenation in SQLite. However, as plalx illustrates, different SQL servers speak different dialects, which makes my application database dependent with this query. Since the final query will contain additional clauses limiting the potential subset for this inverse LIKE to less than 10 records in most cases, I will be pulling those records and performing the matching at application level instead.
Using ActiveRecord IN expression:
Client.where(:name => query.split(" "))
This code will generate SQL like this:
SELECT * FROM clients WHERE (clients.name IN ['Alice', 'Jackson']);

Dictionary-like search using SQL Server FULL-TEXT

I am trying to create a dictionary for my website.
Searching for 'server' using FREETEXTTable & Rank DESC returns:
name server - A program or server that maps human-readable names..
server - One who serves; a waitress or waiter.
server - A tray for dishes; a salver.
4...
'server' is obviously closer to 'server' than 'name server'. How do I fix the ranking?
I can not just reverse to ASC because there are even worse matches.
Top 3 results for 'God' are 'act of God', 'Lamb of God', 'Le God'..
Edit: Sorry for any confusion. nameserver, server, server.. are in a single column called 'word' this is the column that is queried with full-text search. The definitions are in the next column 'definition' and returned as query results.
I think you can use union to solve the problem of your result ordering problem ..
like
select * from your_table_name where col_name = 'server'
union
select * from your_table_name where col_name like '%server%' order by col1,col2..
this query should give you first row with full text search and then with partial search ..
clarification ..
please note that by col_name i meant to say about the column name what you have for your words..
say your table structure is ..
dictionary-
( c_word ,
c_definition,
c_synonyms
)
then you have to modify my query as
select * from Dictionary where c_word = 'server'
union
select * from Dictionary where c_word like '%server%' order by c_definition,c_synonyms
so that this query will show first where c_word value exactly match the word 'server' followed by the partial search..
for dynamic query-- you need to replace 'server' with the variable where you are getting requested keyword for search .
I used the PATINDEX function to do this at one point. Something like the following:
SELECT
Word,
Definition
FROM
FREETEXTTABLE(Dictionary, Word, #search, 20) AS Matches
INNER JOIN Dictionary ON
Matches.Key = Dictionary.ID
ORDER BY
CASE PATINDEX('%' + #search + '%', Word)
WHEN -1 THEN 1000
ELSE PATINDEX('%' + #search + '%', Word)
END
It doesn't perform too terribly since you're using the full text index to get a smaller result set (max 20 as well, in this case). PATINDEX finds a string within an expression. If the search string doesn't exist within the expression, it returns -1. This might occur if you're also searching definitions, if your search matches on a synonym or stemmed word (eg: you search for "took" so "take" is returned), or if your search involves multiple words. The CASE statement sorts those results to the end.

How to replace common words in sql column

I have a table of common words that are used in sentences (i.e. A, the, and, where, etc...)
What I want to do is loop through all those words and strip them out of the descriptions that people have entered to attempt to generate common keywords or tags. But I can't use replace because replace will remove any instance of the common word regardless of whether it is only a couple of letters that make up a larger word. For instance:
I want to replace A in the description. Now obviously a lot of words contain the letter a. So all those A's will be stripped from the words. I don't want that. I only want it when A is used a a whole word. I can figure this out using regular expressions but was wondering if there was anyway to do this in SQL without having to resort to CLR proc.
Maybe I am missing something but I couldn't seem to find an easy way to do this without having to write some specific scenarios like: word plus space before, word plus space after, word plus period after, etc... I don't think that is the best way.
For quick and dirty, I used to slosh through the various SQL functions PATINDEX, LEFT, RIGHT and LIKE to do this sort of thing. For one-time data prep, I export to something like Excel and eyeball it.
A good approach also is to create a new StringSubstitutionTable with two columns SOURCESTRING and TARGETSTRING and run a replace function to replace the SOURCESTRING with the TARGETSTRING on the joined table. This is cool because you can just add substitution entries as needed.
You can try nesting the replaces for each word you would like to replace. For example:
UPDATE TableName
SET ColumnName = REPLACE(REPLACE(REPLACE(REPLACE(TableName.ColumnName,' a ',' '),' the ',' '),' and ',' '), ' ', ' ')
Let me know if this is what you were looking for.
Here is they way I did something similar to what you are trying to do.
During your replace action...
Append a space before and after the common word.
Append a space before and after the description.
Let's suppose you want to remove the CommonWord "A" from the Description.
Description: "A good phrase never starts with A or ends with A"
CommonWord: "A"
Update TableName
Set Description =
LTRIM(RTRIM(Replace(' ' + Description + ' ', ' ' + CommonWord + ' ', ' ')))
This lets you delete all whole words that equal 'A'. Because you are replacing ' A ' with a space you need to LTRIM RTRIM to remove any leading or trailing spaces.
You could also do this in two steps:
--
-- Step 1 Loop through all common words removing them
--
Update TableName
Set Description = Replace(' ' + Description + ' ', ' ' + CommonWord + ' ', ' ')
--
-- Step 2 Unconditionally Trim all Descriptions
--
Update TableName
Set Description = LTRIM(RTIM(Description))