Differene between 2 where conditions which looks similar - sql

My mind is blind when I see those 2 where conditions and I can't understand what's the difference.
Can someone explain me? First returns 273 records and the second one returns 93. I thought they should return the same records.
1st
s.value LIKE '%One Travel%'
OR s.value LIKE '%One RSA%'
OR s.value LIKE '%One Other%'
OR s.value LIKE '%GP&U%'
OR s.value = ' '
2nd
s.value LIKE (
'%One Travel%'
,'%One RSA%'
,'%One Other%'
,'%GP&U%'
, ' ')

I don't know H2 at all, but I assume the second query evaluates to:
s.value LIKE '%One Travel%'
OR s.value LIKE '%One RSA%'
OR s.value LIKE '%One Other%'
OR s.value LIKE '%GP&U%'
OR s.value LIKE ' '
So you're left with the difference between s.value = ' ' and s.value LIKE ' '. Apparently H2 follows ANSI SQL, and the ANSI standard ignores trailing spaces in comparisons (actually the strings to be compared are padded with spaces till they are the same length). So s.value = ' ' returns TRUE for ' ', but also for '' and ' '. LIKE doesn't pad spaces to compare, since it is used for pattern matching rather than equality tests. Hence, LIKE ' ' only matches a single space.
In short; your first query returns more rows because rows where value is an empty string or multiple spaces, are also returned. Your second query returns only rows where value is a single space (ignoring the other conditions for simplicity).

