This question already has answers here:
Query with multiple values in a column
(4 answers)
Closed 2 years ago.
first, here is how the mysql data looks like:
"group" column in "table_a"
---------------
user1 = 123,456,789
user2 = 789,897,12
user3 = 789
user4 = 4789,123,456
---------------
I am trying to return all users who have "789" in their group column field.
I have:
SELECT * from table_a WHERE group LIKE %789%
this query returns user1,user2,user3,user4 (user4 should not be part of the results)
and:
SELECT * from table_a WHERE group LIKE %789%
only returns user3
How can I return only user1, user2 and user3?
Obviously your query is missing single quotes around the right operand of like:
where grp like '%789%'
However please note that this is not a reliable to check if a value belongs to a comma-separated list, since it would partially match on any value. If your list is like '123,45,67890', then the like expression would match, while you probably don't want that.
I would recommend find_in_set():
where find_in_set('789', grp)
Finally: you should not have a data model where multiple numbers are stored in a single string columns. Instead, you should have another table, where each value is stored on a separate row. More about this can be read in this famous SO question.
Note: group is a language keyword, hence not a good choice for a column name; I renamed it to grp in the above code snippets;
Related
This question already has answers here:
Is storing a delimited list in a database column really that bad?
(10 answers)
Closed 1 year ago.
I have a MySQL table that contains books information. Part of that information is a special character (^) separated list of values that corresponds to the book names. I'm having some problems getting the correct information out of the database. Table looks like
id OwnedBooks CustomerID
1 Harry^Two States^Tintin 101
2 Harry Potter^Tintin 290
3 Harry Prizoner of Azhaban 278
So when I search for 'Harry' in the ownedbooks column, I should get only one record i.e. (record id=1)
My query looks like below
SELECT * FROM books where ownedbooks like '%Harry%'
This query return all the records as I have used like, but I wanted to match the exact string with (^) as a separation.
When I search for 'Harry Potter' it should return the second record i.e (record id=2)
If you want to match a book named exactly "Harry" then you may use the following LIKE logic:
SELECT *
FROM books
WHERE ownedbooks LIKE '%^Harry^%' OR -- appears in the middle of the list
ownedbooks LIKE 'Harry^%' OR -- appears in the beginning of the list
ownedbooks LIKE '^Harry'; -- appears in the end of the list
You would be making a good design decision to move away from storing ^ delimited data in your table. Instead, get each book title onto a separate record.
This question already has answers here:
SQL query to count number of times certain values occur in multiple rows
(5 answers)
Closed 4 years ago.
SELECT firstname, lastname, id
FROM contact
WHERE id IN
(SELECT contactid
FROM taglist
WHERE contactid IN
(SELECT contactid
FROM customerlist
WHERE companyid = 1) AND (tagid = 1 OR tagid = 4))
I have the query above where there is a single table that has a userid and a tag id. Each user can have multiple tags that are listed as separate entries on this table.
I need to be able to select only users with two or more specified tags. I thought the above query would do this, but it is returning every user with either tag 1 or tag 4.
If I change it to this: (tagid = 1 AND tagid = 4)) I get 0 results because it is only looking at each individual entry, and no entry has more than one tag per user.
This example only has two tags selected, but the goal here is to allow the end user to be able to select any number of available tags and only show results where the user matches all selected tags.
I don't have any way to know a specific number of tags that are going to be selected to match on. Currently there are 20 available tags, and clients can add their own tags if they wish.
So how do I accomplish this? I am very new to SQL queries, and not very familiar with joins yet so I am thinking this is going to have something to do with it, but I don't know. Any nudges in the right direction would be greatly appreciated.
You can get contacts with the two tags by doing:
SELECT contactid
FROM taglist
WHERE tagid IN (1, 4)
GROUP BY contactid
HAVING COUNT(*) = 2;
The rest of your query is doing other stuff not mentioned in your question, so it is unclear what you really want. Obviously, you can use this as a subquery to get full contact information.
Apologies for the title as I'm a bit unsure how to phrase this myself so hopefully an example might help.
I've got a MySQL table that holds questions
question_id, PK Int
text - Text
I also have a table called value that looks like this
value_id, PK Int
value - varchar
I think I might need a mapping table for this along the lines of
question_to_value
question_id int
value_id int
Though if my example looks like I don't need one then I can change the structure
Basically, given a single or multiple value_ids I want to pick the question that should be asked
so if I am given value_ids 1,2 I should have a unique question_id relating to those ids in the database. Given a value_id of 3 there should be a different question_id, and an input of value_ids (1,2,3) or 1,3 should again retrieve unique question_ids for both permutations.
I'm struggling with how I should go about it. Should I use a) a sort of joining table for this, and b) Most efficient way of querying it.
My initial thought it to have a question_to_value table that holds a question_id and value_id on a 1-1 basis, then doing the following
select question_id from question WHERE value_id in (?,?,?) but i'm not sure if this is the optimal way to structure this. Especially as the trouble is using the 'IN' query above if I'm just given the value_id of 1, it would actually bring back all the questions where value_id '1' is the only or part of the group of values to product a particular question. e.g
question_id 1 maps to value 1
question_id 2 maps to values of 1 and 2.
my in statement would bring back question_ids 1 and 2 for a value_id of 1 when I only want question_id 1 as it should match all criteria.
Any ideas on how I should structure this?
*** editing I'm trying to come up with another way of phrasing this to avoid confusion so hopefully the following will help
consider I have 4 'questions'
a
b
c
d
If I'm given an input of 1 I only want to retrieve a.
If I'm given 2 inputs of 1 and 2 I only want to retrieve b.
If I'm given 3 inputs of 1,2,3 I only want to retrieve c.
If I'm given 2 inputs of 1 and 3 I only want to retrieve d.
I'm trying to break the problem apart into component parts to define the question in a way that can be expressed in code.
I'm working on the idea that the proper question must match two rules:
The question must have an entry for each of the input values
The question must not have entries for any other input value
First, consider a query that returns all the value ids for the inputs.
SELECT value_id from values where `value` IN <inputs>
I don't know what language you are using, so I can't tell you how to build the inputs list. In php, it would be something like:
"('" . implode("','" $inputs) . "')"
to properly wrap each option in quotes (assuming the values don't also have quotes, but that's a separate, language-specific problem to solve).
Now it is simple to use that query to create a query that returns questions that have ANY of the input values:
SELECT question_id
FROM mapping_table
WHERE value_id IN (SELECT value_id from values where `value` IN <inputs>)
Finally, we can tweak that query to only return the question_ids with the right number of matches. We want one row for each question, and we only want questions that match all the values:
SELECT question_id
FROM mapping_table
WHERE value_id IN (SELECT value_id from values where `value` IN <inputs>)
GROUP BY question_id
HAVING COUNT(question_id) = <number of inputs>
That will give you a list of question_ids that match constraint 1 above. It will not test for constraint 2 in every case; if the input is (1,2) then this will match the question for (1,2) and the question for (1,2,3).
However, if you only get one row back from this query, there is no need to filter that list with the second query.
If you did get more than one match for the above, the second query is pretty simple - it's similar to the above query but with a different WHERE clause. This will get all the mapping table entries for the ids from the first query, and match the ones that don't have any extras:
SELECT question_id
FROM mapping_table
WHERE question_id IN <ids from first query>
GROUP BY question_id
HAVING COUNT(question_id) = <number of inputs>
You could combine the two queries, but unless performance is an issue, I'd keep them separate to make things easier to maintain.
NOTE: there is nothing here to constrain your data to make sure it is valid. In other words, there's nothing to prevent two questions from matching (1,2) when the questions are added to the database.
I have a column holds a comma-separated values.
1,2,3
4,6,7
2,3,8
12234,5467,232445,232455,11223
With given criteria of array (e.g., 1,4,9),
How can I select rows whose value contains any of given?
I mean when I am given with 1,4,9, I need to select
1,2,3 -- has 1
4,6,7 -- has 4
UPDATE
I have a table who has a column of comma-separated values of other entity's primary keys.
I understand the reason why the original table designer did this. The other entity actually resides in other database which means not joinable. Or he or she just wanted to do like this.
The STUDENT table
id name classes
---------------------------
1 John 1,2,3
2 Jane 2,8,233423423
The Criteria
With given comma-separated class numbers, find students who is attending any of them.
given: 1 -> select John
given: 233423423 -> select Jane
given: 1,233423423 -> select Both
You can use dynamic template for regular expression. For example:
SET #Criteria='1,4,9';
SELECT `name`
FROM STUDENT
WHERE STUDENT.classes REGEXP concat('(^|,)(', REPLACE(#Criteria, ',', '|'), ')(,|$)');
If you have an input 1,4,9 and you have to find rows where any of 1, 4, or 9 occur in a comma-separated list?
SELECT ...
FROM MyTable
WHERE FIND_IN_SET(1, mycolumn)
OR FIND_IN_SET(4, mycolumn)
OR FIND_IN_SET(9, mycolumn)
See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_find-in-set for information about this function.
This should illustrate to you that storing comma-separated lists is not a good idea for a relational database, when you want to treat the elements of the list as discrete values.
See also my answer to Is storing a delimited list in a database column really that bad?
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Mysql WHERE problem with comma-separated list
I have the next info in a table
name categories
------ -----------
John 1,4
Jim 4,1
JAck 4,1
between other.
I want to select all the rows that pertain to category 4, but this statement..
SELECT name, categories
FROM `mytable`
WHERE 4 IN (categories)
returns only "Jim" and "Jack" but not "John". What am I doing wrong?
Edit: Sadly I cant change the structure of the table. I need to use that comma-list style
I am not sure why you are storing a comma separated list in a single column. But it you cannot change the table structure, you will want to use LIKE to compare the data:
select name, categories
from yourtable
where categories like '%4%'
See SQL Fiddle with Demo
Or you can use the FIND_IN_SET function:
select name, categories
from yourtable
where FIND_IN_SET(4,categories) > 0
See SQL Fiddle with Demo
My suggestion would be to change your table to not store your data in this comma-separated format, it will cause nothing but problems.