I am trying to find addresses from a MySQL database by outcode, ie the first letters of a UK postcode. The following snippet works fine for two letter outcodes:
select * from addresstable where LEFT (Postcode, 2) in ('CB','PE','IP')
but I need it to work in cases where the outcode may be only one letter, ie:
select * from addresstable where LEFT (Postcode, 2) in ('B','BS','GL')
and the Left statement will of course fail on the single letter case.
How best can I do this search?
Thanks
Martin
I'm not an expert on UK postcodes, but it seems they always start with either one letter or two, followed by at least one digit. If that is true, you could use PATINDEX to find the first number, and then use SUBSTRING to get the first characters up to that first number:
select *
from addresstable
where SUBSTRING(Postcode,1,PATINDEX('%[0-9]%',Postcode)-1) in ('B','BX','GL')
Apparently, PATINDEX isn't built-in with MySQL. There are some functions you can create that simulates the behavior if you want to go that route. Another option, but a bit more clunky, but may work is to just check the second character to see if it is numeric or not. If it is, use the LEFT for one character, otherwise use the LEFT for two characters:
select *
from #addresstable
where (case when concat('',SUBSTRING(Postcode,2,1) * 1) = SUBSTRING(Postcode,2,1) then left(Postcode,1) else left(Postcode,2) end) in ('B','BX','GL')
You could use an OR clause for length 1
select *
from addresstable
where LEFT(Postcode, 2) in ('BS','GL')
OR LEFT(Postcode, 1) = 'B'
or
select *
from addresstable
where LEFT(Postcode, 2) = 'GL'
OR LEFT(Postcode, 1) = 'B'
Use regular expressions. To get postcodes that start with "B", "BS", or "GL":
where Postcode regexp '^(B|BS|GL)'
Of course, this example is a bit silly because postcodes that start with BS also start with B, so this can be simplified to:
where Postcode regexp '^(B|GL)'
Related
I am trying to pull a product code from a long set of string formatted like a URL address. The pattern is always 3 letters followed by 3 or 4 numbers (ex. ???### or ???####). I have tried using REGEXP and LIKE syntax, but my results are off for both/I am not sure which operators to use.
The first select statement is close to trimming the URL to show just the code, but oftentimes will show a random string of numbers it may find in the URL string.
The second select statement is more rudimentary, but I am unsure which operators to use.
Which would be the quickest solution?
SELECT columnName, SUBSTR(columnName, LOCATE(columnName REGEXP "[^=\-][a-zA-Z]{3}[\d]{3,4}", columnName), LENGTH(columnName) - LOCATE(columnName REGEXP "[^=\-][a-zA-Z]{3}[\d]{3,4}", REVERSE(columnName))) AS extractedData FROM tableName
SELECT columnName FROM tableName WHERE columnName LIKE '%___###%' OR columnName LIKE '%___####%'
-- Will take a substring of this result as well
Example Data:
randomwebsite.com/3982356923abcd1ab?random_code=12480712_ABC_DEF_ANOTHER_CODE-xyz123&hello_world=us&etc_etc
In this case, the desired string is "xyz123" and the location of said pattern is variable based on each entry.
EDIT
SELECT column, LOCATE(column REGEXP "([a-zA-Z]{3}[0-9]{3,4}$)", column), SUBSTR(column, LOCATE(column REGEXP "([a-zA-Z]{3}[0-9]{3,4}$)", column), LENGTH(column) - LOCATE(column REGEXP "^.*[a-zA-Z]{3}[0-9]{3,4}", REVERSE(column))) AS extractData From mainTable
This expression is still not grabbing the right data, but I feel like it may get me closer.
I suggest using
REGEXP_SUBSTR(column, '(?<=[&?]random_code=[^&#]{0,256}-)[a-zA-Z]{3}[0-9]{3,4}(?![^&#])')
Details:
(?<=[&?]random_code=[^&#]{0,256}-) - immediately on the left, there must be & or &, random_code=, and then zero to 256 chars other than & and # followed with a - char
[a-zA-Z]{3} - three ASCII letters
[0-9]{3,4} - three to four ASCII digits
(?![^&#]) - that are followed either with &, # or end of string.
See the online demo:
WITH cte AS ( SELECT 'randomwebsite.com/3982356923abcd1ab?random_code=12480712_ABC_DEF_ANOTHER_CODE-xyz123&hello_world=us&etc_etc' val
UNION ALL
SELECT 'randomwebsite.com/3982356923abcd1ab?random_code=12480712_ABC_DEF_ANOTHER_CODE-xyz4567&hello_world=us&etc_etc'
UNION ALL
SELECT 'randomwebsite.com/3982356923abcd1ab?random_code=12480712_ABC_DEF_ANOTHER_CODE-xyz89&hello_world=us&etc_etc'
UNION ALL
SELECT 'randomwebsite.com/3982356923abcd1ab?random_code=12480712_ABC_DEF_ANOTHER_CODE-xyz00000&hello_world=us&etc_etc'
UNION ALL
SELECT 'randomwebsite.com/3982356923abcd1ab?random_code=12480712_ABC_DEF_ANOTHER_CODE-aaaaa11111&hello_world=us&etc_etc')
SELECT REGEXP_SUBSTR(val,'(?<=[&?]random_code=[^&#]{0,256}-)[a-zA-Z]{3}[0-9]{3,4}(?![^&#])') output
FROM cte
Output:
I'd make use of capture groups:
(?<=[=\-\\])([a-zA-Z]{3}[\d]{3,4})(?=[&])
I assume with [^=\-] you wanted to capture string with "-","\" or "=" in front but not include those chars in the result. To do that use "positive lookbehind" (?<=.
I also added a lookahead (?= for "&".
If you'd like to fidget more with regex I recommend RegExr
I have a column STR which may contain any strings. I'm using MySql. How to find strings which don't contain letters in SQL without using Regular Expressions? As I understand RegExp in SQL is [^...].
So how to select the strings without using [^...]?
Regexp is the most sensible way of doing this. An alternative without...
SELECT STR
FROM YourTable
WHERE NOT EXISTS (SELECT *
FROM (SELECT 'A' AS C
UNION ALL
SELECT 'B'
UNION ALL
SELECT 'C'
/* Todo. Add remaining letters */
) Chars
WHERE INSTR(STR, C) > 0)
I am not sure which RDBMS you're using. But, if you do not want to use regular expression, you can loop through every character in the string and check the ASCII code. If they are only falling in the range 48 to 57, they are only numbers.
Note : This may be very costly operation
I've been to the regexp page on the MySQL website and am having trouble getting the query right. I have a list of links and I want to find invalid links that do not contain a period. Here's my code that doesn't work:
select * from `links` where (url REGEXP '[^\\.]')
It's returning all rows in the entire database. I just want it to show me the rows where 'url' doesn't contain a period. Thanks for your help!
SELECT c1 FROM t1 WHERE c1 NOT LIKE '%.%'
Your regexp matches anything that contains a character that isn't a period. So if it contains foo.bar, the regexp matches the f and succeeds. You can do:
WHERE url REGEXP '^[^.]*$'
The anchors and repetition operator make this check that every character is not a period. Or you can do:
WHERE LOCATE(url, '.') = 0
BTW, you don't need to escape . when it's inside [] in a regexp.
Using regexp seems like an overkill here. A simple like operator would do the trick:
SELECT * FROM `links` WHERE url NOT LIKE '%.%
EDIT:
Having said that, if you really want to negate regexp, just use not regexp:
SELECT * FROM `links` WHERE url NOT REGEXP '[\\.]';
I have a field called 'areasCovered' in a MySQL database, which contains a string list of postcodes.
There are 2 rows that have similar data e.g:
Row 1: 'B*,PO*,WA*'
Row 2: 'BB*, SO*, DE*'
Note - The strings are not in any particular order and could change depending on the user
Now, if I was to use a query like:
SELECT * FROM technicians WHERE areasCovered LIKE '%B*%'
I'd like it to return JUST Row 1. However, it's returning Row 2 aswell, because of the BB* in the string.
How could I prevent it from doing this?
The key to using like in this case is to include delimiters, so you can look for delimited values:
SELECT *
FROM technicians
WHERE concat(', ', areasCovered, ', ') LIKE '%, B*, %'
In MySQL, you can also use find_in_set(), but the space can cause you problems so you need to get rid of it:
SELECT *
FROM technicians
WHERE find_in_set('B', replace(areasCovered, ', ', ',') > 0
Finally, though, you should not be storing these types of lists as strings. You should be storing them in a separate table, a junction table, with one row per technician and per area covered. That makes these types of queries easier to express and they have better performance.
You are searching wild cards at the start as well as end.
You need only at end.
SELECT * FROM technicians WHERE areasCovered LIKE 'B*%'
Reference:
Normally I hate REGEXP. But ho hum:
SELECT * FROM technicians
WHERE concat(",",replace(areasCovered,", ",",")) regexp ',B{1}\\*';
To explain a bit:
Get rid of the pesky space:
select replace("B*,PO*,WA*",", ",",");
Bolt a comma on the front
select concat(",",replace("B*,PO*,WA*",", ",","));
Use a REGEX to match "comma B once followed by an asterix":
select concat(",",replace("B*,PO*,WA*",", ",",")) regexp ',B{1}\\*';
I could not check it on my machine, but it's should work:
SELECT * FROM technicians WHERE areasCovered <> replace(areaCovered,',B*','whatever')
In case the 'B*' does not exist, the areasCovered will be equal to replace(areaCovered,',B*','whatever'), and it will reject that row.
In case the 'B*' exists, the areCovered will NOT be eqaul to replace(areaCovered,',B*','whatever'), and it will accept that row.
You can Do it the way Programming Student suggested
SELECT * FROM technicians WHERE areasCovered LIKE 'B*%'
Or you can also use limit on query
SELECT * FROM technicians WHERE areasCovered LIKE '%B*%' LIMIT 1
%B*% contains % on each side which makes it to return all the rows where value contains B* at any position of the text however your requirement is to find all the rows which contains values starting with B* so following query should do the work.
SELECT * FROM technicians WHERE areasCovered LIKE 'B*%'
Is it possible in MySQL to select rows for a certain range of items?
For example when I want to select all items in where the first letter of the NAME is between the B and T, alphabetically.
I know I can make this is PHP aswell, but it would save me a bit of time if this is possible in MySQL...
Is it possible, and if so, how?
The ideal situation would be something like this:
$sql="SELECT * FROM paths FROM name=name1 TO name=name6"; //which would select name1, 2, 3, 4, 5, 6.
Using BETWEEN will basically get you there, but you need to use one letter past where you want to end. Experiment until you get the result you desire.
SELECT * FROM paths WHERE UPPER(name) BETWEEN 'B' AND 'U';
The idea here is that everything beginning with a 'T' will sort alphabetically before anything beginning with a 'U'. You need to convert it to upper-case via UPPER() so you don't run up against potential collation problems.
So your results could be like:
B,
Bill
Bob
Jane
Tommy
Travis
But Uwe (He's German) would be excluded.
You can use BETWEEN like:
SELECT * FROM paths WHERE name BETWEEN 'B' AND 'U'