Sql Full Text keyword search - contains or not contains - sql

Hi i was asked to upgrade our website s keyword search section. It needs to be like in the picture.
The user can select from two different options from select box and it refers to my full text indexed column. Then he/she enter a pharese or word and says add. It goes to "contains box" and it means that search result needs to contains that word. If the user drags it to the other box search results shouldnt contains that word/s.
I did it some way. But im concerned about the performance. These searches occurs in every 15 seconds in average and the table has ~30 million records.
This is what i did:
INNER JOIN CONTAINSTABLE (FullTextDB,column1,'"software developer*"') ka on a.refnumber = ka.[key]
left JOIN CONTAINSTABLE (FullTextDB,column1,'"mvc*" ') ri on a.refnumber = ri.[key]
INNER JOIN CONTAINSTABLE (FullTextDB,column2,'"php*" ') yer on a.refnumber = yer.[key]
WHERE ri.[key] is null
It brings correct results but how can i improve this. I used left join to exclude. Any ideas?
Thank you.

Grouping your search keywords will provide improved performance
example
"(A OR B) AND NOT (C)"

Related

Convert Xpath to SQL

Previously we were fetching a number of countries from a table. Now the table changed to support multiple languages inside the text cell. The previous SQL statement was:
select b.text, a.iso_num, a.iso2, a.iso3, a.kfz, a.ind_member
from schema.zl_countrycode a, schema.zl_countrycode_lsd b
where a.ind_land = 1 and a.kfz is not NULL and dat_end = to_date('99991231','YYYYMMDD') and a.ZL_COUNTRYCODE_id = b.ZL_COUNTRYCODE_LSD_ID order by text
The list previously outputted each country in a row.
With the addition of the language selection, the list suddenly doubled in size - because it lists every county in two different languages.
This is how the table looks with the GUI
I'm trying to figure out, how to expend the statement to only select each "DE:" value in the text column. After having a quick indirect discussion with the developers, they provided me this XPATH statement:
Parentofparent/Parent/Valuestable[name="ZL_COUNTRYCODE"]/Valueclassification[name="TEXT"]/Value/ValueLng[lng="DE"]
I don't know the first thing about XPATH and no matter what I have tried so far, it failed.
Please help me out if you're knowledgeable in this field. It's probably an Oracle database, as I have experienced a plethora of Oracle error codes in the last few days.
I think this should do the trick:
SELECT b.TEXT
,a.iso_num
,a.iso2
,a.iso3
,a.kfz
,a.ind_member
,a.de
FROM SCHEMA.zl_countrycode a
JOIN SCHEMA.zl_countrycode_lsd b
ON a.ZL_COUNTRYCODE_id = b.ZL_COUNTRYCODE_LSD_ID AND b.spec_lng = 'DE'
WHERE a.ind_land = 1
AND a.kfz IS NOT NULL
AND dat_end = to_date('99991231', 'YYYYMMDD')
ORDER BY TEXT

SQL like with two wildcards anywhere in text

Is there a way to create a where statement using like with two words (or more) but they are not in the same order as the words given?
select
i.ITEM_NUMBER as Item,
min(i.ITEM_DESCRIPTION) as Description,
i.ORGANIZATION_CODE as Org,
max(m.MANUFACTURER_NAME) as Manufacturer,
max(m.MANUFACTURERS_PARTNUMBER) as Partnumber
from mis.XXEAM_INVENTORY_REPORT_WITH_LOCATORS_CONSIGNED_MATERIAL_AND_CATEGORIES_TBL i
left outer join
mis.XXEAM_MANUFACTURING_PART_NUMBERS_TBL m on i.ITEM_NUMBER = m.ITEM_NUMBER
where
i.ITEM_DESCRIPTION like '%ALLEN BRADLEY%PLC%'
group by i.ORGANIZATION_CODE, i.ITEM_NUMBER
I would like to search the description text above as the '%ALLEN BRADLEY%PLC%' or '%PLC%ALLEN BRADLEY%'. I would like to avoid using OR statements because the dataset is huge and the query can take a long time.
The wildcards can be more than two, I just took those two as an example. In my mind I would for instance prefer to fetch the dataset for the first word and then fetch from that dataset the second word. Perhaps the only way is to select into temp-table.
You can do two LIKE for 'ALLEN BRADLEY' and 'PLC'. It should work for what you want:
SELECT
i.ITEM_NUMBER AS Item
,MIN(i.ITEM_DESCRIPTION) AS Description
,i.ORGANIZATION_CODE AS Org
,MAX(m.MANUFACTURER_NAME) AS Manufacturer
,MAX(m.MANUFACTURERS_PARTNUMBER) AS Partnumber
FROM mis.XXEAM_INVENTORY_REPORT_WITH_LOCATORS_CONSIGNED_MATERIAL_AND_CATEGORIES_TBL i
LEFT OUTER JOIN mis.XXEAM_MANUFACTURING_PART_NUMBERS_TBL m
ON i.ITEM_NUMBER = m.ITEM_NUMBER
WHERE i.ITEM_DESCRIPTION LIKE '%ALLEN BRADLEY%'
and i.ITEM_DESCRIPTION LIKE '%PLC%'
GROUP BY i.ORGANIZATION_CODE
,i.ITEM_NUMBER
you can use:
PATINDEX ('((.*)[ALLEN BRADLEY](.*)[PLC](.*))|('(.*)[PLC](.*)[ALLEN BRADLEY](.*)'),
i.ITEM_DESCRIPTION);
Depending on your need for a performatic, powerful query, it makes sense to create a full-text index on the column. It will benefit your query by using the index and also give you the flexibility when including new items to the condition. If the query is small, the LIKE will be enough, but for long tables where time is a problem, create a full-text index.
WHERE CONTAINS (i.ITEM_DESCRIPTION,"'ALLEN BRADLEY' OR 'PLC' OR 'any other item searched'");

