MySQL query to categorised address based on values using regular Expression - mysql

I have a table which has one column of addresses. I have some 10 - 11 places name.
When i query that table using 'Select * ...', i want to create a new column which matches the values with address fields and store that values into new column of exist else 'Not Found'.
The table has address column as below. I want to extract areas from it such as BTM Layot, Wilson Garden
When i do the select query, the output should be that address field and one more field which will give me the abstract location area from address field. And if any value does not matches the address field then it shoud display as 'Area Nt Specified'

Consider a cross join query (query with no joins but a list of tables in FROM clause) between the larger table of addresses (t1) and smaller table of your 10-11 places (t2) holding BTM Layot, Wilson Garden... values. This will be scalable instead of manually entering/editing places in an IN clause.
Then use a LIKE expression in a WHERE clause to match the places which are a part of the larger address string. However, to return all original address values with matched places use the LEFT JOIN...NOT NULL query with cross join as derived table (sub).
SELECT `maintable`.`address`, IFNULL(sub.`place`, 'Area Nt Specified') As matchplaces
FROM `maintable`
LEFT JOIN
(SELECT t1.ID, t1.address, t2.place
FROM `maintable` As t1,
(SELECT `place` FROM `placestable`) As t2
WHERE t1.address LIKE Concat('%',t2.place,'%')) As sub
ON `maintable`.ID = sub.ID
WHERE `maintable`.ID IS NOT NULL;
If really need to use regular expression, replace the LIKE expression in derived table with below:
WHERE t1.address regexp t2.place

If you have a list of know places, then you can do:
select (case when address regexp '(, BTM Layout|, Bapuji Nagar|, Adugodi)$'
then substring_index(address, ', ', -1)
else 'Not Found'
end)
You can expand the regular expression to include as many places as you like.
Or alternatively, you don't really need a regular expression:
select (case when substring_index(address, ', ', -1) in ('BTM Layout', 'Bapuji Nagar', 'Adugodi', . . .)
then substring_index(address, ', ', -1)
else 'Not Found'
end)

Related

How to select parts of string in MySQL 5.x

I have a varchar(255) field within a source table and the following contents:
50339 My great example
2020002 Next ID but different title
202020 Here we go
Now I am processing the data and do an insert select query on it. From this field I would need the INT number at the beginning of the field. IT IS followed by 2 spaces and a text with var length, this text is what I need as well but for another field. In General I want to to put text and ID in two fields which are now in one.
I tried to grab it like this:
SELECT STATUS REGEXP '^(/d{6,8}) ' FROM products_test WHERE STATUS is not null
But then I learned that in MySQL 5.x there are no regexp within the SELECT statement.
How could I seperate those values within a single select statment, so I can use it in my INSERT SELECT?
From the correct solution of user slaakso, resulted another related problem since somtimes the STATUS field is empty which then results in only one insert, but in case there is a value I split it into two fields. So the count does not match.
My case statement with his solution somehow contains a syntax problem:
CASE STATUS WHEN ''
THEN(
NULL,
NULL
)
ELSE(
cast(STATUS as unsigned),
substring(STATUS, locate(' ', STATUS)+3)
)
END
You can do following. Note that you need to treat the columns separately:
select
if(ifnull(status, '')!='', cast(status as unsigned), null),
if(ifnull(status, '')!='', substring(status, locate(' ', status)+2), null)
from products_test;
See db-fiddle

Selecting rows in a subquery not working when "where in" clause is a dynamic field with replaced JSON brackets/quotes

