T-SQL Using CONTAINS predicate with Hyphen - sql

Imagine a table (table1) with one column (column1) and one record whose value is 'roll-over'. Then use the following SQL query and you will not get any records.
select * from table1 where contains(column1, ' "roll-over" ')
Is there a way to escape the hyphen in the search text? So far I have not been successful trying this (I have tried all below escapes with no success).
select * from table1 where contains(column1, ' "roll\-over" ')
select * from table1 where contains(column1, ' "roll!-over" ')
select * from table1 where contains(column1, ' "roll[-]over" ')
Also, please note that using the LIKE keyword is not possible for my application because I am taking advantage of full-text search indexing.

It looks like you may not be able to do that. Give this article a read:
https://support.microsoft.com/en-us/help/200043/prb-dashes---ignored-in-search-with-sql-full-text-and-msidxs-queries
They suggest searching only alphanumeric values (lame) or using the LIKE Clause (not an option for you).

Partial solution: you can force the query to return records containing hyphens (or any character) by using the charindex function to test that the string contains the character, e.g.:
select * from table1 where contains(column1, ' "roll-over" ')
and charindex('-', column1) > 0

Related

How to check if a string contains exactly two words in an SQL query?

I need to execute a simple SQL query that will only select those names that are made up of exactly two words
SELECT NAME
FROM GROUP
WHERE NAME <Contains exactly two words>
You can use like and not like:
where name like '% %' and not like '% % %'
Another option is using LEN() (of course, I assume there are no trailing spaces):
SELECT [NAME]
FROM [GROUP]
WHERE LEN([NAME]) - LEN(REPLACE([NAME], ' ', '')) = 1
If the data in the NAME column has trailing space, you may use TRIM (for SQL Server 2017+) or a combination of LTRIM() and RTRIM() for earlier versions:
SELECT [NAME]
FROM [GROUP]
WHERE LEN(TRIM([NAME])) - LEN(REPLACE(TRIM([NAME]), ' ', '')) = 1
If you want both words present and exact:
SELECT *
FROM table
WHERE column LIKE '%word1%'
AND column LIKE '%word2%'

Using subquery with IN clause

I am stuck at one particular problem here, I am fetching ID's from one column that are like this ',90132988,90133148,72964884,' Let's say this value is stored in a column ColumnA of Table1.
I want to use this in another query that's using IN clause something like this.
SELECT *
FROM USER_GROUP
WHERE ID IN (SELECT CONCAT(CONCAT('(',REPLACE(LTRIM(RTRIM(REPLACE(COLUMNA, ',', ' '))), ' ', ',')),')') FROM Table1)
When I run this query I get invalid number error. Any suggestions ?
You get a number error because id is a number. So, Oracle wisely assumes that the subquery returns numbers.
I think the logic you want is:
SELECT ug.*
FROM USER_GROUP ug
WHERE EXISTS (SELECT 1
FROM Table1 t1
WHERE t1.COLUMNA LIKE '%,' || ug.ID || ',%'
);
I strongly discourage you from storing number lists as strings. Just store one row per number. That is really much simpler and the resulting code will be more efficient.
You can try converting "ID" using TO_CHAR, but you will lose the use of any index on ID if you have one.
SELECT *
FROM USER_GROUP
WHERE TO_CHAR(ID) IN (SELECT CONCAT(CONCAT('(',REPLACE(LTRIM(RTRIM(REPLACE(COLUMNA, ',', ' '))), ' ', ',')),')') FROM Table1)

DB2 efficient select query with like operator for many values (~200)

I have written the following query:
SELECT TBSPACE FROM SYSCAT.TABLES WHERE TYPE='T' AND (TABNAME LIKE '%_ABS_%' OR TABNAME LIKE '%_ACCT_%')
This gives me a certain amount of results. Now the problem is that I have multiple TABNAME to select using the LIKE operator (~200). Is there an efficient way to write the query for the 200 values without repeating the TABNAME LIKE part (because there are 200 such values which would result in a really huge query) ?
(If it helps, I have stored all required TABNAME values in a table TS to retrieve from)
If you are just looking for substrings, you could use LOCATE. E.g.
WITH SS(S) AS (
VALUES
('_ABS_')
, ('_ACCT_')
)
SELECT DISTINCT
TABNAME
FROM
SYSCAT.TABLES, SS
WHERE
TYPE='T'
AND LOCATE(S,TABNAME) > 0
or if your substrings are in table CREATE TABLE TS(S VARCHAR(64))
SELECT DISTINCT
TABNAME
FROM
SYSCAT.TABLES, TS
WHERE
TYPE='T'
AND LOCATE(S,TABNAME) > 0
You could try REGEXP_LIKE. E.g.
SELECT DISTINCT
TABNAME
FROM
SYSCAT.TABLES
WHERE
TYPE='T'
AND REGEXP_LIKE(TABNAME,'.*_((ABS)|(ACCT))_.*')
Just in case.
Note, that the '_' character has special meaning in a pattern-expression of the LIKE predicate:
The underscore character (_) represents any single character.
The percent sign (%) represents a string of zero or more characters.
Any other character represents itself.
So, if you really need to find _ABS_ substring, you should use something like below.
You get both rows in the result, if you use the commented out pattern instead, which may not be desired.
with
pattern (str) as (values
'%\_ABS\_%'
--'%_ABS_%'
)
, tables (tabname) as (values
'A*ABS*A'
, 'A_ABS_A'
)
select tabname
from tables t
where exists (
select 1
from pattern p
where t.tabname like p.str escape '\'
);

