SQL Server dynamic column list in contains function - sql

I have a database table in SQL Server 2008 with 5 nvarchar(max) columns. We're using the CONTAINS function to look for text in these columns.
We can look in all five columns using this kind of query:
SELECT *
FROM SomeTable ST
WHERE CONTAINS( (ST.ColumnA, ST.ColumnB, ST.ColumnC, ST.ColumnD, ST.ColumnE) , '"Strawberry"')
Now we want to search for text for one or more of these columns dynamically. For example, only look in ColumnB and ColumnE. I tried using a CASE statement, but I couldn't.
The only solution I can think of is dynamic SQL, but I'd prefer to avoid this. (The full query is very complicated.) Is there a way to do this without using dynamic SQL?

The only way I can think of to avoid using dynamic SQL involves using a temp table and if statements and stored proc. Have a stored proc with parameters for each of the columns that include the text to search that columns for. Create a temp table or table variable to store interim results.
Have five different if statements one for each possible column. In each if insert to the temp table if the variable is not null. something like:
IF #ColA is not null
BEGIN
INSERT INTO #temp
SELECT * FROM SomeTable ST
WHERE CONTAINS( (ST.ColumnA) , #ColA)
END
At the end select from the temp table to show your result.
This only works well though if you don't have very many columns and it would be unlikely that more will be added. Frankly, the fact that you have multiple columns you need to do full text search for the same search string indicates to me that you may have a basic problem with the database design.

I just can think in a solution like this, but this doesn't use full text Search... let me know if it is useful for you.
SELECT *
FROM SomeTable ST
WHERE 1=1
AND ((#colA = '') OR ST.ColumnA LIKE #colA)
AND ((#colB = '') OR ST.ColumnB LIKE #colB)
AND ((#colC = '') OR ST.ColumnC LIKE #colC)
AND ((#colD = '') OR ST.ColumnD LIKE #colD)
AND ((#colE = '') OR ST.ColumnE LIKE #colE)
The search_on parameters would be bit (0, 1) so, when set on 1, the search on that column would be activated.

You could UNION the 5 individual cases, then PIVOT and concatenate. I'm not sure it's any better than dynamic SQL.
You would end up with something like:
SET #FindKey = '%B%E%' -- This is your search which field criteria
WITH RESULTS1 AS (
SELECT PK, 'A' AS Col
FROM SomeTable ST
WHERE #FindKey LIKE '%A%' AND CONTAINS(ST.ColumnA, '"Strawberry"')
UNION
SELECT PK, 'B' AS Col
FROM SomeTable ST
WHERE #FindKey LIKE '%B%' AND CONTAINS(ST.ColumnB, '"Strawberry"')
UNION
SELECT PK, 'C' AS Col
FROM SomeTable ST
WHERE #FindKey LIKE '%C%' AND CONTAINS(ST.ColumnC, '"Strawberry"')
UNION
SELECT PK, 'D' AS Col
FROM SomeTable ST
WHERE #FindKey LIKE '%D%' AND CONTAINS(ST.ColumnD, '"Strawberry"')
UNION
SELECT PK, 'E' AS Col
FROM SomeTable ST
WHERE #FindKey LIKE '%E%' AND CONTAINS(ST.ColumnE, '"Strawberry"')
)
,RESULTS2 AS (
SELECT PK, ISNULL([A], '') + ISNULL([B], '') + ISNULL([C], '') + ISNULL([D], '') + ISNULL([E], '') AS FoundKey
FROM RESULTS PIVOT ( MIN(Col) FOR Col IN ([A], [B], [C], [D], [E]) ) AS pvt
)
SELECT *
FROM SomeTable
INNER JOIN RESULTS2
ON RESULTS2.PK = SomeTable.PK
WHERE RESULTS2.FoundKey LIKE #FindKey

Related

How to use LIKE with ANY in BigQuery?

I would like to use the LIKE ANY operator to exclude rows based on an array of substrings, but BigQuery does not recognize it.
declare unlaunched_clistings array<string>;
set unlaunched_clistings = {unlaunched_clistings} ;
select * from {p}.simeon_logs.process_errors e
where not e.message like any(unlaunched_clistings)
Error : LIKE ANY is not supported at [8:32]
Is there any workaround for this?
LIKE ANY is not supported, however you can use following 2 ways:
Use LIKE with ORs between them
WITH table AS (
SELECT 'abc' as col union all
SELECT 'xzy' as col
)
SELECT col
FROM TABLE
WHERE (col like '%abc%'
OR col like '%cde%' OR col like '%something%')
User RegEx
WITH table AS (
SELECT 'abc' as col
UNION ALL
SELECT 'xzy' as col
)
SELECT col
FROM TABLE
WHERE REGEXP_CONTAINS(col
, 'abc|cde|something')
Above both will give you abc row.

SQL Search rows that contain strings from 2nd table list

I have a master table that contains a list of strings to search for. it returns TRUE/FALSE if any string in the cell contains text from the master lookup table. Currently I use excel's
=SUMPRODUCT(--ISNUMBER(SEARCH(masterTable,[#searchString])))>0
is there a way to do something like this in SQL? LEFT JOIN or OUTER APPLY would be simple solutions if the strings were equal; but they need be contains..
SELECT *
FROM t
WHERE col1 contains(lookupString,lookupColumn)
--that 2nd table could be maintained and referenced from multiple queries
hop
bell
PRS
2017
My desired results would be a column that shows TRUE/FALSE if the row contains any string from the lookup table
SEARCH_STRING Contained_in_lookup_column
hopping TRUE
root FALSE
Job2017 TRUE
PRS_tool TRUE
hand FALSE
Sorry i dont have access to the DB now to confirm the syntax, but should be something like this:
SELECT t.name,
case when (select count(1) from data_table where data_col like '%' || t.name || '%' > 0) then 'TRUE' else 'FALSE' end
FROM t;
or
SELECT t.name,
case when exists(select null from data_table where data_col like '%' || t.name || '%') then 'TRUE' else 'FALSE' end
FROM t;
Sérgio
You can use a combination of % wildcards with LIKE and EXISTS.
Example (using Oracle syntax) - we have a v_data table containing the data and a v_queries table containing the query terms:
with v_data (pk, value) as (
select 1, 'The quick brown fox jumps over the lazy dog' from dual union all
select 2, 'Yabba dabba doo' from dual union all
select 3, 'forty-two' from dual
),
v_queries (text) as (
select 'quick' from dual union all
select 'forty' from dual
)
select * from v_data d
where exists (
select null
from v_queries q
where d.value like '%' || q.text || '%');

combining 3 tables where combination of 2 columns is not unique

There are 3 (will be up to 6 in the future) tables with the same columns.
I need to unify them, i.e. union on same columns. In addition to this - rows shall not be unique, based on 2 column combination! There are a couple of examples on the net, but all of them show how to exclude unique column values based on WHERE for one column. In my case there are 2 columns (Col1 and Col2 combination).
Here are the schematics:
and
And here is how I imagined final query (for 3-tables) would look like:
SELECT
*
FROM
(
SELECT * FROM table1
UNION
SELECT * FROM table2
UNION
SELECT * FROM table3
)
GROUP BY
Col1, Col2
HAVING
COUNT (*) > 1
What would be a correct way?
P.S. FYI single-column solutions
Multiple NOT distinct
How to select non "unique" rows
How to Select Every Row Where Column Value is NOT Distinct
EDIT:
I have used the code from accepted answer and added additional search criteria:
ON (SOUNDEX(Merged.[name_t1]) = SOUNDEX(Multiples.[name_t1]) OR Merged.[name_t1] LIKE '%' + Multiples.[name_t1] + '%' OR Multiples.[name_t1] LIKE '%' + Merged.[name_t1] + '%')
AND (SOUNDEX(Merged.[name_t2]) = SOUNDEX(Multiples.[name_t2]) OR Merged.[name_t2] LIKE '%' + Multiples.[name_t2] + '%' OR Multiples.[name_t2] LIKE '%' + Merged.[name_t2] + '%')
search col1 and col2:
-by SOUNDEX
-by col1 like (col1 from other table)
-by (col1 from other table) like col1
Here's the basics of a CTE-based approach :
With Merged AS
( -- CTE 1 : All Data in one table
SELECT * FROM table1
UNION ALL
SELECT * FROM table2
UNION ALL
SELECT * FROM table3
)
, Multiples AS
( -- CTE 2 : Group by the fields in common
SELECT Col1, Col2
FROM Merged
GROUP BY Col1, Col2
HAVING Count(*)>1 -- only want Groups of 2 or more
)
SELECT
Merged.*
FROM Merged INNER JOIN Multiples
-- Only return rows from Merged if they're in Multiples
ON Merged.[Col1]=Multiples.[Col1]
AND Merged.[Col2]=Multiples.[Col2]
Something like that works with my own example MS-SQL data, and it looks like SQLite syntax is the same. HTH!

Like Operator for checking multiple words

I'm struggling for a like operator which works for below example
Words could be
MS004 -- GTER
MS006 -- ATLT
MS009 -- STRR
MS014 -- GTEE
MS015 -- ATLT
What would be the like operator in Sql Server for pulling data which will contain words like ms004 and ATLT or any other combination like above.
I tried using multiple like for example
where column like '%ms004 | atl%'
but it didn't work.
EDIT
Result should be combination of both words only.
Seems you are looking for this.
`where column like '%ms004%' or column like '%atl%'`
or this
`where column like '%ms004%atl%'
;WITH LikeCond1 as (
SELECT 'MS004' as L1 UNION
SELECT 'MS006' UNION
SELECT 'MS009' UNION
SELECT 'MS014' UNION
SELECT 'MS015')
, LikeCond2 as (
SELECT 'GTER' as L2 UNION
SELECT 'ATLT' UNION
SELECT 'STRR' UNION
SELECT 'GTEE' UNION
SELECT 'ATLT'
)
SELECT TableName.*
FROM LikeCond1
CROSS JOIN LikeCond2
INNER JOIN TableName ON TableName.Column like '%' + LikeCond1.L1 + '%'
AND TableName.Column like '%' + LikeCond2.L2 + '%'
Try like this
select .....from table where columnname like '%ms004%' or columnname like '%atl%'

T-SQL Comma delimited value from resultset to in clause in Subquery

I have an issue where in my data I will have a record returned where a column value will look like
-- query
Select col1 from myTable where id = 23
-- result of col1
111, 104, 34, 45
I want to feed these values to an in clause. So far I have tried:
-- Query 2 -- try 1
Select * from mytableTwo
where myfield in (
SELECT col1
from myTable where id = 23)
-- Query 2 -- try 2
Select * from mytableTwo
where myfield in (
SELECT '''' +
Replace(col1, ',', ''',''') + ''''
from myTable where id = 23)
-- query 2 test -- This works and will return data, so I verify here that data exists
Select * from mytableTwo
where myfield in ('111', '104', '34', '45')
Why aren't query 2 try 1 or 2 working?
You don't want an in clause. You want to use like:
select *
from myTableTwo t2
where exists (select 1
from myTable t
where id = 23 and
', '+t.col1+', ' like '%, '+t2.myfield+', %'
);
This uses like for the comparison in the list. It uses a subquery for the value. You could also phrase this as a join by doing:
select t2.*
from myTableTwo t2 join
myTable t
on t.id = 23 and
', '+t.col1+', ' like '%, '+t2.myfield+', %';
However, this could multiply the number of rows in the output if there is more than one row with id = 23 in myTable.
If you observe closely, Query 2 -- try 1 & Query 2 -- try 2 are considered as single value.
like this :
WHERE myfield in ('111, 104, 34, 45')
which is not same as :
WHERE myfield in ('111', '104', '34', '45')
So, If you intend to filter myTable rows from MyTableTwo, you need to extract the values of fields column data to a table variable/table valued function and filter the data.
I have created a table valued function which takes comma seperated string and returns a table value.
you can refer here T-SQL : Comma separated values to table
Final code to filter the data :
DECLARE #filteredIds VARCHAR(100)
-- Get the filter data
SELECT #filteredIds = col1
FROM myTable WHERE id = 23
-- TODO : Get the script for [dbo].[GetDelimitedStringToTable]
-- from the given link and execute before this
SELECT *
FROM mytableTwo T
CROSS APPLY [dbo].[GetDelimitedStringToTable] ( #filteredIds, ',') F
WHERE T.myfield = F.Value
Please let me know If this helps you!
I suppose col is a character type, whose result would be like like '111, 104, 34, 45'. If this is your situation, it's not the best of the world (denormalized database), but you can still relate these tables by using character operators like LIKE or CHARINDEX. The only gotcha is to convert the numeric column to character -- the default conversion between character and numeric is numeric and it will cause a conversion error.
Since #Gordon, responded using LIKE, I present a solution using CHARINDEX:
SELECT *
FROM mytableTwo tb2
WHERE EXISTS (
SELECT 'x'
FROM myTable tb1
WHERE tb1.id = 23
AND CHARINDEX(CONVERT(VARCHAR(20), tb2.myfield), tb1.col1) > 0
)