I am trying to write a query to select game names separated by commas in a subquery that are stored in a discount code column in JSON format. The query below currently only returns one result, when I should be expecting multiple game names to follow based on the logic.
SELECT
discount_code, discount_type, percentage_off,
(
SELECT
GROUP_CONCAT(name)
FROM
games AS g
WHERE
g.id IN (
REPLACE(
REPLACE(
REPLACE(dc.game_ids, '[', '' ), ']', ''
), '"', ''
)
)
) AS game_names
FROM
discount_codes AS dc
WHERE
status = 1 AND
active = 1
ORDER BY
id
ASC
Any idea why the query only returns one result (one game name) from the subquery?
Edit:
Example Data:
id name description
- - -
1 Fun and exciting! Game description...
2 Game Name Game description...
discount_codes
id discount_code discount_type percentage_off game_ids
- - - - -
1 10OFF single-use 10 ["1"]
2 FREE ongoing 100 ["1,2"]
The reason that your query only returns one result is that the return value of your REPLACE calls is a string, not a set of values. When MySQL then tries to evaluate that expression, it converts the string to an integer (to match g.id) and that results in it returning the first value in the string (e.g. 1,3,5 is converted to 1), hence you only get one value returned. The best way to implement your desired functionality is to use the inbuilt JSON functions (assuming you are using MySQL 5.7 or later); however, given the nature of your data you still need to remove the double quotes from the values:
SELECT
discount_code, discount_type, percentage_off,
(
SELECT
GROUP_CONCAT(name)
FROM
game AS g
WHERE
JSON_SEARCH(REPLACE(dc.game_ids, '"', ''), 'one', g.id) IS NOT NULL
) AS game_names
FROM
discount_codes AS dc
WHERE
status = 1 AND
active = 1
ORDER BY
id
ASC
If you are using a version of MySQL prior to 5.7, you can use FIND_IN_SET instead. Note that for FIND_IN_SET to work correctly, it's important there are no spaces in the string either, so you need to add another level of REPLACE nesting:
SELECT
discount_code, discount_type, percentage_off,
(
SELECT
GROUP_CONCAT(name)
FROM
game AS g
WHERE
FIND_IN_SET(g.id,
REPLACE(
REPLACE(
REPLACE(dc.game_ids, '[', '' ), ']', ''
), '"', ''
)
)
) AS game_names
FROM
discount_codes AS dc
WHERE
status = 1 AND
active = 1
ORDER BY
id
ASC
Demo on dbfiddle

MySQL How to split string from column by " " and insert result separated by , into another column?

I would like to ask how to split string from column (all rows in table) by " " and insert result separated by , into another column in same table?
Many thanks for any advice.
Table struct example:
------------------------------------------
| Original string | Spliced string |
------------------------------------------
| Some string 001 | Some,String,001 |
------------------------------------------
If I needed to "split" a string on a delimiter, I'd likely make use of the nifty SUBSTRING_INDEX function. But there are a few quirks to be aware of.
The approach I would take would certainly be to write a SELECT statement first. That would include the expression(s) in the SELECT list that return the "separated" values that I wanted to assign to another column. I'd get those expressions tested using a SELECT statement, before I wrote an UPDATE statement.
SELECT t.id
, t.column_i_want_to_split
, expr1
FROM mytable t
ORDER BY t.id
To test specific cases, I'd make use of an inline view
SELECT t.id
, t.note
, t.val
, expr1
FROM ( SELECT 1 AS id, 'empty string test' AS note, '' AS val
UNION ALL SELECT 2, 'null', NULL
UNION ALL SELECT 3, 'one space', ' '
UNION ALL SELECT 4, 'four spaces', ' '
UNION ALL SELECT 5, 'test5', ' abc def '
UNION ALL SELECT 6, 'test6', 'g hi kl m'
) t
ORDER BY t.id
Once I had the expression(s) returning the values I want to assign to another column, I'd convert the SELECT into an UPDATE statement. To process all rows, omit the WHERE clause.
UPDATE mytable t
SET t.another_column = expr1
Without a more definitive specification, or at least some concrete examples of what you are attempting to achieve, we're just guessing. Given only a general description of the problem, all we can offer is some general advice.

MySQL syntax for conditional CONCAT depending on a field content?

I have inherited a simple table from a client, that stores two addresses (shipping address and business address) in just two fields shipping_address and business_address. There is a field called ship_to with enum('shipping','business'), and a field for a full name. The client wants an output as:
full name: address
Where "address" column should be picked by the ship_to value. If ship_to = shipping then use shipping_address column. If ship_to = business then use business_address column.
For instance:
Joe Smith: Roach Street #10, Rats Village
How I can use CONCAT with IF condition? I'm guessing something like this, which obviusly is just an idea:
SELECT CONCAT( full_name, ':', IF (ship_to=='shipping', shipping_address, business_address ) AS contact FROM `table`
But, what's the right syntax for doing this?
Lacking the closing )
SELECT
CONCAT( full_name, ':', IF (ship_to='shipping', shipping_address, business_address )) as contact
FROM TableName

MySQL returning an empty field: CONCAT(nonEmpty1,empty2,nonEmpty3) = NULL

