I have the following mysql table:
map_id - module_id - category_id
1 - 3 - 6
2 - 3 - 9
3 - 3 - 11
4 - 4 - 6
5 - 4 - 9
6 - 4 - 12
map_id is the primary key. I have a list of category_id in an array.
My select criteria is:
Both module_id = 3, 4 should be returned if category_id array contains 6,9.
Only module_id = 3 should be returned if category_id array contains 6,9,11
Right now if I run a simple WHERE...IN query then all the rows are selected, which is not what I want.
Edit: Actually I was looking for a more dynamic solution. Probably my question wasn't clear (it is my first one).
say I have these category_id's:
$cat = array(6,9)
If I query
"SELECT module_id FROM maptable WHERE category_id IN (".implode(',', $cat).")"
then I get rows with both module_id 3 and 4.
On the other hand, if the array is
$cat = array(6,9,11)
and I run the same query, I again get same result. But I want only rows with module_id = 3 this time.
SQL isn't really designed for a query like this, but it can be done.
SELECT module_id FROM
(SELECT module_id FROM table WHERE category_id = 6) cat_6
JOIN (SELECT module_id FROM table WHERE category_id = 9) cat_9 USING (module_id)
JOIN (SELECT module_id FROM table WHERE category_id = 11) cat_11 USING (module_id)
Make sure to have an index on category_id, module_id and a second index on module_id, category_id. Ideally you make those unique indexes.
WHERE ((category_id = 6 OR category_id=9) AND module_id=3) OR ((category_id = 6 OR category_id=9 OR category_id = 11) AND (module_id=3 OR module_id=4))
?
There's probably a simpler way of writing this, but I think you get the point :-)
when you use WHERE...IN it means 'any of in(...) value'
you can use AND instead
You could try:
SELECT * FROM `table`
WHERE (`module_id` IN(3,4) AND `category_id` IN(6,9))
OR (`module_id` IN(3) AND `category_id` IN(6,9,11))
Related
I have an existing table with millions of entries (growing) that consists of:
userid|name|etc...
1 frank ...
1 frank ...
2 joe ...
5 sam ...
1 franky ...
What I need to do is return a table of:
place|name|total
1 franky 3
2 sam 1
3 joe 1
Where total is the SUM(userid = the distinct userid).
Currently I'm doing a query to SELECT DISTINCT userid from table and then foreach returned value in php, I'm doing another query to return the name and sum(userid = userid).
As you can assume, this is very taxing and takes a long time now with all of the values. Is there any way to speed this up by doing 1 query?
i think you need
SELECT #a:=#a+1 AS `place`, name, COUNT(userid) AS `total`
FROM `your_table`, (SELECT #a:= 0) AS a
GROUP BY userid
SELECT userid, COUNT(*)
FROM some_table
GROUP BY userid
This question already has an answer here:
Select all rows that have at least a list of features
(1 answer)
Closed 9 years ago.
I have a mysql table
Table A
--------------------
item_id category_id
--------------------
1 1
1 2
1 4
2 1
2 3
Would like to make an sql query that will select all matches in an array
example:
given category_ids are 1,4 it should return only item_id 1
given category_ids are 1 it should return item_id 1 and 2
Thanks
For categories 1, 4:
SELECT item_id, COUNT(*) c
FROM TableA
WHERE category_id IN (1, 4)
GROUP BY item_id
HAVING c = 2
For category 1:
SELECT item_id, COUNT(*) c
FROM TableA
WHERE category_id IN (1)
GROUP BY item_id
HAVING c = 1
I think you should be able to see the pattern -- the HAVING clause should match the number of categories.
This assumes that item_id, category_id is unique in the table.
given category_ids are 1,4
SELECT item_id, category_id
FROM TableA
WHERE category_id IN (1, 4)
given category_ids are 1
SELECT item_id, category_id
FROM TableA
WHERE category_id IN (1)
I have a Database table in MYSQL, it looks like this:
Project_ID user_ID name
11 1 fred
11 2 rick
11 1 fred
I want to get the names in the table, but when I display it I get the same name twice because the user_ID 1 appears twice in the table. I tried to display it with GROUP BY and SUM, but I don't want to do it this way. How do I get it not to return duplicate rows?
Use DISTINCT
SELECT DISTINCT user_ID
, verschil_ma
FROM project_uren
WHERE project_ID = 11
GROUP BY user_ID
Point 1 is that should the user be assigned to the project twice?
Point 2 - Use the DISTINCT keyword to return only unique records - http://dev.mysql.com/doc/refman/5.0/en/distinct-optimization.html
SELECT DISTINCT user_ID
FROM TABLE
WHERE Project_id = 11
That will return you 1 and 2 (You won't get 1 twice)
Thanks
$results = // query
$results = array_unique($results);
There are 6 possible keys in a MySQL field. Lets call them types. Through PHP, I have defined an array, that is called $order, and arranges these types in order I want them to appear.
There is a table, articles, which has a field articles.type . Any article can have 0-6 types added to it. Now, what I want to do, is grab all of the articles, and order them from the prototype. What is the best way to do this? Can this be done in MySQL, since I suppose that would be faster? And if not, how can it be done in PHP?
Example:
Table:
id articleId type
1 3 type1
2 3 type2
3 3 type3
4 3 type4
5 4 type5
6 4 type6
7 5 type5
8 7 type1
9 7 type5
Order:
$order=array('type1','type2','type3','type4','type5','type6');
How do I fetch the results ordered by my $order variable?
You'd need to massage that array into a mysql-style if/case statement:
$order_by = "ORDER BY CASE";
$pos = 1;
foreach ($order as $clause) {
$order_by .= " CASE `type`='$clause' THEN " . $pos++;
}
$order_by .= " ELSE " . $pos++;
which would generate something like
ORDER BY CASE
WHEN `type`='type1' THEN 1
WHEN 'type`='type2' THEN 2
...
ELSE n
Can this be done in MySQL, since I suppose that would be faster?
Only if you allow MySQL to use an index
You can create a temp table:
$query = "CREATE TABLE IF NOT EXISTS test (
sort INT NOT NULL AUTO_INCREMENT,
`type` VARCHAR(20) NOT NULL,
PRIMARY KEY (sort),
KEY (`type`, sort)
ENGINE=MEMORY (SELECT 1,'other' <<-- see query below.
UNION SELECT 2,'type1' <<-- build this part using
UNION SELECT 3,'type2' <<-- Marc B's code.
UNION SELECT 4,'type3'
UNION SELECT 5,'type4'
UNION SELECT 6,'type5'
UNION SELECT 7,'type6' ";
Run this query.
Now you can link against this query using a join and use test.sort as your sortkey:
SELECT t1.id, t1.article_id, COALESCE(t.`type`,'other') as sort_type
FROM table1 t1
LEFT JOIN test t ON (t1.`type` = t.`type`)
WHERE ....
ORDER BY t.sort;
This query will be fully indexed and run as fast as possible.
Any time there is an update within my music community (song comment, artist update, new song added, yadda yadda yadda), a new row is inserted in my "updates" table. The row houses the artist id involved along with other information (what type of change, time and date, etc).
My users have a "favorite artists" section where they can do just that -- mark artists as their favorites. As such, I'd like to create a new feature that shows the user the changes made to their various favorite artists.
How should I be doing this efficiently?
SELECT *
FROM table_updates
WHERE artist_id = 1
OR artist_id = 500
OR artist_id = 60032
Keep in mind, a user could have 43,000 of our artists marked as a favorite.
Thoughts?
This depends on how your database is setup. If I had my way, I'd set it up with a table like so:
Table: user_favourite_artist
user_id | artist_id
---------------------
1 | 2
1 | 8
1 | 13
2 | 2
3 | 6
6 | 20
6 | 1
6 | 3
user_id and artist_id together would be a composite primary key. Each row specifies a user, by id, and an artist they have as a favourite, by id. A query like so:
SELECT artist_id FROM user_favourite_artist WHERE user_id = 1
Would give you the artist_id's 2, 8, and 13. This is a very simple query that will scale to your expectations.
On the reverse, when an artist is updated, you'd run this query:
SELECT user_id FROM user_favourite_artist WHERE artist_id = 2
And you would get the user_id's 1 and 2. This will tell you which users to notify. This query is also simple and will scale.
Maybe you can try this:
SELECT *
FROM table_updates
WHERE artist_id IN(1, 500, 60032)
If you have the marked artists in a secondary table, I would recomend rather using a join.
Something like
SELECT *
FORM table_updates tu INNER JOIN
table_marked_by_user tmbu ON tu.artist_id = tmbu.artist_id
WHERE tmbu.user_id = $user_id
If you're on SQL Server, you can use a nested select statement:
select * from table_updates where artist_id in
(select artist_id from favorites_table where user_id = 10)
If you don't mind doing dirty reads, you can speed it up with (nolock).
select * from table_updates (nolock) where artist_id in
(select artist_id from favorites_table (nolock) where user_id = 10)