I've a db table named "users" which has a column named "alerts". The alert column has the comma separated data in following sequence;
UserA -> 2314|1,2315|1,2316|3
UserB -> 4235|2,2315|1,2314|3
UserC -> 342|5,2314|1,2316|3
Where if I split the comma and then slash separated value then;
2314 = pid
1 = uid
If I want to search all users having specific pid e.g. 2314 and to list them OR fetch them all, how and what SQL query I should have to use?
On the face of it, you would search for ',2314|', but the problem is that numbers at the start of the value don't have a preceding comma.
There are 3 ways to solve it.
Handle the start case and middle case separately:
select * from users
where alerts like '2314|%'
or alerts like '%,2314|%'
Combine the cases by adding a comma to the beginning of the value to make it look like a middle case:
select * from users
where concat(',', alerts) like '%,2314|%'
Use a regular expression to combine the cases:
select * from users
where alerts rlike '(^|,)2314\|'
It would be better to redesign your tables to break out a new table to handle the many-to-many relationship you have shoehorned into one column.
Related
I have 5 users which have a column 'shop_access' (which is a list of shop IDs eg: 1,2,3,4)
I am trying to get all users from the DB which have a shop ID (eg. 2) in their shop_access
Current Query:
SELECT * FROM users WHERE '2' IN (shop_access)
BUT, it only returns users which have shop_access starting with the number 2.
E.g
User 1 manages shops 1,2,3
User 2 manages shops 2,4,5
User 3 manages shops 1,3,4
User 4 manages shops 2,3
The only one which will be returned when running the IN Clause is User 2 and User 4.
User 1 is ignored (which it shouldn't as it has number 2 in the list) as it does not start with the number 2.
I'm not in a position to currently go back and change the way this is set up, eg convert it to JSON and handle it with PHP first, so if someone can try to make this work without having to change the column data (shop_access) that would be ideal.
A portable solution is to use like:
where concat(',', shop, ',') like '%,2,%'
Or if the value to search for is given as a parameter:
where concat(',', shop, ',') like concat('%,', ?, ',%')
Depending on your database, there may be neater options available. In MuSQL:
where find_in_set('2', shop)
That said, I would highly recommend fixing your data model. Storing CSV data in a database defeats the purpose of a relational database in many ways. You should have a separate table to store the user/shop relations, which each tuple on a separate row. Recommended reading: Is storing a delimited list in a database column really that bad?.
Also, you might want to consider using REGEXP here for an option:
SELECT *
FROM users
WHERE shop_access REGEXP '[[:<:]]2[[:>:]]';
-- [[:<:]] and [[:>:]] are word boundaries
SELECT * FROM users WHERE (shop_access = 2) OR (shop_access LIKE "2,%" OR shop_access LIKE "%,2,%" OR shop_access LIKE "%,2")
I have a query i have been working on trying to get a specific set of data, join the comments in duplicate phone numbers of said data, then join separate tables based on a common field "entry_id" which also happens to be the number on the end of the word custom_ to pull up that table.
table named list and tables containing the values i want to join is custom_entry_id (with entry_id being a field in list in which i need the values of each record to replace the words in order to pull up that specific table) i need entry_id from the beginning part of my query to stick onto the end of the word custom for every value my search returns to get the fields from that custom table designated for that record. so it will have to do some sort of loop i guess? sorry like i said I am at a loss at this point
this is where i am so far:
SELECT * ,
group_concat(comments SEPARATOR '\r\n\r\n') AS comments_combined
FROM list WHERE `status` IN ("SALEA","SALE")
GROUP BY phone_number
//entry_id is included in the * as well as status
// group concat combines the comments if numbers are same
i have also experimented on test data with doing a full outer join which doesnt really exist. i feel if you can solve the other part for me i can do the joining of the data with a query similar to this.
SELECT * FROM test
LEFT JOIN custom_sally ON test.num = custom_sally.num
UNION
SELECT * FROM test
RIGHT JOIN custom_sally ON test.num = custom_sally.num
i would like all of this to appear with every field from my list table in addition to all the fields in the custom_'entry_id' tables for each specific record. I am ok with values being null for records that have different custom fields. so if record 1 has custom fields after the join of hats and trousers and record 2 has socks and shoes i realize that socks and shoes for record 1 will be null and hats and trousers for record 2 will be null.
i am doing all this in phpmyadmin under the SQL tab.
if that is a mistake please advise as well. i am using it because ive only been working with SQl for a few months. from what i read its the rookie tool.
i might be going about this all wrong if so please advise
an example
i query list with my query i get 20,000 rows with columns like status, phone_number, comments, entry_id, name, address, so on.
now i want to join this query with custom fields in another table.
the problem is the custom tables' names are all linked to the entry_id.
so if entry_id is 777 then the custom table fields are custom_777
my database has over 100 custom tables with specials fields for each record depending on its entry_id.
when i query the records I don't know how to join the custom fields that are entry_id specific to the rest of my data.i will pull up some tables and data for a better example
this is the list table:
this is the custom_"entry_id"
Full Outer Join in MySQL
for info on full outer joins.
I have a database table that contains person's fingerprints (template column here), each person can introduce 2 fingers, so the same person must have 2 records.
Here is the table :
Person with ID '275' have 2 records, each for a single finger.
Now I am using Talend to create a table so I can merge every two fingerprints in a single one, I mean row n°37 and 38 will be in single row and template column will be concatenated to have only one person_id
You can try something like this:
INSERT INTO newtable (ids, person_id_integer)
SELECT CONCAT(finger1.id, "|", finger2.id), finger1.person_id_integer
FROM oldtable finger1, oldtable finger2
where finger1.person_id_integer = finger2.person_id_integer
and finger1.id <> finger2.id
Of course, depnds on how you want to store the new data
:)
I found a solution :
I added the same table twice as an input and output like shown in this photo and first fetched it with this query :
select FP_ID, FP_DEVICE, group_concat(FP_FINGER_PRINT SEPARATOR ''),FP_EMPLOYEE_ID
from t_finger_print GROUP BY FP_EMPLOYEE_ID;
I have a table on my database that lists different sections to show. We only want to show the sections if the user ID is inside a column of the database called 'userAccess' which will have a comma seperated list of the users who can see it.
Example row
id section userAccess
1 editNews 1,13,15
So how can I query that out and say something like
SELECT `section` WHERE '$userID' is in `userAccess`
I tried LIKE %, but obviously that will return all 3 users if I do LIKE %1%.
SELECT `section` WHERE FIND_IN_SET('$userID', `userAccess`) != 0
You could consider moving to a groups based permissioning structure, then have a GroupAccess table, with an FK to your section and the group ID. Users would be assigned to a Group in a UserGroup link table. This provides you with a lot of flexibility (but more complexity).
Or failing that, simply have
id section userAccess
1 editNews 1
2 editNews 13
3 editNews 15
Another alternative:
SELECT `section`
FROM t
WHERE concat(',', '$userID', ',') like concat(',', `userAccess`, ',')
In other words, you can use like if you put the separator around the two strings. I offer this because it is more similar to the solution you tried and you can use the same approach in other databases.
I use mySQL and I have a members table with a BLOB 'contacts' field containing a comma separated list of other member's IDs:
TABLE members:
id_member = 1
firstname = 'John'
contacts (BLOB) = '4,6,7,2,5'
I want to retrieve all the first names in the 'contacts' list of an individual, with a single query. I tried the following:
SELECT firstname from members WHERE id_member IN ( SELECT contacts FROM members WHERE id_member = 1 );
It returns only one row, but when I try:
SELECT firstname from members WHERE id_member IN ( 4,6,7,2,5 );
It returns all the first names from the list. I can use two queries to achieve this, but I thought I'd double check if there's a way to make it work with one simple, elegant query.
Thanks for reading, any help appreciated.
Jul
That seems like a very poor table design. Is it possible to change it?
If you can't change the design then you can handle comma separated values in MySQL by using FIND_IN_SET but it won't be able to use indexes efficiently:
SELECT firstname
FROM members
WHERE FIND_IN_SET(id_member, (SELECT contacts FROM members WHERE id_member = 1))
But rather than going this route, I'd strongly recommend that if possible you normalize your database. Consider using a join table instead of a comma separated list. Then you can find the entries you need by using joins and the search will be able to use an index.
If you're using a serialized BLOB type column to store these values then you're not going to be able to do what you want. A more SQL friendly approach is to create a relationship table that can be used as part of a JOIN operation, such as a member_contacts table that has an association between one id_member value and some other.
Expanding your comma separated list into individual records is a pretty simple mechanical process.
Can you change this DB structure? The contacts field really should be a related table rather than a column. Assuming a contacts table with this structure:
id_contact
id_member
Then you would use EXISTS instead:
SELECT firstname from members m WHERE EXISTS (SELECT 1 FROM contacts c WHERE c.id_contact = m.id_member );