Separating comma broken words in PHP and selecting extra information - php

I've been trying to look into this for a while now but can't find an answer that explains the coding properly. Basically I have a mysql table with 'connections' relevant to a user. These connections are separated with a comma:
connection1, connection2, connection3, connection4, etc
What I need to do is to separate each one into an array like so:
$connection1
$connection2
$connection3
$connection4
Then for each of these I need to be able to select sertain information from a different table, so for example:
(SELECT name,id FROM users WHERE username = (all of the connections above))
Could any of you let me kow how this would be possible? Thank you

You can use FIND_IN_SET to do a JOIN, or you can join against a table of integers and use that with Substring_index to get the values from the CSV string
Normally a comma separated list in a database is the sign of poor design. Better to split them off into another table, with one row for each item in the comma separated list.
EDIT - Example of how to do it using a table of integers:-
SELECT name,id
FROM users a
INNER JOIN (SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(concat(Connection, ','), ',', aCnt), ',', -1) AS aConnection
FROM Connections
CROSS JOIN (
SELECT a.i+b.i*10+c.i*100 + 1 AS aCnt
FROM integers a, integers b, integers c) Sub1
WHERE (LENGTH(Connection) + 1 - LENGTH(REPLACE(Connection, ',', ''))) >= aCnt) Sub2
ON a.username = Sub2.aConnection
This relies on a table called integers with a single column called i, with 10 rows with the values 0 to 9. You can cross join this against itself to get a range of numbers. In this case from 0 to 999, then limited by the number of commas in the field you are splitting up. This value is then used to find the commas for SUBSTRING_INDEX to split the string up.

It is simple. Use explode function of php.
$text= "connection1, connection2, connection3, connection4";
$res= explode(",",$text);
foreach($res as $i=>$id)
{
echo $res[$i];
}

Related

Why GROUP_CONCAT add coma separated when used in 1 column but not if use multiple columns?

I have 1 table with 6 columns (id, username, start, end, flag, timestamp) and I am trying to use GROUP_CONCAT to concatenate the columns.
Everything works fine except that I have no separator for the columns.
SELECT GROUP_CONCAT(start, end, flag SEPARATOR ';') FROM time;
The result is the following:
15531696461553177094End Time;15531779481553177962End Time;15531779561553177960End Lunch
What we see here is the columns from 2 tables that have the same structure and are concatenated using the separator ;
Before in a different server, the columns were divided by , so the result was:
1553169646,1553177094,End Time;1553177948,1553177962,End Time;1553177956,1553177960,End Lunch
I don't know what is different in this new server as I have no access in the old one.
Did anyone face something like this before? I am stuck in this as the following code of my script is based on the previews output. I would like to have the same output:
1553169646,1553177094,End Time;1553177948,1553177962,End Time;1553177956,1553177960,End Lunch
You can write as to concat per record column values and switching record add ; at the switching of every record,
SELECT GROUP_CONCAT(CONCAT_WS(',',start, end, flag) SEPARATOR ';') FROM time;
CONCAT_WS() stands for Concatenate With Separator and is a special form of CONCAT().
Firstly, Concat() the columns using comma. Then, you can do Group_Concat():
SELECT GROUP_CONCAT(CONCAT(start, ',', end, ',', flag) SEPARATOR ';') FROM time;

mysql query explode with two table join

my sql query
SELECT
team.id,
team.atitle,
team.etitle,
team.cup_id,
team.logo,
team.modarb,
team.count_id,
team.link AS tlink,
country.atitle AS name,
country.etitle AS ename,
cup.id AS catid,
cup.link,
cup.description,
cup.name AS cupname
FROM cup LEFT JOIN team ON (cup.id IN (". implode(', ', 'team.cup_id') ."))
LEFT JOIN country ON (country.id = team.count_id)
where cup.id='5'
row team.cup_id look like this 5, 4, 3,
need know how to use implode in mysql query
You should fix your data structure so you are not storing lists of ids as a string. Doing so is wrong, wrong, wrong:
It is wrong to store numbers as strings.
It is wrong to have ids in a table without properly declared foreign key references.
It is wrong to store lists in a single column, when SQL offers a great method for storing lists: a table.
Just in case you cannot fix the data structure, you can do:
FROM cup LEFT JOIN
team
ON find_in_set(cup.id, team.cup_id) > 0 LEFT JOIN
country
ON (country.id = team.count_id)
I only offer this as a stop-gap until you fix the data to be SQLish in form.

