Sorry for the bad title, do not know how to describe it in one sentence.
There is the table:
id, user_id, task_id
I need to select user_ids which have records with several task_id
Kind of pseudocode
Select user_id from tasks wherehas task_id = 1 and task_id = 2
As they say, there are many ways to skin a cat. Here is one:
To get a list of users that have multiple tasks assigned, and (at minimum) they have task_id 1 AND task_id 2:
SELECT
user_id
FROM user_tasks // or whatever your table is called
WHERE task_id in (1, 2)
GROUP BY user_id
HAVING COUNT(DISTINCT task_id) = 2
Let us get all the rows where task is is 1 or 2, group them up by user and show only users who have a min task ID that is different to the max task id:
SELECT
user_id
FROM t
WHERE task_id in (1, 2)
GROUP BY user_id
HAVING MIN(task_id) <> MAX(task_id)
You need to appreciate in all of this that when you write a WHERE clause, it is evaluated to be true for every individual row. This means you cannot say WHERE x = 1 AND x = 2 because the value of X can never ever be simultaneously 1 and 2 ON THE SAME ROW.
Instead we use an OR, to get all the user rows that are 1 or 2 and this will give us a mix - some users have multiple rows (the first row is 1 and the next row is 2). Other users have only one row- either a one or a two.
User Task
John 1
Jane 1
Jane 1
Jake 1
Jake 2
Joel 2
When we apply a grouping operation, all those rows are squashed down to one row per user and then things like MIN and MAX can be used and make sense. For a user with only one row his MIN and MAX will be the same number. For a user who had 20 rows that are all value 1, they will also be MIN and MAX the same. Only users who have at least one row that is a 1 and another row that is a 2 will have a different min and max:
User MIN MAX
John 1 1
Jane 1 1
Jake 1 2 <-- the only user HAVING MIN <> MAX
Joel 2 2
Min and max is only really useful in cases where you're looking for 2 different values. In other cases you might look for COUNT DISTINCT that contains the same number as there are elements in the IN list
I think you mean you want the values of user_id for which there is a task with task_id 1 and a task with task_id 2.
Your solution doesn't work because it's looking for a task which has task_id 1 and task_id 2 (which is impossible)
You need:
select a.user_id from tasks a where a.task_id = 1 inner join
tasks b where b.user_id = a.user_id and b.task_id = 2
Related
I need to assign jobs to users based on a score (number of "chances") calculated from previous jobs they have done. Here's my table of users:
user chances
Anna 6
Barry 4
Steve 3
Jackson 3
Helga 3
Maureen 3
Paul 3
Karen 2
Anita 2
Samson 2
Frank 2
Jean 1
Lilly 1
Boris 1
In another table, I have 100 rows of unassigned jobs (with currently NULL user), e.g.
id title user
1 Sort filing NULL
2 Clean office NULL
3 Order stationery NULL
I want to assign these jobs to the users above using a weighting based on the number of "chances" they have. For example, Anna will have 6 chances to be assigned one of these jobs, while Boris will have 1.
I've been playing around with a CASE which will assign a user to jobs, but nothing is satisfactory.
What's the best way for me to achieve this? Thanks
Presumably, you're after something like this...
SELECT user
FROM my_table
ORDER BY RAND() * chances * (SELECT SUM(chances) FROM my_table) DESC ;
If the changes are a small number and integers, then the easiest way might be:
update anothertable at
set user = (select user
from chances c cross join
(select 1 as n union all select 2 union all select 3 union all
select 4 union all select 5 union all select 6
) n
on c.chances <= n.n
where at.user is null
order by rand()
limit 1
);
The where clause is just so MySQL doesn't get the (brilliant) idea of optimizing away the subquery and only calling it once.
I did some research and learned about the COALESCE(sum(num), 0) function. The issue is the example I found only related to using one table.
I am calculating a sum from a second table, and if there are no records for an item in the second table, I still want it to show up in my query and have a sum of zero.
SELECT note.user, note.product, note.noteID, note.note, COALESCE(sum(noteTable.Score), 0) as points
FROM note, noteTable
WHERE note.user <> 3 AND note.noteID = noteTable.noteID
I am only recieving results if there is an entry in the second table noteTable. If there are scores added for a note, I still want them to show up in the result with a points value of zero.
Table Examples:
Note
user | product | noteID |note
3 1 1 Great
3 2 2 Awesome
4 1 3 Sweet
NoteTable
noteID | score
1 5
The query should show me this:
user | noteID | sum(points)
3 1 5
3 2 0
4 3 0
But I am only getting this:
user | noteID | sum(points)
3 1 5
http://sqlfiddle.com/#!9/aae812/2
SELECT
note.user,
note.product,
note.noteID, note.note,
COALESCE(sum(noteTable.Score),0) as points
FROM note
LEFT JOIN noteTable
ON note.noteID = noteTable.noteID
WHERE note.user <> 3
and I guess you should add:
GROUP BY note.noteid
if you expect to get SUM for every user. So you want to get more then 1 record back.
First, learn to use proper JOIN syntax and table aliases. The answer to your question is SUM() along with COALESCE():
SELECT n.user, n.product, n.noteID, n.note,
COALESCE(sum(nt.Score), 0) as points
FROM note n LEFT JOIN
noteTable nt
ON n.noteID = nt.noteID
WHERE n.user <> 3
GROUP BY n.user, n.product, n.noteID, n.note;
You also need a GROUP BY.
So I have MySQL 3 tables, items (which in this case are lodging properties and the data is simplified below), amenities that the properties might offer, and amenities_index which is a list of item ids and amenity ids for each amenity offered. The end user can select any number of amenities they want and I want to return the results in order of the number of amenities that match what they are looking for. So, if they search for 3 different amenities, I want the items listed that offer all 3, then those that offer 2, 1 and finally the rest of the items. I have a query that I think is working for getting the results in the correct order, but I was hoping that I could also return a point value based on the matches, and that's where I'm running into trouble. My SQL skills are a bit lacking when it comes to more complex queries.
Here is an example query I have that returns the results in the correct order:
SELECT * FROM items
ORDER BY
(
SELECT count(*) AS points
FROM `amenities_index`
WHERE
(amenity_id = 1 || amenity_id = 2)
AND amenities_index.item_id = items.id
) DESC
And here is what the tables are structured like. Any help is appreciated.
items table
id name
1 location 1
2 location 2
3 location 3
4 location 4
amenities table
id name
1 fireplace
2 television
3 handicapped accessible
4 kitchenette
5 phone
amenities_index
item_id amenity_id
1 2
1 3
1 5
2 1
2 2
2 6
3 2
3 3
3 4
3 5
You want to move your expression into the select clause:
SELECT i.*,
(SELECT count(*) AS points
FROM `amenities_index` ai
WHERE amenity_id in (1, 2) AND
ai.item_id = i.id
) as points
FROM items i
ORDER BY points desc;
You can also do this as a join query with aggregation:
SELECT i.*, ai.points
FROM items i join
(select ai.item_id, count(*) as points
from amenities_index ai
where amenity_id in (1, 2)
) ai
on ai.item_id = i.id
ORDER BY ai.points desc;
In most databases, I would prefer this version over the first one. However, MySQL would allow the first in a view but not the second, so it has some strange limitations under some circumstances.
I'm implementing a messaging system on my site, and have a table to store the conversation participants like so:
conversation_id user_id
3 2
3 28
4 1
4 2
5 1
5 2
5 28
I can't find a query that will let me check if a conversation already exists between 2 users (or more). I basically want 3 (conversation_id) to be returned if user 2 is sending to user 28, or vice-versa, like that I can keep the conversation going even if they haven't explicitly replied to a previous message.
With the having clause you can filter to only the conversation_ids where both users participate
select conversation_id
from your_table
where user_id in (2, 28)
group by conversation_id
having count(distinct user_id) = 2
I need a little help with a MySQL query.
I have two tables one table is a list of backlinks with a is_homepage (bool) flag. The second table is a list of the domains for all of the backlinks, a was link_found (bool) flag, and a url_count column which is the number of rows in the backlinks table that are associated with each domain.
Note that the domain_id column is the foreign key to the domain table id column. Heres some sample data.
backlinks
id domain_id is_homepage page_href
1 1 1 http://ablog.wordpress.com/
2 1 0 http://ablog.wordpress.com/contact/
3 1 0 http://ablog.wordpress.com/archives/
4 2 1 http://www.somewhere.org/
5 2 0 http://www.somewhere.org/page=3
6 3 1 http://www.great-fun-site.com/
7 3 0 http://www.great-fun-site.com/index.html
8 4 0 http://red.blgspot.com/page=7
9 4 0 http://blue.blgspot.com/page=9
domains
id url_count link_found domain_name
1 3 1 wordpress.com
2 2 0 somewhere.org
3 2 1 great-fun-site.com
4 2 1 blgspot.com
The results Im looking to get from the above data would be: count = 2, total = 5.
Im trying to get the count of rows from the domains table (count) and then the sum of the url_count (total) from the domains table WHERE link_found is 1 and where one of the links in the backlink table is_homepage is 1.
Here's the query I'm trying to work with.
SELECT SUM(1) AS count, SUM(`url_count`) total
FROM `domains` AS domain
LEFT JOIN `backlinks` AS link ON link.domain_id = domain.id
WHERE domain.id IN (
SELECT DISTINCT(bl.domain_id)
FROM `backlinks` AS bl
WHERE bl.tablekey_id = 11
AND bl.is_homepage = 1
)
AND domain.link_found = 1
AND link.is_homepage = 1
GROUP BY `domain`.`id`
The problem with this query is that it returns a row for each entry in the domains table. I think I might need one more sub query to add up the returned results but I'm not sure if that's correct. Does anyone see what I'm doing wrong? Thank you!
EDIT:
The problem I'm having is that if there are more than one homepage in the back-links table then its counted multiple times. I need to only count each domain once.
Well, you shouldn't have to do a group by as you are not selecting anything other than aggregated fields. I'm no mysql expert, but this should work:
SELECT count(d.id) as count, sum(d.url_count) as total from domains as d
inner join backlinks as b
on b.domain_id = d.id
Where d.Link_found = 1 and b. is_homepage = 1
The reason you're getting a row for each entry in the domains table is that you're grouping by domain.id. If you want grand totals only, just leave off the GROUP BY piece.
I think a fairly simple query will do the trick:
SELECT COUNT(*), SUM(domains.URL_Count)
FROM domains
WHERE domains.link_found = 1 AND domains.id IN (
SELECT domain_id FROM backlinks WHERE is_homepage = 1)
There's a working SQLFiddle here.
Thanks for the help. Sorry it was so hard to explain I need a MySQL fiddle :)
If anyones interested heres what I ened up with:
SELECT SUM(1) AS count, SUM(total) AS total
FROM
(
SELECT SUM(`url_count`) total
FROM `domains` AS domain
LEFT JOIN `backlinks` AS link ON link.domain_id = domain.id
WHERE domain.id IN (
SELECT DISTINCT(bl.domain_id)
FROM `backlinks` AS bl
WHERE bl.tablekey_id = 11
AND bl.is_homepage = 1
)
AND domain.link_found = 1
AND link.is_homepage = 1
GROUP BY `domain`.`id`
) AS result