LIKE in the second command is not a function, it is actually the same LIKE predicate. But its right-hand argument is specified as a row value.
I guess many DBMS throw an error, but H2 tries to convert all values here to a character string instead, in some rare cases it is useful, but in this case it isn't.
something LIKE (
'%One Travel%'
,'%One RSA%'
,'%One Other%'
,'%GP&U%'
, ' ')`
becomes
something LIKE 'ROW (%One Travel%, %One RSA%, %One Other%, %GP&U%, )'
in recent versions of H2 or
something LIKE '(%One Travel%, %One RSA%, %One Other%, %GP&U%, )'
in older versions (they don't support row values, but they treat such expressions as non-standard arrays).
Both expressions are meaningless. You need to use the first command with multiple OR conditions. Alternatively you can use a complex regular expression with non-standard REGEXP operator (with similar to LIKE syntax) or with also non-standard REGEXP_LIKE function.
Actually VALUE is a keyword, so both these commands cannot be executed by H2 (at least by its recent versions), but I assume it was just a replacement of a real column name.

Related

SQL Using LIKE and ANY at the same time

I have a table with a column feature of type text and a text array (text[]) named args. I need to select from the table those rows in which the feature column contains at least one of the elements of the args array.
I've tried different options, including this:
SELECT * FROM myTable WHERE feature LIKE '%' + ANY (args) + '%';
But that does not work.
The simple solution is to use the regular expression match operator ~ instead, which works with strings in arg as is (without concatenating wildcards):
SELECT *
FROM tbl
WHERE feature ~ ANY(args);
string ~ 'pattern' is mostly equivalent to string LIKE '%pattern%', but not exactly, as LIKE uses different (and fewer) special characters than ~. See:
Escape function for regular expression or LIKE patterns
If that subtle difference is not acceptable, here is an exact implementation of what you are asking for:
SELECT *
FROM tbl t
WHERE t.feature LIKE ANY (SELECT '%' || a || '%' FROM unnest(t.args) a);
Unnest the array, pad each element with wildcards, and use LIKE ANY with the resulting set.
See:
IN vs ANY operator in PostgreSQL

Get rows which contain exactly one special character

I have a SQL query which returns some rows having the below format:
DB_host
DB_host_instance
How can i filter to get rows which only have the format of 'DB_host' (place a condition to return values with only one occurrence of '_')
i tried using [0-9a-zA-Z_0-9a-zA-Z], but seems like its not right. Please suggest.
One option would be using REGEXP_COUNT and at most one underscore is needed then use
WHERE REGEXP_COUNT( col, '_' ) <= 1
or strictly one underscore should exist then use
WHERE REGEXP_COUNT( col, '_' ) = 1
A simple method is a regular expression:
where regexp_like(col, '^[^_]+_[^_]+$')
This matches the full string when there is a string with no underscores followed by an underscore followed by another string with no underscores.
You could also do this with LIKE, but it is more complicated:
where col like '%\_%' and col not like '%\_%\_%'
That is, has one underscore but not two. The \ is needed because _ is a wildcard for LIKE patterns.
You can suppress underscores in the string, and ensure that the length of the result is just one character less than the original:
where len(replace(col, '_', '')) = len(col) - 1
I wonder how this method would compare to a regex or two likes in terms of efficiency on a large dataset. I would not be surprised it it was more efficient.

Why "=" and "like" work in the same statement

I was practicing SQL injection skill, and I found that I could put = and LIKE in a single statement.
However, I'm not sure what does this mean and why it works?
SELECT 1 FROM users WHERE name='' LIKE '%'
So, what does that mean when I put = and LIKE in a statement, and when would I write something like this?
I am guessing that you are using MySQL, because this is syntactically correct in MySQL. It treats boolean types as numbers (which will be converted to integers and strings).
So, your code should be parsed as:
WHERE (name = '') LIKE '%'
This is because = and LIKE have the same precedence, and when operators have the same precedence, they are evaluated left-to-right (as explained in the documentation).
This, in turn evaluates to one of these three possibilities:
WHERE 1 LIKE '%' -- when name = ''
WHERE 0 LIKE '%' -- otherwise when name is not null
WHERE NULL like '%'
The first two will always evaluate to true. The third would discard any row where name is null.
(in MySQL and other popular DBMS) The LIKE operator is used to search for a specified pattern in a column. It admits "%" as a wildcard that represents zero, one, or multiple characters.
Your query always passes because the string '' meets this wildcard (zero characters). Incidentally, almost anything will. Some DBMS will react differently to such a query though.

search for the presence of two strings in oracle database in a clob column?

I have a clob column with a long string.
like "great job done today. good "
I want to retrieve all the records which has both the words great and good .
both the position is not fixed.
It's not clear what "which has both the words great and good " actually means.
If you mean you want to check if the string has both patterns of words, then it is simple as
where lower(col) like '%good%' AND lower(col) like '%great%'
If you mean they should contain true words good and great, then for simpler cases something like should do
where ' ' || lower(col) || ' ' LIKE '% good %' AND ' ' || lower(col) || ' ' LIKE '% great %'
However, this will not match a sentence ending with the word and having a full stop. It gets lengthy if you want to simply use LIKE to handle such scenarios.
REGEXP functions give more flexibility, but could be less performant.
WHERE REGEXP_LIKE ( s, '(^|\W)good(\W|$|\.)') AND REGEXP_LIKE ( s, '(^|\W)great(\W|$|\.)')
This searches for word boundaries, i.e. the word surrounded by non-word characters and start and end including an ending dot. If you want to ignore case, add ,'i' as 3rd argument to it.
I think this is the basic logic you want:
where lower(col) like '%good%' and lower(col) like '%great%'
In clobs, you can't quite use like:
where dbms_lob.instr(col, 'good') and dbms_log.instr(col, 'great')
Try this and let me know if it works for you.
SELECT *
FROM clob_table
WHERE DBMS_LOB.INSTR(clob_text,'great')>0
AND DBMS_LOB.INSTR(clob_text,'good')>0;
Remember put the names of your table and columns.
Here my results,

Match Character Whether or Not It Exists in Like Statement

I need a like expression that will match a character whether or not it exists. It needs to match the following values:
..."value": "123456"...
..."value": "123456"...
"...value":"123456"...
This like statement will almost work: LIKE '%value":%"123456"%'
But there are values like this one that would also match, but I don't want returned:
..."value":"99999", "other":"123456"...
A regex expression to do what I'm looking to do is 'value": *?"123456"'. I need to do this in SQL Server 2008 and I don't believe there is good regex support in that version. How can I match using a like statement?
Remove the whitespace in your compare with REPLACE():
WHERE REPLACE(column,' ','') LIKE '%"value":"123456"%'
May need a double replace for tabs:
REPLACE(REPLACE(column,' ',''),' ','')
I don't think you can with the like operator. You could exclude ones you could match, like if you want to make sure it just doesn't contain other:
[field] LIKE '%value":%"123456"%` AND [field] NOT LIKE '%"other"%'
Otherwise I think you'd have to do some processing on the string. You could write a UDF to take the string and parse it to find the value for 'value' and compare based on that:
dbo.fn_GetValue([field], 'value') = '123456'
The function could find the index of '"' + #name + '"', find the next index of a quote, and the one after that, then get the string between those two quotes and return it.