Mysql with regular expression - php

I have a query regarding regular expression.I have design a table which contain three column one column contain member ids which are separated by commas.I am showing you my table structure.Please follow
send_id member_id
1 1211,23,34
2 1,23
I want to select only send_id 2 data which contain member_id as 1.
this is the query that i am using
SELECT * FROM table WHERE column REGEXP '^[1]+$';
but this query giving me both row.Please help me.
With Regards
Rahul

Never store separate values in one column
Normalize your structure like
send_id member_id
1 1211
1 23
1 34
2 1
2 23
If you still want your regex, then it will be
SELECT * FROM t WHERE column REGEXP '(^|[^0-9])1([^0-9]|$)'

First, you should be normalizing your data so you're not in this horrible mess in the first place. Here's a good resource explaining normalization.
Second, I believe your problem lies with your regular expression. Try this instead:
SELECT * FROM table WHERE column REGEXP '^[1]$';
The regular expression you're using uses the [1]+ group. The + means it has to match [1] 1 or more times, hence why you're getting two rows instead of one. Removing the + means it will match [1] once.
However, that still won't fix your problem, as more than one row contains 1. This is why normalization is so important.

Having multiple values inside a column isn't a good practice for designing a DB.
You should normalize your data, i.e., put just one piece of atomic information inside each element of your table.
You can find more information regarding to this in Wikipedia:
http://en.wikipedia.org/wiki/Database_normalization

Like they have told you, perfect solution would be normalize your data, I think Alma Do Mundo answer explains it quite well.
If you want to use REGEXP anyway you have to take in account four approaches; id is the only one, id is the first, id is in the middle and id is at the end. I have use id=74 for the example:
SELECT * FROM table WHERE member_id REGEXP '(^74$|^74,|,74,|,74$)';

depending on your requirements, you should either normalize your data i.e. make 3 tables, one with the send ID, one with the member id, and one that combines the two, then you can link them up with INNER JOINS.
However, if you are going to do it that way, you can use a "WHERE member_id LIKE %1%" to pull in all the relevant fields. You'll have to use the application to filter the relevant records.
In any case, if you're not going to normalize the data you will have to use the front end to filter out the results.
An example of the inner join syntax would look like this
SELECT * FROM SendTable
JOIN Send_Member ON SendTable.send_id = Send_Member.send_id
JOIN Member ON Member.member_id = Send_Member.member_id
WHERE Member.member_id = 1;
where the schema looks like:
Sendtable:
send_Id (primary key)
...other fields
Send_Member:
send_id (primary key and foreign key to SendTable)
member_id (primary key and foreign key to member)
...any fields you might want that are relevant to the particular send table and member table link
Member:
member_id (primarykey)
...other fields

Related

Checking for value in pdo query from string [duplicate]