best-result search using multiple tags on a column that stores values as CSV

I have tags stored in a column that are separated by commas. I'm trying to create a best match search.
I do not want to match partial strings, so I've added a comma at the beginning and end of each string like so ,apple,orange,banana, so that I can look up using LIKE '%,apple,% and it doesn't care what the position is.
how do I get the list of ids in order based on the best match compared to the search tags
is there a pure mySQL way of doing this?
Right now I'm dealing with it in PHP by looping through each tag and building out an array that counts the number of matches. 99% of time there will be a max of up to 5 tags being searched.
also in my case I'm using two tag fields/columns that have separate tag categories
SQL FIDDLE DEMO
Without a schema I imagine you need something like this.
SELECT
t.tagID,
t.tagText,
num_match.num_appear,
((LENGTH(`tagText`) - LENGTH(REPLACE(`tagText`, ',', '')))/LENGTH(',')) - 1 as wordnumber,
(num_match.num_appear / (((LENGTH(`tagText`) - LENGTH(REPLACE(`tagText`, ',', '')))*1.0/LENGTH(',')) - 1)) *100 as porcentage
FROM
tblTAG t left join
(SELECT tagID, count(tagID) as num_appear
FROM
(( SELECT tagID
FROM tblTAG
WHERE tagText LIKE '%,apple,%'
) union all
( SELECT tagID
FROM tblTAG
WHERE tagText LIKE '%,banana,%'
)) as result
GROUP BY tagID
) as num_match
ON t.tagID = num_match.tagID

fetch the comma separate field in mysql query

My table id and skillid values are
1=>3
2 =>5
3 =>5,6,8
I have tried the query to fetch the value from my table
SELECT * FROM mytable WHERE skillid IN ('3', '5');
But i am getting only two rows, that was first and second row.
But i need the result three rows.
Thanks in advance.
The 'IN' comparison operator works like an equality operator. This:
expr IN ('3','5')
is equivalent to:
( expr = '3' OR expr = '5' )
That should be sufficient to explain why your query is not returning what you expect.
If your table has a character column that contains a comma separated list, like this:
id skill_id_list
-- -------------
1 3
2 5
3 5,6,8
Then one option, to search for a particular id value in the list is to make use of the MySQL FIND_IN_SET function. For example:
SELECT t.id
, t.skill_id_list
FROM mytable t
WHERE FIND_IN_SET('3', t.skill_id_list)
OR FIND_IN_SET('5', t.skill_id_list)
The MySQL FIND_IN_SET function is documented here:
https://dev.mysql.com/doc/refman/5.5/en/string-functions.html#function_find-in-set
Of course, that's only one option. There are several other ways to get an equivalent result.
If there are no spaces in the skill_id_list column, then another option is to use a LIKE operator, but taking care to handle the edge cases.
There are four cases you would need to check for the id value appearing:
as the only one in the list
at the beginning of the list
in the middle of the list
at the end of the list
To explicitly handle those four cases, you could check each one, for example:
WHERE skill_id_list LIKE '3' -- only one in list
OR skill_id_list LIKE '3,%' -- beginning of list
OR skill_id_list LIKE '%,3,%' -- middle of list
OR skill_id_list LIKE '%,3' -- end of list
Or, another way to approach that is to turn all of those cases into the single "middle of the list" by just appending a comma to the beginning and end of the list, and then doing a single check, for example:
WHERE CONCAT(',',skill_id_list,',') LIKE '%,3,%'
Note that spaces embedded in the list could cause a row not to match. The MySQL REPLACE function can be used to remove spaces, replacing all spaces with an empty string, something like this:
WHERE CONCAT(',',REPLACE(skill_id_list,' ',''),',') LIKE '%,3,%'
NOTE
The preceding attempts to to answer the question you asked. The following addresses a fundamentally different (though closely related) issue, concerning the relational dataa model and normalization.
Repeating attributes in normalized relational model are represented in separate table. That's the normative relational model. We typically avoid storing comma separated lists, and instead implement a separate table to store the repeating attributes.
For example, if a job has multiple skills, we would typically create another table to hold the list of job skills:
CREATE TABLE job
( id INT NOT NULL PRIMARY KEY
, description VARCHAR(10)
);
CREATE TABLE job_skill
( job_id INT NOT NULL COMMENT 'FK ref job.id'
, skill_id INT NOT NULL COMMENT ''
, PRIMARY KEY (job_id, skill_id)
, FOREIGN KEY job_skill_FK1 (job_id) REFERENCES job (id)
);
We'd represent the data in your model as five separate rows:
job_skill
job_id skill_id
------ --------
1 3
2 5
3 5
3 6
3 8
That's the normative pattern.
To get back a list of job ids that require skills 3 or 5:
SELECT s.job_id
FROM job_skill s
WHERE s.skill_id in (3,5)
GROUP BY j.job_id
To get back a list of job ids that require skills 3 and 5, there's several ways to do that, for example:
SELECT s.job_id
FROM job_skill s
ON s.job_id = t
WHERE s.skill_id in (3,5)
GROUP BY j.job_id
HAVING COUNT(DISTINCT s.skill_id) = 2
If it's more convenient for your use case to get back a comma separated list as a string, you can use the GROUP_CONCAT aggregate function:
SELECT j.id AS job_id
, GROUP_CONCAT(s.skill_id ORDER BY s.skill_id) AS skill_id_list
FROM job j
LEFT
JOIN job_skill s
ON s.job_id = j.id
WHERE ...
ORDER BY ...
Please check
SELECT * FROM mytable WHERE 5 IN (skillid) OR 3 IN (skillid);
SELECT * FROM mytable WHERE skillid LIKE '3%' OR skillid LIKE '5%';
Definetly this is NOT the way to do it...
YOU SHOULD NORMALIZE your table to avoid this kind of problems
This is not good practice, you should normalize your table table, but REGEXP would be helpful
Please try this way
SELECT * FROM mytable WHERE
skillid REGEXP '[[:<:]]3[[:>:]]' OR skillid REGEXP '[[:<:]]5[[:>:]]'