SQL query to find records with specific prefix

I'm writing SQL queries and getting tripped up by wanting to solve everything with loops instead of set operations. For example, here's two tables (lists, really - one column each); idPrefix is a subset of idFull. I want to select every full ID that has a prefix I'm interested in; that is, every row in idFull which has a corresponding entry in idPrefix.
idPrefix.ID idFull.ID
---------- ----------
12 8
15 12
300 12-1-1
12-1-2
15
15-1
300
Desired result would be everything in idFull except the value 8. Super-easy with a for each loop, but I'm just not conceptualizing it as a set operation. I've tried a few variations on the below; everything seems to return all of one table. I'm not sure if my issue is with how I'm doing joins, or how I'm using LIKE.
SELECT f.ID
FROM idPrefix AS p
JOIN idFull AS f
ON f.ID LIKE (p.ID + '%')
Details:
Values are varchars, prefixes can be any length but do not contain the delimiter '-'.
This question seems similar, but more complex; this one only uses one table.
Answer doesn't need to be fast/optimized/whatever.
Using SQL Server 2008, but am more interested in conceptual understanding than a flavor-specific query.
Aaaaand I'm coming back to both real coding & SO after ~3 years, so sorry if I'm rusty on any etiquette.
Thanks!
You can join the full table to the prefix table with a LIKE
SELECT idFull.ID
FROM idFull full
INNER JOIN idPrefix pre ON full.ID LIKE pre.ID + '%'

SQL - How to "flatten" several very similar rows into 1

Apologies if the title isn't clear - I just didn't know how to describe the issue and I really don't know SQL that well/at all.
I am working with a database used by our case management system. At places it has clearly been extended over time by the developers. I am working with Contact details (names, addresses, etc...) and they have added extra fields to deal with email addresses and to allow for home/work/mobile phone numbers etc...
The problem is that they haven't added a new field for each individual new field. They have instead added a couple of fields in 2 different tables - the first field includes the field name, the second then includes the actual data.
The first is called AddElTypeText in a table called AdditionalAddElTypes - The AddElTypeText field includes values like "Work Telephone 1", "Fax", "Home Email" etc... (There are a total of 10 different values and I can't see the developers expanding this number any time soon)
The second field is called AddElementText in a table called AdditionalAddressElements - the AddElementText then includes the actual data e.g. the phone number, email address.
For those of you who (unlike me) find it easier to look at the SQL code, it's:
SELECT
Address.AddressLine1
,AdditionalAddElTypes.AddElTypeText
,AdditionalAddressElements.AddElementText
FROM
Address
INNER JOIN AdditionalAddressElements
ON Address.AddressID = AdditionalAddressElements.AddressID
INNER JOIN AdditionalAddElTypes
ON AdditionalAddressElements.AddElTypeID = AdditionalAddElTypes.AddElTypeID
I can work with this, but if any contact has 2 or more "additional" elements, I get multiple rows, with most of the data being the same, but just the 2 columns of AddElTypeText and AddElementText being different.
So can anyone suggest anything to "flatten" a contact into a single row. I had in mind something like concatenating AddElTypeText and AddElementText into a single string field, ideally with a space in between AddElTypeText and AddElementText, and then a : or , separating the pairs of AddElTypeText and AddElementText.
However, I have very little idea how to achieve that, or whether an entirely different approach would be better. Any help very gratefully received!
Gary
As #twn08 said, this type of question has generally been asked before. It's generally a pain to do this kind of grouping concatenation in SQL Server, involving the use of FOR XML.
That being said, here's a SQLFiddle that (I believe) does something like what you wanted. And here's the actual query:
WITH Results AS
(
SELECT a.*,
t.AddElTypeText,
aa.AddElementText
FROM
Address a
INNER JOIN
AdditionalAddressElements aa
ON a.AddressID = aa.AddressID
INNER JOIN
AdditionalAddElTypes t
ON aa.AddElTypeID = t.AddElTypeID
)
SELECT
res.AddressID,
STUFF((
SELECT ', ' + AddElTypeText + ': ' + AddElementText
FROM Results
WHERE (AddressID = res.AddressID)
FOR XML PATH (''))
,1,2,'') AS AdditionalElements
FROM Results res
GROUP BY res.AddressID

Is there away in SQL Server to sort by the number of matched words in a contains function on a full text index

I have a table in a database that has a description of an item. I want to be able to have the user type a search term and return the rows that had at least one match, sorted by the number of matches they had, descending.
I don't know if this is possible, I haven't been able to find an answer googling so I'm coming here.
Basically if the user enters "truck blue with gold two tone", this will be generated:
SELECT * FROM MyItemsTable
WHERE contains(Description, 'truck or blue or with or gold or two or tone')
and have that return sorted by the number of words that matched.
Any advice would be greatly appreciated. This table will become very large in time so efficiency is also in the back of my mind as well.
This seems to have worked very well, thanks very much to Gordon Linoff.
SELECT * FROM MyItemsTable m
INNER JOIN
CONTAINSTABLE(MyItemsTable, Description, 'truck or blue or with or gold or two or tone') AS l ON m.MyItemsTable=l.[KEY]
Reference
In case you have a record like "truck blue with gold two tone". You can use below query.
SELECT * FROM
MyItemsTable as t
JOIN CONTAINSTABLE(MyItemsTable , Description,'"truck"') fulltextSearch
ON
t.[Id] = fulltextSearch.[KEY]
This will also bring this record.