I have PHP 5 code accessing a MyISAM table on MySQL 5 server. The query looks like this:
SELECT CONCAT(fName1,' ',mName2,' ',lName3) AS userName
FROM users
WHERE level > 10
When there's no mName filled in, I am expecting output like "fname lname" , but I'm getting "" (empty string) instead (the number of rows returned is correct). Where am I making a mistake?
PHP code:
<?php
$result = mysql_query($the_above_query);
while ($result_row = mysql_fetch_assoc($result)) {
// do stuff with the name
// except I'm getting empty strings in $result_row['userName']
}
Relevant part of table structure:
CREATE TABLE users {
/* -snip- */
`fName1` varchar(50) default NULL,
`mName2` varchar(50) default NULL,
`lName3` varchar(50) default NULL,
`level` int(11) default 0,
/* -snip- */
} ENGINE=MyISAM DEFAULT CHARSET=utf8;
(also, is this way (column concatenation in MySQL) a good idea, or should I fetch the columns to PHP and join them there?)
Turns out that I was getting back a NULL; PHP treats a returned NULL and empty string("") similarly, you'd have to compare with === to see the difference.
From google: http://bugs.mysql.com/bug.php?id=480
[23 May 2003 4:32] Alexander Keremidarski
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.mysql.com/documentation/ and the instructions on
how to report a bug at http://bugs.mysql.com/how-to-report.php
This is doccumented behaviour of CONCAT() function.
From Manual chapter 6.3.2 String Functions
CONCAT(str1,str2,...)
Returns the string that results from concatenating the arguments. Returns NULL if any
argument is NULL
Use CONCAT_WS() instead or wrap NULLable paremeters with IFNULL() function.
Documentation and usage for CONCAT_WS: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_concat-ws
From MYSQL docs
CONCAT() returns NULL if any argument
is NULL.
you want to use CONCAT_WS()
CONCAT_WS(separator,str1,str2,...)
But best bet is to just pull it back and use php cause if you need a different format or just one of those fields later you'll have to make another db call
In MySQL concatenating any string to a NULL value results in NULL.
You have to check for NULL before concatenate using IFNULL:
SELECT CONCAT(IFNULL(fName1,''),' ',IFNULL(mName2,''),' ',IFNULL(lName3,'')) AS userName
FROM users
WHERE level > 10
This was the solution I came up with which included Keeper and Ersatz answer. System would not allow me to vote you guys up though :(
CONCAT_WS(IFNULL(ts_usr_nameDetails.first_name,''),' ',IFNULL(ts_usr_lib_connectionNameDetails.first_name,'')) AS composerName
This allowed for some amazing results
This is an answer based on the solution above by #chocojosh and another question here: MySQL/SQL: Update with correlated subquery from the updated table itself
I had a similar problem, but I was trying to concat a bunch of group_concats and some were NULL which caused the whole row to be NULL. The goal was to place data from other tables into a single field in the main table to allow fulltext searches.
Here is the SQL that worked. Note the first parameter for concat_ws I made ' ', this allowed for spaces between the values for the fulltext field.
Hope this helps someone.
update
products target
INNER JOIN
(
select p.id,
CONCAT_WS(
' ',
(select GROUP_CONCAT(field SEPARATOR ' ') from table1 where productId = p.id),
p.title,' ',
(select GROUP_CONCAT(field, ' ', descriptions SEPARATOR ' ') from table2 where productId = p.id),
(select GROUP_CONCAT(field SEPARATOR ' ') from table3 where productId = p.id),
(select GROUP_CONCAT(field, ' ', catno SEPARATOR ' ') from table4 where productId = p.id),
(select GROUP_CONCAT(field SEPARATOR ' ') from table5 where productId = p.id),
(select GROUP_CONCAT(field SEPARATOR ' ') from table6 where productId = p.id),
(select GROUP_CONCAT(field SEPARATOR ' ') from table7 where productId = p.id)
) as ft
from products p
) as source
on target.id = source.id
set target.fulltextsearch = source.ft
you could also the COALESCE() function to return the first non-null value. Like so:
SELECT CONCAT(fName1,COALESCE(CONCAT(' ',mName2,' '),' '),lName3) AS userName
FROM users
WHERE level > 10
This would also only put one space if there was no middle name and a space before and after if there was a middle name.
Reference for this function can be found at: http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_coalesce