I need a function in R that mimics the functionality of LIKE in MySQL.
(I need to validate outcomes of SQL queries and R scripts against each other. If I had a function that exists to mimic the functionality of LIKE, great, that reduces my workload.)
I am adding some of the behaviors of LIKE from the link above. As you can see, there are ways in which LIKE differs from the standard grep regex.
LIKE (description from the link)
Pattern matching using SQL simple regular expression comparison. Returns 1 (TRUE) or 0 (FALSE).
Per the SQL standard, LIKE performs matching on a per-character basis, thus it can produce results different from the = comparison operator:
Trailing spaces are significant
With LIKE you can use the following two wildcard characters in the pattern.
Character Description
% Matches any number of characters, even zero characters
_ Matches exactly one character
In MySQL, LIKE is permitted on numeric expressions. (This is an extension to the standard SQL LIKE.)
mysql> SELECT 10 LIKE '1%';
-> 1
Try sqldf package. You can write sql-like queries on data.frame
For example:
require(sqldf)
data(CO2)
new.data <- sqldf("select * from CO2 where Plant like 'Qn%'")
try ?grepl or package sqldf
df=data.frame(A=c("mytext_is_here","anothertext_is_here","mytext_is_also_here"),B=1:3)
df
firstSolution = subset(df, grepl("^mytext", A))
library("sqldf")
secondSolution = sqldf("select * from df where A like 'mytext%'")
Source: page 8 of http://cran.r-project.org/web/packages/sqldf/sqldf.pdf
I think you could use grepl function in R to do the same.
grepl does partial string matching and it will return a logical vector which you could later use to subset data along with other conditions as well.
You could also later use '!' sign in front of grepl to filter out the results having that expression.
ex. sample=c("data","ddata","ddata1")
filtered_data=grepl("dd",sample)
# it gives a logical vector FALSE TRUE TRUE
#and it can be used as follows to find out all the elements that have a string "dd" in it.
sample[grepl("dd",sample)]
Please note that grepl is case sensitive.
Related
My query:
Select * From tableName Where columnName Like "[PST]%"
is not giving the expected result.
Why does this wildcard not work in MySql?
If you want to filter on strings that contain any 'P', 'S', or 'T', then you can use a regex:
where col rlike '[PST]'
If you want strings that contain substring 'PST', then no need for square brackets - and like is enough:
where col like '%PST%'
If you want the matching character(s) at the start of the string, then the regex solution looks like:
where col rlike '^PST'
And the like option would be:
where col like 'PST%'
MySQL's LIKE syntax is documented here: https://dev.mysql.com/doc/refman/8.0/en/pattern-matching.html
Standard SQL from decades ago defined only two wildcards: % and _. These are the only wildcards an SQL product needs to support if they want to say they are SQL compliant and support the LIKE predicate.
% matches zero or more of any characters. It's analogous to .* in regular expressions.
_ matches exactly one of any character. It's analogous to . in regular expressions.
Also if you want to match a literal '%' or '_', you need to escape it, i.e. put a backslash before it:
WHERE title LIKE 'The 7\% Solution'
Microsoft SQL Server's LIKE syntax is documented here: https://learn.microsoft.com/en-us/sql/t-sql/language-elements/like-transact-sql?view=sql-server-ver15
They support % and _ wildcards, and the \ escape character, but they extend standard SQL with two other forms:
[a-z] matches one character, but only characters in the range inside the brackets. This is similar in regular expressions. The - is a range operator, unless it appears at the start or end of the string inside the brackets.
[^a-z] matches one character, which must not be one of the characters in the range inside the brackets. Also the same in regular expressions.
These are not standard forms of wildcards for the LIKE predicate, and other brands of SQL database don't support them.
Later versions of the SQL standard introduced a new predicate SIMILAR TO which supports much richer patterns and wildcards, since the right-side operand is a string which contains a regular expression. But since this predicate was introduced in a later edition of the SQL standard, some implementations had already developed their own solution that was almost the same.
MySQL called the operator REGEXP and RLIKE is a synonym (https://dev.mysql.com/doc/refman/8.0/en/regexp.html).
It was requested in https://bugs.mysql.com/bug.php?id=746 to support SIMILAR TO syntax to help MySQL comply with the SQL standard, but the request was turned down, because it had subtly different behavior to the existing REGEXP/RLIKE operator.
Microsoft SQL Server has partial support of regular expression wildcards in the LIKE operator, and also a dbo.RegexMatch() function.
SQLite has a GLOB operator, and so on.
Thanks everyone!
For specific this question, we need to use regexp
Select * From tableName Where ColumnName Regexp "^[PST]";
For more detail over Regular Expression i.e Regexp :
https://www.youtube.com/watch?v=KoltE-JUY0c
I got this question when I use mysql search something. here is the detailed information.
say I got a table named test with a column named content. in a specific record, the content column holds:
["
/^\w{2,}/","
/^[a-z][a-z0-9]+$/","
/^[a-z0-9]+$/","
/^[a-z]\d+$/"]
there is a linefeed character in the end of the lines(last line excluded)
so when I used the like syntax to search this record, I wrote a SQL like this
select * from test where `content` like
'[\"\n/^\\\\w{2,}/\",\"\n/^[a-z][a-z0-9]+$/\",\"\n/^[a-z0-9]+$/\",\"\n/^[a-z]\\\\d+$/\"]'
and it returned the right result. but when I changed the like to = and this SQL statement didn't work, after I tried several times, I got this SQL statement that worked:
select * from test where `content` =
'[\"\n/^\\w{2,}/\",\"\n/^[a-z][a-z0-9]+$/\",\"\n/^[a-z0-9]+$/\",\"\n/^[a-z]\\d+$/\"]'
it worked. so here is the question:
why on earth the like and = have different escape strategy? in the like statement I have to use \\\\w,\\\\d while in the = statement \\w,\\d just doing fine?
MySQL LIKE operator to select data based on patterns.
The LIKE operator is commonly used to select data based on patterns. Using the LIKE operator in the right way is essential to increase the query performance.
The LIKE operator allows you to select data from a table based on a specified pattern. Therefore, the LIKE operator is often used in the WHERE clause of the SELECT statement.
MySQL provides two wildcard characters for using with the LIKE operator, the percentage % and underscore _.
The percentage (%) wildcard allows you to match any string of zero or more characters.
The underscore (_) wildcard allows you to match any single character.
Comparison operations result in a value of 1 (TRUE), 0 (FALSE), or NULL. These operations work for both numbers and strings. Strings are automatically converted to numbers and numbers to strings as necessary.
The following relational comparison operators can be used to compare not only scalar operands, but row operands:
= > < >= <= <> !=
Note: = is Equal operator and LIKE for Simple pattern matching
I have two databases, both containing phone numbers. I need to find all instances of duplicate phone numbers, but the formats of database 1 vary wildly from the format of database 2.
I'd like to strip out all non-digit characters and just compare the two 10-digit strings to determine if it's a duplicate, something like:
SELECT b.phone as barPhone, sp.phone as SPPhone FROM bars b JOIN single_platform_bars sp ON sp.phone.REGEX = b.phone.REGEX
Is such a thing even possible in a mysql query? If so, how do I go about accomplishing this?
EDIT: Looks like it is, in fact, a thing you can do! Hooray! The following query returned exactly what I needed:
SELECT b.phone, b.id, sp.phone, sp.id
FROM bars b JOIN single_platform_bars sp ON REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(b.phone,' ',''),'-',''),'(',''),')',''),'.','') = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(sp.phone,' ',''),'-',''),'(',''),')',''),'.','')
MySQL doesn't support returning the "match" of a regular expression. The MySQL REGEXP function returns a 1 or 0, depending on whether an expression matched a regular expression test or not.
You can use the REPLACE function to replace a specific character, and you can nest those. But it would be unwieldy for all "non-digit" characters. If you want to remove spaces, dashes, open and close parens e.g.
REPLACE(REPLACE(REPLACE(REPLACE(sp.phone,' ',''),'-',''),'(',''),')','')
One approach is to create user defined function to return just the digits from a string. But if you don't want to create a user defined function...
This can be done in native MySQL. This approach is a bit unwieldy, but it is workable for strings of "reasonable" length.
SELECT CONCAT(IF(SUBSTR(sp.phone,1,1) REGEXP '^[0-9]$',SUBSTR(sp.phone,1,1),'')
,IF(SUBSTR(sp.phone,2,1) REGEXP '^[0-9]$',SUBSTR(sp.phone,2,1),'')
,IF(SUBSTR(sp.phone,3,1) REGEXP '^[0-9]$',SUBSTR(sp.phone,3,1),'')
,IF(SUBSTR(sp.phone,4,1) REGEXP '^[0-9]$',SUBSTR(sp.phone,4,1),'')
,IF(SUBSTR(sp.phone,5,1) REGEXP '^[0-9]$',SUBSTR(sp.phone,5,1),'')
) AS phone_digits
FROM sp
To unpack that a bit... we extract a single character from the first position in the string, check if it's a digit, if it is a digit, we return the character, otherwise we return an empty string. We repeat this for the second, third, etc. characters in the string. We concatenate all of the returned characters and empty strings back into a single string.
Obviously, the expression above is checking only the first five characters of the string, you would need to extend this, basically adding a line for each position you want to check...
And unwieldy expressions like this can be included in a predicate (in a WHERE clause). (I've just shown it in the SELECT list for convenience.)
MySQL doesn't support such string operations natively. You will either need to use a UDF like this, or else create a stored function that iterates over a string parameter concatenating to its return value every digit that it encounters.
I do this question, because I can't found a question with the same reason. The reason is when I use LIKE, I get CONSISTENT RESULTS, and when I use (=) operator I get INCONSISTENT RESULTS.
THE CASE
I have a BIG VIEW (viewX) with multiple inner joins and left joins, where some columns have null values, because the database definition allows for that.
When I open this VIEW I see for example: 8 rows as result.
When I run for example: select * from viewX where column_int = 34 and type_string = 'xyz', this query shows me 100 rows, that aren't defined in the result of the view. [INCONSISTENT]
BUT
When I run select * from viewX where column_int = 34 and type_string like 'xyz', this query show me only 4 rows, that is defined in the view when I opened (see 1.) [CONSISTENT]
Does anyone idea, of what is happening here?
From the documentation.....
'Per the SQL standard, LIKE performs matching on a per-character basis, thus it can produce results different from the = comparison operator: '
more importantly (when using LIKE):
'string comparisons are not case sensitive unless one of the operands is a binary string'
from :
http://dev.mysql.com/doc/refman/5.0/en/string-comparison-functions.html
Per the MySQL documentation LIKE does function differently than =, especially when you have trailing or leading spaces.
You need to post your actual query but I'm guessing it's related to the known variances.
Can I match and replace a text pattern in a MYSQL select?
EDIT
For now it looks like the answer is: Can't be done,
since you can't capture what was matched (from Eric's answer / comments). For now I will look into adding a lookup table.
Simplified example:
The MySQL table Coleridge holds many strings like:
text
------------------------------------
In_Xanadu_did_Kubla_Khan
A_stately_pleasure_dome_decree
Where_Alph_the_sacred_river_ran
Through_caverns_measureless_to_man
Down_to_a_sunless_sea
Is there a way to express the select
SELECT text =~ s / [ ^_ ] + _ ( .* ) _ [ ^_ ] + $ / \1 / as replaced FROM Coleridge
and get
replaced
________________________
Xanadu_did_Kubla
stately_pleasure_dome
Alph_the_sacred_river
caverns_measureless_to
to_a_s
Please Note:
The regular expression s/ / / I
provided is much less complicated
than what the real world DB contains
Unfortunately I can't normalize
the DB ..
There's no regex way to replace anything in MySQL. You can match in MySQL based on RegEx (regexp), but that doesn't return what part is matched, just the whole column that is. But, you can use replace like so:
select replace(col, 'e', 'i') from tbl
This will return regex as rigix.
As for your specific example, you'd have to use a combination of locate and substring:
select
substring(col
, locate('_', col)+1
, locate('_', reverse(col))-(len(col)-locate('_', col)-1))
from tbl
The general rule on string manipulations/handling on the database level is: Keep it simple. RDBMS's think in sets, and that's where they shine. Pulling individual string manipulations is not in their sweet spot. As such, no RDBMS has really mature string handling functions (and there certainly isn't any consistency across the different ones). If your regex is reasonably complex, you will most likely want to just handle it on the presentation/app layer, and not in the database.
No, you can't. MySQL only supports regexes for matching (RLIKE), not replacement.