Why is "or not" and "not" not allowed in Contains (tsql)? - tsql

I have searched if there is a reason why tsql contains wouldnt allow "or not" or "not" as unary operator.
On the microsoft site it just says "OR NOT operator is not allowed"
CONTAINS (Transact-SQL)
I can simply put the unary not in outside of contains to be able to do that right?
SELECT * FROM Person
WHERE NOT CONTAINS(*, 'Steve')
and the same with "or not"
SELECT * FROM Person
WHERE CONTAINS(FirstName, 'Peter') OR NOT CONTAINS(LastName, 'Smith')
Is it problematic to do queries as in the two examples?
Thanks for your helpManuel

Your examples should work.
An expression like CONTAINS( Description, 'NOT "Mountain" ') is probably not allowed because it is equivalent (we can rewrite it) to NOT CONTAINS( Description, 'Mountain').
Similarly, an expression like CONTAINS( Description, '"River" OR NOT "Mountain" ') is equivalent to CONTAINS( Description, 'River') OR NOT CONTAINS( Description, 'Mountain').

Do you have some specific reason to do Full Text search in your situation?
In your example you might want simplify query to the following:
SELECT * FROM Person
WHERE FirstName LIKE '%Peter%' OR LastName NOT LIKE '%Smith%'
If you need to use Full Text search, you could change query to something like this:
SELECT * FROM Person
WHERE CONTAINS(FirstName, 'Peter')
EXCEPT
SELECT * FROM Person
WHERE CONTAINS(LastName, 'Smith')

Related

POSTGRESQL Dollar Quotes in Where Clause

For people who tried or needed a solution to escape every special character (even $) in a WHERE CLAUSE in POSTGRESQL, here is how it should be use
the documentation can be somehow hard to understand, and there is no proper example of it so here is mine
e.g : if you want to make a request looking as
SELECT
*
FROM
<TableName>
WHERE
<ColumnName> = 'string with ' character';
it will throw an error cause "character'" is outside the string
So here is how it should be written:
SELECT
*
FROM
<TableName>
WHERE
<ColumnName> = $$string with ' character$$;
The WHERE CONDITION will take the string literally; the interface may look broken but the following instruction will still be interpreted as expected.
SELECT
*
FROM
<TableName>
WHERE
<ColumnName> = $$string with ' character$$ AND <OtherColumnName> IS NOT NULL;
This could even be another escaped string with $$.
For details about dollar quoting, look at the documentation.

Prefix/wildcard searches with 'websearch_to_tsquery' in PostgreSQL Full Text Search?