Search for a particular value in a string with commas

I have a TEXT column in my Table T and contains some values separated by Commas.
Example
Columns BNFT has text values such as
B20,B30,B3,B13,B31,B14,B25,B29,B1,B2,B4,B5
OR
B1,B2,B34,B31,B8,B4,B5,B33,B30,B20,B3
I want to return result in my query only if B3 is present.
It should not consider B30-B39 or B[1-9]3 (i.e. B13, B23 .... B93).
I tried with below query, but want to implement REGEXP or REGEXP_LIKE/INSTR etc. Haven't used them before and unable to understand also.
Select *
FROM T
Where BNFT LIKE '%B3,%' or BNFT LIKE '%B3'
Pls advise
Procedures will not work. Query must start with Select as 1st statement.
The first advice is to fix your data structure. Storing lists of ids in strings is a bad idea:
You are storing numbers as strings. That is the wrong representation.
You are storing multiple values in a string column. That is not using SQL correctly.
These values are probably ids. You cannot declare proper foreign key relationships.
SQL does not have particularly strong string functions.
The resulting query cannot take advantage of indexes.
That said, sometimes we are stuck with other people's bad design decisions.
In SQL Server, you would do:
where ',' + BNFT + ',' LIKE '%,33,%'
This question was originally tagged MySQL, which offers find_in_set() for this purpose:
Where find_in_set(33, BNFT) > 0
Select *
FROM T
Where ',' + BNFT + ',' LIKE '%,B3,%';
or
Select *
FROM T
Where CHARINDEX (',B3,',',' + BNFT + ',') > 0;
This can be easily achieve by CTE, REGEXP/REGEXP_Like/INSTR works better with oracle, for MS SQL Server you can try this
DECLARE #CSV VARCHAR(100) ='B2,B34,B31,B8,B4,B5,B33,B30,B20,B3';
SET #CSV = #CSV+',';
WITH CTE AS
(
SELECT SUBSTRING(#CSV,1,CHARINDEX(',',#CSV,1)-1) AS VAL, SUBSTRING(#CSV,CHARINDEX(',',#CSV,1)+1,LEN(#CSV)) AS REM
UNION ALL
SELECT SUBSTRING(A.REM,1,CHARINDEX(',',A.REM,1)-1)AS VAL, SUBSTRING(A.REM,CHARINDEX(',',A.REM,1)+1,LEN(A.REM))
FROM CTE A WHERE LEN(A.REM)>=1
) SELECT VAL FROM CTE
WHERE VAL='B3'

Use REPLACE statement to change data in ALL fields of the result set

Basically, the subject. I'm accessing a database via Web interface, which submits SQL queries using a Web form. The database is in read-only mode, so I cannot use UPDATE statement. Also, please note that I need to act on all fields at once. Here's what I've tried:
SELECT *, REPLACE((SELECT * FROM sf0314.groups), ':', ';')
FROM sf0314.groups
WHERE group_id < 1000
Server replied with the following error message:
There was an error in your query: subquery must return only one column
I also tried to use AS to refer to all fields in the main SELECT, but it was unsuccessful as well. I understand how I can use REPLACE to update one or several named fields in the result set. But, the question is:
How can I refer to multiple (all) fields in the REPLACE statement? Thank you!
You can not. REPLACE() function accepts three string arguments, but can't accept lists or resultsets.
You have to list all of your columns in the select statement, then add REPLACE function to each column.
Example
SELECT
REPLACE(field1, ':', ';') AS field1
REPLACE(field2, ':', ';') AS field2,
REPLACE(field3, ':', ';') AS field3,
REPLACE(field4, ':', ';') AS field4,
FROM
YourTable
EDIT (Summarizing the conversation in the comments)
You can generate your field list using the metadata storage provided by the RDBMS. In most Database Engines, the INFORMATION_SCHEMA contains the metadata:
Example for MySQL:
SELECT
CONCAT('REPLACE(`', C.COLUMN_NAME, '`, '':'', '';'')')
FROM
information_schema.COLUMNS C
WHERE
C.TABLE_SCHEMA = '[YourDatabaseName]'
AND C.TABLE_NAME = '[YourTableName]'
Example for MSSQL (using DMVs):
USE [YourDatabaseName];
SELECT
'REPLACE([' + C.name + '], '':'', '';'')'
FROM
sys.columns C
WHERE
C.object_id = OBJECT_ID('[schema].[table]')