Sql Select into array - column has seperater - mysql

I have a column in my DB that has the following data (yeah i know its wrong to have multiple names separated by some random character)
"John Cusack | Thandie Newton | Chiwetel Ejiofor"
I want to be able to separate these people into an array to use later or even just to be able display them like below will help
John Cusack
Thandie Newton
Chiwetel Ejiofor
any ideas please
thanks in advance

As you say, storing delimited lists in an RDBMS really is not a good idea; however, you may be able to use MySQL's string manipulation functions such as SUBSTRING_INDEX() to obtain your desired results (MySQL doesn't have array types, so I assume you're merely looking to split the data):
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(my_column, '|', 1), -1),
SUBSTRING_INDEX(SUBSTRING_INDEX(my_column, '|', 2), -1),
SUBSTRING_INDEX(SUBSTRING_INDEX(my_column, '|', 3), -1)
FROM my_table
Note that one doesn't actually need to invoke SUBSTRING_INDEX() twice for the first and last elements of the list, but I thought it informative to do so in order that the pattern for further elements can be seen more clearly.
If you were so inclined, you could build a stored procedure that loops over the string populating a temporary table with each found element—but this is all so far away from "good practice" that it's almost certainly not worth delving into it any further.

you can try this.
select substring_index(substring_index('a|b|c|h', '|',#r:=#r+1),'|',-1) zxz
from (select #r:=0) x,
(select 'x' xx union select 'v' xx union select 'z' xx union select 'p' xx) z;
Result looks like
----
|zxz|
-----
|a |
------
|b |
------
|c |
------
|h |
------
locatet here: Mysql
and a little modified.
Remember: The "count" of the union statements have to be the same as your delemiter.
Kind Regars

Related

How to extract specifc part from a string in MySQL

I am trying to extract a specifc part from a string in MySQL, however, I am unable to extract it correctly.
The pattern is the following:
-MB|{field_1}-AA|{field_2}-BB|{field_3}
This is the example
-MB|string1-AA|string2-BB|string3
I've written the following code to extract the last field, however it is not dynamic, and will only work, when we have a specific number of letters/numbers:
SELECT
test_string,
SUBSTRING(test_string, LOCATE( '|', test_string) + 1 - LOCATE( '|', test_string) - 9) as string3
FROM test_table;
The output is the whole string and then just the last part of it:
string3
Having this said, can someone suggest a syntax that I can use in order to extract:
the values between the 1st | and second |
the value between the 2nd | and the 3rd |
and a better way to extract everything after the 3rd |
Thank you in advance!
If you're going for the last string only, you can REVERSE() the string first then locate | and then use it to do SUBSTRING() on the reversed string.. THEN reverse it again to get the original string. There are three REVERSE() in total if you're going with SUBSTRING() without a subquery:
SELECT test_string,
REVERSE(SUBSTRING(REVERSE(test_string),1,LOCATE('|',REVERSE(test_string))-1))
FROM test_table;
If you're using a subquery, you can reduce the usage of REVERSE() to two, albeit with a longer query:
SELECT test_string,
REVERSE(SUBSTRING(rvstr,1,LOCATE('|',rvstr)-1))
FROM
(SELECT test_string,
REVERSE(test_string) rvstr
FROM test_table) a;
But you can avoid all that and just use SUBSTRING_INDEX
SELECT test_string,
SUBSTRING_INDEX(test_string, '|', -1)
FROM test_table;
You can use the same function to extract other string separated by the delimiter using something like this:
SELECT test_string,
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',1),'|',-1) AS 'Str1',
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',2),'|',-1) AS 'Str2',
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',3),'|',-1) AS 'Str3'
FROM test_table;
As for "way to extract everything after the 3rd", I think it's a bit tricky but maybe:
SELECT test_string,
Str1,Str2,Str3,
SUBSTRING(test_string,LENGTH(CONCAT(Str1,Str2,Str3))+4) AS 'StrAfter3rd'
FROM
(SELECT test_string,
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',1),'|',-1) AS 'Str1',
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',2),'|',-1) AS 'Str2',
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',3),'|',-1) AS 'Str3'
FROM test_table) v;
Getting the LENGTH() of the concatenated results of Str1 to Str3 with 3 of the original | re-added and + the last | before the 4th string (+4 in total), then use it for the SUBSTRING().
Demo fiddle

Familiar function of PATINDEX in mysql for Postgresql

Is there any familiar function for PATINDEX of mysql for postgresql. I'm trying to make a sql like this in postgres.
SELECT PATINDEX('%schools%', 'W3Schools.com');
which throw an error:
no function matches the given name and argument types. you might need
to add explicit type casts
To be more detailed, I'm trying to get seperate number part and string part of a string in Postgresql. I found example like this:
SELECT Section
FROM dbo.Section
ORDER BY LEFT(Section, PATINDEX('%[0-9]%', Section)-1), -- alphabetical sort
CONVERT(INT, SUBSTRING(Section, PATINDEX('%[0-9]%', Section), LEN(Section))) -- numerical
There are two ways to implement this, the example as below:
postgres=# select strpos('W3Schools.com','Schools');
strpos
--------
3
(1 row)
postgres=# select position('Schools' in 'W3Schools.com');
position
----------
3
(1 row)
postgres=# select regexp_matches('hahahabc123zzz', '(abc)(123)');
regexp_matches
----------------
{abc,123}
postgres=# select array_to_string(regexp_matches('hahahabc123zzz', '(abc)(123)'),' ');
array_to_string
-----------------
abc 123
postgres=# select (regexp_matches('hahahabc123zzz', '(abc)(123)'))[1] as a, (regexp_matches('hahahabc123zzz', '(abc)(123)'))[2] as b;
a | b
-----+-----
abc | 123
(1 row)
Do you want this?
And you can get all functions of string process here: https://www.postgresql.org/docs/10/functions-string.html
Can you try POSITION() function:
SELECT POSITION('schools' in 'W3Schools.com');

select distinct values of a replaced selected result

Good day all.
I'm facing a little problem with a mySql query. let's assume we have a table with a coulmn in which the values are pairs, but unified in the same field, so something like this:
id | serviceName
----+-------------
1 | foo - bar
2 | foo - doo
3 | foo - tep
4 | bee - bar
5 | bee - blo
I would like to select distinct the first part of serviceName, in this case foo, bee.
the desired output should be:
foo
bee
in the resultset.
what I've thought right now is something about making a SELECT DISTINCT a FROM REPLACE ( (SELECT serviceName as a FROM tableName), ' - ***', '')
but i'm not really sure if it is possible, and how to make it. I only would like to select the first part of the field, and I would like to take only distinct vlaues of it... it is possible? I need a right direction pointing,, I can make researches by my self.
thanks in advance.
Assuming that you always want to split on a dash -, this should work for you.
SELECT DISTINCT LEFT(serviceName, LOCATE('-', serviceName) - 2) FROM tableName;
SQLFiddle
IS this what you are looking at ?
select substring_index(serviceName,'-',1) as `first_part`
from test
group by `first_part`
DEMO

Count the frequency of each word

I've been trolling the internet and realize that MySQL is not the best way to get at this but I'm asking anyway. What query, function or stored procedure has anyone seen or used that will get the frequency of a word across a text column.
ID|comment
----------------------
Ex. 1|I love this burger
2|I hate this burger
word | count
-------|-------
burger | 2
I | 2
this | 2
love | 1
hate | 1
This solution seems to do the job (stolen almost verbatim from this page). It requires an auxiliary table, filled with sequential numbers from 1 to at least the expected number of distinct words. This is quite important to check that the auxiliary table is large enough, or results will be wrong (showing no error).
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(maintable.comment, ' ', auxiliary.id), ' ', -1) AS word,
COUNT(*) AS frequency
FROM maintable
JOIN auxiliary ON
LENGTH(comment)>0 AND SUBSTRING_INDEX(SUBSTRING_INDEX(comment, ' ', auxiliary.id), ' ', -1)
<> SUBSTRING_INDEX(SUBSTRING_INDEX(comment, ' ', auxiliary.id-1), ' ', -1)
GROUP BY word
HAVING word <> ' '
ORDER BY frequency DESC;
SQL Fiddle
This approach is as inefficient as one can be, because it cannot use any index.
As an alterative, I would use a statistics table that I would keep up-to-date with triggers. Perhaps initialise the stats table with the above.
Something like this should work. Just make sure you don't pass in a 0 length string.
SET #searchString = 'burger';
SELECT
ID,
LENGTH(comment) - LENGTH(REPLACE(comment, #searchString, '')) / LENGTH(#searchString) AS count
FROM MyTable;

Using concat in where conditions, good or bad?

A simple quiz:
Probably many guys know this before,
In my app there is a query in which Im using concat in where condition like this,
v_book_id and v_genre_id are 2 variables in my procedure.
SELECT link_id
FROM link
WHERE concat(book_id,genre_id) = concat(v_book_id,v_genre_id);
Now, I know there is a catch/bug in this, which will occur only twice in your lifetime. Can you tell me what is it?
I found this out yesterday and thought I should make a noise about all others practicing this.
Thanks.
Let's have a look
WHERE concat(book_id,genre_id) = concat(v_book_id,v_genre_id);
as opposed to
WHERE book_id = v_book_id AND genre_id = v_genre_id;
There. The second solution is
faster (optimal index usage)
easier to write (less code)
easier to read (what on earth was the author thinking to concatenate numbers???)
more correct (as Alnitak also stated in the question's comments). check out this sample data:
book_id | genre_id
1 | 12
11 | 2
Now add (or concat) v_book_id = 1 and v_genre_id = 12 and see how you'll get funny results with your concat() query
Note, some databases (including MySQL) allow operations on tuples, which may be what the clever author of the above really intended to do:
WHERE (book_id, genre_id) = (v_book_id, v_genre_id);
A working example of such a tuple predicate:
SELECT * FROM (
SELECT 1 x, 2 y FROM DUAL UNION ALL
SELECT 1 x, 3 y FROM DUAL UNION ALL
SELECT 1 x, 2 y FROM DUAL
) a
WHERE (x, y) = (1, 2)
Note, some databases will need extra parentheses around the right-hand side tuple : ((1, 2))