I'm currently using the websearch_to_tsquery function for full text search in PostgreSQL. It all works well except for the fact that I no longer seem to be able to do partial matches.
SELECT ts_headline('english', q.\"Content\", websearch_to_tsquery('english', {request.Text}), 'MaxFragments=3,MaxWords=25,MinWords=2') Highlight, *
FROM (
SELECT ts_rank_cd(f.\"SearchVector\", websearch_to_tsquery('english', {request.Text})) AS Rank, *
FROM public.\"FileExtracts\" f, websearch_to_tsquery('english', {request.Text}) as tsq
WHERE f.\"SearchVector\" ## tsq
ORDER BY rank DESC
) q
Searches for customer work but cust* and cust:* do not.
I've had a look through the documentation and a number of articles but I can't find a lot of info on it. I haven't worked with it before so hopefully it's just something simple that I'm doing wrong?
You can't do this with websearch_to_tsquery but you can do it with to_tsquery (because ts_query allows to add a :* wildcard) and add the websearch syntax yourself in in your backend.
For example in a node.js environment you could do smth. like this:
let trimmedSearch = req.query.search.trim()
let searchArray = trimmedSearch.split(/\s+/) //split on every whitespace and remove whitespace
let searchWithStar = searchArray.join(' & ' ) + ':*' //join word back together adds AND sign in between an star on last word
let escapedSearch = yourEscapeFunction(searchWithStar)
and than use it in your SQL
search_column ## to_tsquery('english', ${escapedSearch})
You need to write the tsquery directly if you want to use partial matching. plainto_tsquery doesn't pass through partial match notation either, so what were you doing before you switched to websearch_to_tsquery?
Anything that applies a stemmer is going to have hard time handling partial match. What is it supposed to do, take off the notation, stem the part, then add it back on again? Not do stemming on the whole string? Not do stemming on just the token containing the partial match indicator? And how would it even know partial match was intended, rather than just being another piece of punctuation?
To add something on top of the other good answers here, you can also compose your query with both websearch_to_tsquery and to_tsquery to have everything from both worlds:
select * from your_table where ts_vector_col ## to_tsquery('simple', websearch_to_tsquery('simple', 'partial query')::text || ':*')
Another solution I have come up with is to do the text transform as part of the query so building the tsquery looks like this
to_tsquery(concat(regexp_replace(trim(' all the search terms here '), '\W+', ':* & '), ':*'));
(trim) Removes leading/trailing whitespace
(regexp_replace) Splits the search string on non word chars and adds trailing wildcards to each term, then ANDs the terms (:* & )
(concat) Adds a trailing wildcard to the final term
(to_tsquery) Converts to a ts_query
You can test the string manipulation by running
SELECT concat(regexp_replace(trim(' all the search terms here '), '\W+', ':* & ', 'gm'), ':*')
the result should be
all:* & the:* & search:* & terms:* & here:*
So you have multi word partial matches e.g. searching spi ma would return results matching spider man

Combining rows from multiple sources in Virtual list Filemaker

I am trying to make an Excel-like 'pivot table' in Filemaker using a Virtual List as the source of the data. The issue is I want to be able to have 'categories' down the first column that aren't fixed. The field names won't work.
My current thought is to have a table with a field of the layout name and the categories, that I would combine with the rest of the data via a ExecuteSQL (or other function).
I can get it to work with two ExecuteSQL statements, one for the categories and one for the 'bulk' of the data, using text for the WHERE in the categories eSQL, then I combine them into one and I'm set.
My issue is that I'd like to be able to get the categories using a get(LayoutName) function, making the script more flexible. Whenever I use the get(LayoutName) in the WHERE line of the SQL I get a ? for the result. I have also tried putting the layout name in a field using a get(LayoutName), then using that field as in the WHERE statement, but that also returns an error.
I admit I am a bit of a newbie at this, so the problem is likely between the keyboard and the chair with a simple syntax error. I have tried a bunch of different ways with quotes, no quotes, single quotes, etc.
Here is what I am using for pulling the categories...
Substitute ( ExecuteSQL ( "SELECT Category_List
FROM Categories_VL
WHERE Layout_Name = Get(LayoutName)" ; "" ; "") ; ", " ; $$delim )
All of the field names are correct, and if I change the LayoutName to a text that matches the Layout_Name field I want, it works fine.
I apologize if I have been too wordy, but I figure more info is better than answering a bunch of questions because I forgot something!
TIA!
I am struggling to understand your question. I hope I am addressing the correct issue.
You cannot use Filemaker functions inside an SQL query. To find records where the Layout_Name field is equal to the current layout's name, your query should be:
SELECT Category_List
FROM Categories_VL
WHERE Layout_Name = ?
and then you would supply the current layout's name as an argument:
ExecuteSQL ( "SELECT Category_List FROM Categories_VL WHERE Layout_Name = ?" ; "" ; "" ; Get ( LayoutName ) )
Note that instead of substituting the default delimiter, you can specify your own field and row separators within the ExecuteSQL() function itself, for example:
ExecuteSQL ( "SELECT Category_List FROM Categories_VL WHERE Layout_Name = ?" ; $$delim ; "" ; Get ( LayoutName ) )
See: https://help.claris.com/en/pro-help/#page/FMP_Help%2Fexecutesql.html%23

postgres full text search like operator

what is the query to use to search for text that matches the like operator.
I am asking about full text search query, which is of the form
SELECT * FROM eventlogging WHERE description_tsv ## plainto_tsquery('mess');
I want results with "message" as well but right not it does not return anything
If I read the description in the manual correctly, you'll need to use to_tsquery() instead of plainto_tsquery together with a wildcard to allow prefix matching:
SELECT *
FROM eventlogging
WHERE description_tsv ## to_tsquery('mess:*');
You can use LIKE for exact case matches or ILIKE for case insensitive. Use the % as your wildcard.
This will match anything with 'SomeThing' in it (case sensitive).
SELECT * FROM table WHERE name LIKE '%SomeThing%'
This will match anything ending with "ing" (case insensitive).
SELECT * FROM table WHERE name ILIKE '%ing'

Use multiple words in FullText Search input string

I have basic stored procedure that performs a full text search against 3 columns in a table by passing in a #Keyword parameter. It works fine with one word but falls over when I try pass in more than one word. I'm not sure why. The error says:
Syntax error near 'search item' in the full-text search condition 'this is a search item'
SELECT S.[SeriesID],
S.[Name] as 'SeriesName',
P.[PackageID],
P.[Name]
FROM [Series] S
INNER JOIN [PackageSeries] PS ON S.[SeriesID] = PS.[PackageID]
INNER JOIN [Package] P ON PS.[PackageID] = P.[PackageID]
WHERE CONTAINS ((S.[Name],S.[Description], S.[Keywords]),#Keywords)
AND (S.[IsActive] = 1) AND (P.[IsActive] = 1)
ORDER BY [Name] ASC
You will have to do some pre-processing on your #Keyword parameter before passing it into the SQL statement. SQL expects that keyword searches will be separated by boolean logic or surrounded in quotes. So, if you are searching for the phrase, it will have to be in quotes:
SET #Keyword = '"this is a search item"'
If you want to search for all the words then you'll need something like
SET #Keyword = '"this" AND "is" AND "a" AND "search" AND "item"'
For more information, see the T-SQL CONTAINS syntax, looking in particular at the Examples section.
As an additional note, be sure to replace the double-quote character (with a space) so you don't mess up your full-text query. See this question for details on how to do that: SQL Server Full Text Search Escape Characters?
Further to Aaron's answer, provided you are using SQL Server 2016 or greater (130), you could use the in-built string fuctions to pre-process your input string. E.g.
SELECT
#QueryString = ISNULL(STRING_AGG('"' + value + '*"', ' AND '), '""')
FROM
STRING_SPLIT(#Keywords, ' ');
Which will produce a query string you can pass to CONTAINS or FREETEXT that looks like this:
'"this*" AND "is*" AND "a*" AND "search*" AND "item*"'
or, when #Keywords is null:
""