Comma separated values in MySQL "IN" clause

I have a column in one of my table where I store multiple ids seperated by comma's.
Is there a way in which I can use this column's value in the "IN" clause of a query.
The column(city) has values like 6,7,8,16,21,2
I need to use as
select * from table where e_ID in (Select city from locations where e_Id=?)
I am satisfied with Crozin's answer, but I am open to suggestions, views and options.
Feel free to share your views.
Building on the FIND_IN_SET() example from #Jeremy Smith, you can do it with a join so you don't have to run a subquery.
SELECT * FROM table t
JOIN locations l ON FIND_IN_SET(t.e_ID, l.city) > 0
WHERE l.e_ID = ?
This is known to perform very poorly, since it has to do table-scans, evaluating the FIND_IN_SET() function for every combination of rows in table and locations. It cannot make use of an index, and there's no way to improve it.
I know you said you are trying to make the best of a bad database design, but you must understand just how drastically bad this is.
Explanation: Suppose I were to ask you to look up everyone in a telephone book whose first, middle, or last initial is "J." There's no way the sorted order of the book helps in this case, since you have to scan every single page anyway.
The LIKE solution given by #fthiella has a similar problem with regards to performance. It cannot be indexed.
Also see my answer to Is storing a delimited list in a database column really that bad? for other pitfalls of this way of storing denormalized data.
If you can create a supplementary table to store an index, you can map the locations to each entry in the city list:
CREATE TABLE location2city (
location INT,
city INT,
PRIMARY KEY (location, city)
);
Assuming you have a lookup table for all possible cities (not just those mentioned in the table) you can bear the inefficiency one time to produce the mapping:
INSERT INTO location2city (location, city)
SELECT l.e_ID, c.e_ID FROM cities c JOIN locations l
ON FIND_IN_SET(c.e_ID, l.city) > 0;
Now you can run a much more efficient query to find entries in your table:
SELECT * FROM location2city l
JOIN table t ON t.e_ID = l.city
WHERE l.e_ID = ?;
This can make use of an index. Now you just need to take care that any INSERT/UPDATE/DELETE of rows in locations also inserts the corresponding mapping rows in location2city.
From MySQL's point of view you're not storing multiple ids separated by comma - you're storing a text value, which has the exact same meaing as "Hello World" or "I like cakes!" - i.e. it doesn't have any meaing.
What you have to do is to create a separated table that will link two objects from the database together. Read more about many-to-many or one-to-many (depending on your requirements) relationships in SQL-based databases.
Rather than use IN on your query, use FIND_IN_SET (docs):
SELECT * FROM table
WHERE 0 < FIND_IN_SET(e_ID, (
SELECT city FROM locations WHERE e_ID=?))
The usual caveats about first form normalization apply (the database shouldn't store multiple values in a single column), but if you're stuck with it, then the above statement should help.
This does not use IN clause, but it should do what you need:
Select *
from table
where
CONCAT(',', (Select city from locations where e_Id=?), ',')
LIKE
CONCAT('%,', e_ID, ',%')
but you have to make sure that e_ID does not contain any commas or any jolly character.
e.g.
CONCAT(',', '6,7,8,16,21,2', ',') returns ',6,7,8,16,21,2,'
e_ID=1 --> ',6,7,8,16,21,2,' LIKE '%,1,%' ? FALSE
e_ID=6 --> ',6,7,8,16,21,2,' LIKE '%,6,%' ? TRUE
e_ID=21 --> ',6,7,8,16,21,2,' LIKE '%,21,%' ? TRUE
e_ID=2 --> ',6,7,8,16,21,2,' LIKE '%,2,%' ? TRUE
e_ID=3 --> ',6,7,8,16,21,2,' LIKE '%,3,%' ? FALSE
etc.
Don't know if this is what you want to accomplish. With MySQL there is feature to concatenate values from a group GROUP_CONCAT
You can try something like this:
select * from table where e_ID in (Select GROUP_CONCAT(city SEPARATOR ',') from locations where e_Id=?)
this one in for oracle ..here string concatenation is done by wm_concat
select * from table where e_ID in (Select wm_concat(city) from locations where e_Id=?)
yes i agree with raheel shan .. in order put this "in" clause we need to make that column into row below code one do that job.
select * from table where to_char(e_ID)
in (
select substr(city,instr(city,',',1,rownum)+1,instr(city,',',1,rownum+1)-instr(city,',',1,rownum)-1) from
(
select ','||WM_CONCAT(city)||',' city,length(WM_CONCAT(city))-length(replace(WM_CONCAT(city),','))+1 CNT from locations where e_Id=? ) TST
,ALL_OBJECTS OBJ where TST.CNT>=rownum
) ;
you should use
FIND_IN_SET Returns position of value in string of comma-separated values
mysql> SELECT FIND_IN_SET('b','a,b,c,d');
-> 2
You need to "SPLIT" the city column values. It will be like:
SELECT *
FROM table
WHERE e_ID IN (SELECT TO_NUMBER(
SPLIT_STR(city /*string*/
, ',' /*delimiter*/
, 1 /*start_position*/
)
)
FROM locations);
You can read more about the MySQL split_str function here: http://blog.fedecarg.com/2009/02/22/mysql-split-string-function/
Also, I have used the TO_NUMBER function of Oracle here. Please replace it with a proper MySQL function.
IN takes rows so taking comma seperated column for search will not do what you want but if you provide data like this ('1','2','3') this will work but you can not save data like this in your field whatever you insert in the column it will take the whole thing as a string.
You can create a prepared statement dynamically like this
set #sql = concat('select * from city where city_id in (',
(select cities from location where location_id = 3),
')');
prepare in_stmt from #sql;
execute in_stmt;
deallocate prepare in_stmt;
Ref: Use a comma-separated string in an IN () in MySQL
Recently I faced the same problem and this is how I resolved it.
It worked for me, hope this is what you were looking for.
select * from table_name t where (select (CONCAT(',',(Select city from locations l where l.e_Id=?),',')) as city_string) LIKE CONCAT('%,',t.e_ID,',%');
Example: It will look like this
select * from table_name t where ',6,7,8,16,21,2,' LIKE '%,2,%';

Categories