I would like to know if there is a way to get the words that were matched from a full-text search using FREETEXT.
For example:
SELECT *
FROM table
WHERE FREETEXT(column_name, 'search term')
I'd like to be able to see which parts of the text in column_name triggered a match with 'search term' since FREETEXT returns records where the searched column are more than just the search term pattern matches as stated here in the FREETEXT/FREETEXTTABLE section.
I know that using FREETEXTTABLE can return the rank and key but I need to know which actual terms triggered a match if it is possible.
Thanks
Disclaimer, I haven't done this -- I'm going from documentation. I'm not sure this gets you what you want, but you can see how the search is tokenized:
from here
After you apply a given word breaker, thesaurus, and stoplist
combination in a query, you can see how Full-Text Search tokenizes the
results by using the sys.dm_fts_parser dynamic management view. For
more information, see sys.dm_fts_parser (Transact-SQL).
I'm guessing if you want to know which part (token) caused the match -- you'll likely need to run the search on the individual tokens and compare the result sets to see which token or tokens (search term/s) caused the given match.
You could try LIKE
SELECT *
FROM table
WHERE column_name like ('%search term%')
You will need Split String function
Then you will to create one Temporary table which is permanent.
Like in my example StagingFreeText (define data type as per requirement)
create table StagingFreeText (col varchar(100) not null)
Then create Full Text Index on StagingFreeText
In the start of script always truncate table
Truncate table StagingFreeText
Then insert the result into StagingFreeText
;with CTE as
(
SELECT *
FROM table
WHERE FREETEXT(column_name, 'search term')
)
insert into StagingFreeText(col)
SELECT value
FROM CTE
cross apply(select value from dbo.split_string(column_name,' '))ca
Again apply search condition like above
SELECT *
FROM StagingFreeText
WHERE FREETEXT(col, 'search term')
Note : My script is not tested but idea is very much clear.
Or if you don't want to Create another Free Text index on StagingFreeText then you can split the Search Term in #temp table and join StagingFreeText with #temp table
If you want to full text search another way then use plenty of method few are written below
Select * from Table
Where Column_Name Contains('some thing')
Select * from Table
Where Column_Name exists ('some thing')
Select * from Table
Where Column_Name in ('some thing')
Select * from Table
Where Column_Name =(some) ('some thing')
Related
Can someone help me to optimize the code? I have other way to optimize it by using compute column but we can not change the schema on prod as we are not sure how many API's are used to push data into this table. This table has millions of rows and adding a non-clustered index is not helping due to the query cost and it's going for a scan.
create table testcts(
name varchar(100)
)
go
insert into testcts(
name
)
select 'VK.cts.com'
union
select 'GK.ms.com'
go
DECLARE #list varchar(100) = 'VK,GK'
select * from testcts where replace(replace(name,'.cts.com',''),'.ms.com','') in (select value from string_split(#list,','))
drop table testcts
One possibility might be to strip off the .cts.com and .ms.com subdomain/domain endings before you insert or store the name data in your table. Then, use the following query instead:
SELECT *
FROM testcts
WHERE name IN (SELECT value FROM STRING_SPLIT(#list, ','));
Now SQL Server should be able to use an index on the name column.
If your values are always suffixed by cts.com or ms.com you could add that to the search pattern:
SELECT {YourColumns} --Don't use *
FROM dbo.testcts t
JOIN (SELECT CONCAT(SS.[value], V.Suffix) AS [value]
FROM STRING_SPLIT(#list, ',') SS
CROSS APPLY (VALUES ('.cts.com'),
('.ms.com')) V (Suffix) ) L ON t.[name] = L.[value];
I have a table of all employees (employees_all) and then created a new table (employees_new) with the same structure that I would like to append to the original table to include new employees.
I was looking for the right command to use and found that INSERT lets me add data as in the following example:
create table t1 (v varchar);
insert into t1 (v) values
('three'),
('four');
But how do I append data coming from another table and without specifying the fields (both tables have the same structure and hundreds of columns)?
With additional research, I found this specific way to insert data from another table:
insert into employees_all
select * from employees_new;
This script lets you append all rows from a table into another one without specifying the fields.
Hope it helps!
Your insert with a select statement is the most simple answer, but just for fun, here's some extra options that provide some different flexibility.
You can generate the desired results in a select query using
SELECT * FROM employees_all
UNION ALL
SELECT * FROM employees_new;
This allows you to have a few more options with how you use this data downstream.
--use a view to preview the results without impacting the table
CREATE VIEW employees_all_preview
AS
SELECT * FROM employees_all
UNION ALL
SELECT * FROM employees_new;
--recreate the table using a sort,
-- generally not super common, but could help with clustering in some cases when the table
-- is very large and isn't updated very frequently.
INSERT OVERWRITE INTO employees_all
SELECT * FROM (
SELECT * FROM employees_all
UNION ALL
SELECT * FROM employees_new
) e ORDER BY name;
Lastly, you can also do a merge to give you some extra options. In this example, if your new table might have records that already match an existing record then instead of inserting them and creating duplicates, you can run an update for those records
MERGE INTO employees_all a
USING employees_new n ON a.employee_id = n.employee_id
WHEN MATCHED THEN UPDATE SET attrib1 = n.attrib1, attrib2 = n.attrib2
WHEN NOT MATCHED THEN INSERT (employee_id, name, attrib1, attrib2)
VALUES (n.employee_id, n.name, n.attrib1, n.attrib2)
I'm using SQL Server 2017 and my collation is SQL_LATIN1_GENERAL_CP1_CI_AS and ANSI_PADDING is default value (ON).
In my table, one of the columns is of type NVARCHAR(255) and one of the values is inserted like this (including space):
N'abc '
And when I search it without space (N'abc'), I don't want to get N'abc ', but it finds it.
I know I can remove spaces during inserting record, but can't change already inserted records.
How can I prevent to find it with querying like this?
CREATE TABLE #tmp (c1 nvarchar(255))
INSERT INTO #tmp
VALUES (N'abc ')
SELECT *
FROM #tmp
WHERE c1 = N'abc'
DROP TABLE #tmp
I also found this article but want to prevent while when I querying it.
Why the SQL Server ignore the empty space at the end automatically?
I'm using Linq-to-entities with C#, and with SQL query, I can search with 'LIKE' keyword without percent character
SELECT *
FROM #tmp
WHERE c1 LIKE N'abc'
But with Linq, I don't know how to write this query:
entity.Temp.Where(p => p.c1 == "abc");
entity.Temp.Where(p => p.c1.Equals("abc"));
entity.Temp.Where(p => p.c1.Contains("abc"));
You can try:
SELECT * FROM #tmp WHERE cast(c1 as varbinary(510)) = cast(N'abc' as varbinary(510))
This would be very slow if you have a lot of rows, but it works.
I have a big query to get multiple rows by id's like
SELECT *
FROM TABLE
WHERE Id in (1001..10000)
This query runs very slow and it ends up with timeout exception.
Temp fix for it is querying with limit, break this query into 10 parts per 1000 id's.
I heard that using temp tables may help in this case but also looks like ms sql server automatically doing it underneath.
What is the best way to handle problems like this?
You could write the query as follows using a temporary table:
CREATE TABLE #ids(Id INT NOT NULL PRIMARY KEY);
INSERT INTO #ids(Id) VALUES (1001),(1002),/*add your individual Ids here*/,(10000);
SELECT
t.*
FROM
[Table] AS t
INNER JOIN #ids AS ids ON
ids.Id=t.Id;
DROP TABLE #ids;
My guess is that it will probably run faster than your original query. Lookup can be done directly using an index (if it exists on the [Table].Id column).
Your original query translates to
SELECT *
FROM [TABLE]
WHERE Id=1000 OR Id=1001 OR /*...*/ OR Id=10000;
This would require evalutation of the expression Id=1000 OR Id=1001 OR /*...*/ OR Id=10000 for every row in [Table] which probably takes longer than with a temporary table. The example with a temporary table takes each Id in #ids and looks for a corresponding Id in [Table] using an index.
This all assumes that there are gaps in the Ids between 1000 and 10000. Otherwise it would be easier to write
SELECT *
FROM [TABLE]
WHERE Id BETWEEN 1001 AND 10000;
This would also require an index on [Table].Id to speed it up.
I have a situation where I am suppose to compare a document name from one query against query.
I have a table called tbl_doc which consists document_name column.
Another table called tbl_content which consists content_name.
And I have two select queries like
select document_name from tbl_doc
select content_name from tbl_content.
SO I need to compare document_name against content_name if they are equal then need to do a insert operation.
Thanks
You probably mean to check if a certain value exists...
IF EXISTS(
SELECT 1 FROM [tbl_doc]
JOIN [tbl_content] ON [tbl_doc].[document_name] = [tbl_content].[content_name]
WHERE [tbl_doc].[document_name] = #Name )
BEGIN
INSERT INTO [...]
(
...
)
SELECT
...
END
select document_name,content_name
from tbl_doc
join tbl_content on document_name=content_name