I need help for this problem.
In MYSQL Table i have a field :
Field : artist_list
Values : 1,5,3,401
I need to find all records for artist uid 401
I do this
SELECT uid FROM tbl WHERE artist_list IN ('401');
I have all record where artist_list fields values are '401' only, but if i have 11,401 this query do not match.
Any idea ?
(I cant user LIKE method because if artist uid is 3 (match for 30, 33, 3333)...
Short Term Solution
Use the FIND_IN_SET function:
SELECT uid
FROM tbl
WHERE FIND_IN_SET('401', artist_list) > 0
Long Term Solution
Normalize your data - this appears to be a many-to-many relationship already involving two tables. The comma separated list needs to be turned into a table of it's own:
ARTIST_LIST
artist_id (primary key, foreign key to ARTIST)
uid (primary key, foreign key to TBL)
Your database organization is a problem; you need to normalize it. Rather than having one row with a comma-separated list of values, you should do one value per row:
uid artist
1 401
1 11
1 5
2 5
2 4
2 2
Then you can query:
SELECT uid
FROM table
WHERE artist = 401
You should also look into database normalization because what you have is just going to cause more and more problems in the future.
SELECT uid
FROM tbl
WHERE CONCAT(',', artist_list, ',') LIKE '%,401,%'
Although it would make more sense to normalise your data properly in the first place. Then your query would become trivial and have much better performance.

splitting data in a table column for search

I was working with a simple mysql table in php when I came across this problem and I am wondering if there is a solution to this.
The table holds a username and his locations in a comma separated format.
id|user|locations
------------------
1 |abc | A, B, C
------------------
2 |xyz | P, Q, R
I was wondering if there was any way to write a mysql query so that it would return me a user who has location as A.
Basically if one of the values among the comma separated values match, the record should be returned.
I know it is a better way to store them as separate records, but I was just curious if such a retrieval is possible.
Thanks in advance.
Ideally, you should consider normalizing the data so you are not storing the comma separated list.
But if you cannot alter the table structure, MySQL has a FIND_IN_SET() function that can be used to return the rows that match the value you want:
select id, user, locations
from yourtable
where find_in_set('A', locations)
See SQL Fiddle with Demo
We think
the following query may help you -
SELECT * FROM table WHERE column REGEXP '(^|,)A($|,)'
You can have a useful link in -
How to query comma delimited field of table to see if number is within the field

MySQL Search for line in text

in MySQL, I have a row for each user, with a column that contains friends names separated by \n.
eg.
Friend1
Friend2
Friend3
I'd like to be able to quickly search all the users where the Friends field contains Friend2.
I've found FIND_IN_SET but that only works for commas and the data can contains commas and foreign characters.
Obviously searching with regular expressions and the such will be slow. I'm new to the whole cross referencing so I'd love some help on the best way to structure the data so that it can be found quickly.
Thanks in advance.
Edit: Ok, I forgot to mention a point that the data is coming from a
game where friends names are stored locally and there are no links to
another users ID. Thus the strings. Every time they connect I am given
a dump of their friends names which I use in the background to help match games.
The most commonly used structure for this kind of data is usually adding an extra table. I.e.
user
id,
name
email,
e.t.c.
user_friend
user_id
friend_id
Querying this is a matter of querying the tables. I.e.
List all of a users friends names:
SELECT friend_id
FROM user_friend
WHERE user_id = :theUser
Edit: Regarding OPs edit. Just storing the names is possible too. In this case the table structure would become:
user_friend
user_id
friend_name
and the query:
SELECT friend_name
FROM user_friend
WHERE user_id = :theUser
Why are you keeping friend names as text? This will be inefficient to edit uf say a user removes a friend or changes their name. That's another thing, you should store friend names by some auto_increment id key in your database. It's much faster to search for an integer than a string, especially in a very large database. You should set up a friends table which is like
Column 1: connectionid auto_increment key
Column 2: user1id int
Column 3: user2id int
Column 4: date added date
ect...
Then you can search the connection table above for all rows where user is user1id or user2id and get a list of the other users from that.
My database hasn't been filled yet so I can easily change the format and structure in which the data will be stored.
Yes, you need to normalize your database a bit. With current structure, your searches will be quite slow and consume more space.
Check out this wiki for detailed help on normalization.
You can have the friends table and users table separate and link them both by either foreign key constraint or inner joins.
The structure would be:
Users table
id: AUTO_INCRMENT PK
name
other columns
Friends table
id: AUTO_INCREMENT(not required, but good for partitioning)
UserID:
FriendsID
DateAdded
OtherInfo if required.

DB Design; or Conditional Selects with json data

I have a DB with several tables that contain basic, static ID-to-name data. 2 Columns only in each of these reference tables.
I then have another table that will be receiving data input by users. Each instance of user input will have it's own row with a timestamp, but the important columns here will contain either one, or several of the ID's related to names in one of the other tables. For the ease of submitting and retrieving this information I opted to input it as text, in json format.
Everything was going great until I realized I'm going to need to Join the big table with the little tables to reference the names to the ID's. I need to return the IDs in the results as well.
An example of what a few rows in this table might look like:
Column 1 | Column 2 | Timestamp
["715835199","91158582","90516801"] | ["11987","11987","22474"] | 2012-08-28 21:18:48
["715835199"] | ["0"] | 2012-08-28 21:22:48
["91158582","90516801"] | ["11987"] | 2012-08-28 21:25:48
There WILL be repeats of the ID#'s input in this table, but not necessarily in the same groupings, hence why I put the ID to name pairings in a separate table.
Is it possible to do a WHERE name='any-of-these-json-values'? Am I best off doing a ghetto join in php after I query the main table to pull the IDs for the names I need to include? Or do I just need to redo the design of the data input table entirely?
First of all:
Never, ever put more than one information into one field, if you want to access them seperately. Never.
That said, I think you will need to create a full N:M relation, which includes a join table: One row in your example table will need to be replaced by 1-N rows in the join table.
A tricky join with string matching will perform acceptably only for a very small number of rows, and the WHERE name='any-of-these-json-values' is impossible in your construct: MySQL doesn't "understand", that this is a JSON array - it sees it as unstructured text. On a join table, this clause comes quite naturally as WHERE somecolumn IN (1234,5678,8012)
Edit
Assuming your Column 1 contains arrays of IDs in table1 and Column 2 carries arrays of IDs in table2 you would have to do something like
CREATE TABLE t1t2join (
t1id INT NOT NULL ,
t2id INT NOT NULL ,
`Timestamp` DATETIME NOT NULL ,
PRIMARY KEY (t1id,t2id,`Timestamp`) ,
KEY (t2id)
)
(you might want to sanity-check the keys)
And on an insert do the following (in pseudo-code)
Remember timestamp
Cycle all permutations of (Column1,Column2) given by user
Create row
So for your third example row, the SQL would be:
SELECT #now:=NOW();
INSERT INTO t1t2join VALUES
(91158582,11987,#now),
(90516801,11987,#now);

Mysql commaseparated column matching from another table

I would like to select all matches from a commaseparated column in table2, where column could be like this: 0,1,2 OR 2,4,5 OR 2,5 OR 1,3,5 etc.
I have tried with:
SELECT * from table where 1,3,5 IN(SELECT commaseparated FROM table2) WHERE ..
But error on statement when using commas.
I've also tried using REGEXP but in my case i need to search for all matches within 1,3,5
How can i solve this one? :)
Can't do that in standard SQL. it's
WHERE singlevalue IN (list, of, values)
if you want to compare lists against lists, you should revamp your tables so they're properly normalized. Storing formatted data in a field basically negates the purpose of having a relational database - you can't establish relationships with the data if it's not in a format that allows relationships to be formed.
If those CSV lists were in sub-tables, you could do a very simple JOIN query to meet your specifications.

Categories