Advance select query in mysql - mysql

I have a table called 'connections' with these fields:
entry_id
user_id
connector_id
cat_id
Lets put some rows
| entry_id | user_id | connector_id |cat_id |
|:---------|---------|:------------:|:------------:|
| 1 | 11| 33 | 1
| 2 | 13| 11 | 2
| 3 | 9| 11 | 4
| 4 | 11| 33 | 6
| 5 | 33| 11 | 11
| 6 | 9| 11 | 8
Pseudocode
(using connection between id = 11 and oid = 9)
Select cat_id FROM connections c
if cat_id is between 1 and 5
where c.connector_id = id OR c.user_id = id
AND c.connector_id = oid OR c.user_id = oid
else if cat_id is greater than 5
where oid = user_id and id = connector_id
In english;
If the cat_id is between 1 and 5, it should select cat_ids from where oid and id are both in connector_id or user_id, it doesn't matter which order as long as they are in one or the other, but if the cat_id is greater than 5, it should only select cat_ids where oid is the user_id and id is the connector_id.
Result (for connection between id = 11 and oid = 9)
| cat_id |
|:-----------|
| 4 |
| 8 |
One more example:
Result (for connection between id = 33 and oid = 11 )
| cat_id |
|:-----------|
| 1 |
| 6 |
Please ask if they're parts that are not clear.

You should be able to accomplish this by just following your if statements logically. Something like:
Select cat_id FROM connections c
where
(id between 1 and 5 AND (c.connector_id = id OR c.user_id = id)
AND (c.connector_id = oid OR c.user_id = oid))
OR id > 5 AND (oid = user_id and id = connector_id)
Note: in agreement with some of the comments - ensure this is what you need to be doing. I made some assumptions about how you intended your logic to be from the pseudo-code, these may be wrong - so please think about it before just copying and pasting. This specifically applies to how you structured your OR / AND in the where clause.

Related

Mysql count how many answers are correct

I have table user_answers :
id | quiz_id | user_id | question_id | choosen_answer_id |
1 | 1 | 2 | 1 | 5 |
2 | 1 | 2 | 2 | 6 |
3 | 1 | 2 | 3 | 7 |
4 | 1 | 3 | 1 | 5 |
5 | 1 | 3 | 2 | 8 |
6 | 1 | 3 | 3 | 9 |
I want to cont how many correct answers (same choosen_answer_id for same question_id ) has user with user_id = 3 compared with user_id = 2 on same quiz_id
In this example I should receive 1 because user with user_id = 3 answered correct only on question with question_id=1 (for user_id = 2, question_id = 1 choosen_answer_id = 5 and for user_id = 3, question_id = 1 choosen_answer_id = 5`).
Thanks
I understand that you are willing to count for how many questions both users have given the same answer. You could self-join the table as follows :
SELECT COUNT(*) AS number_of_identical_answers
FROM user_answers ua2
INNER JOIN user_answers ua3
ON ua3.user_id = 3
AND ua3.quiz_id = ua2.quiz_id
AND ua3.question_id = ua2.question_id
AND ua3.choosen_answer_id = ua2.choosen_answer_id
WHERE ua2.user_id = 2
If you want to display the joined records instead of counting them, you can change COUNT(*) to a list of columns from tables ua2 (answers of user 2) and ua3 (answers of user 3).
select user_id, count(*)
from table1 t1
join (select *from table1 where user_id = 2) t2
on t2.question_id = t1.question_id
where t2.choosen_answer_id = t1.choosen_answer_id
group by t1.user_id

MYSQL: how to return value from column that has relation to values in another column

Im struggling to articulate this, let alone execute in in MYSQL. How Do I return the userId X where userId.X and permissionId in (1,2,3,4,5,6,7,8) ?
The below example should return 6.
MariaDB [mailserver]> select * from user2permission;
+--------------+--------+
| permissionId | userId |
+--------------+--------+
| 1 | 5 |
| 1 | 6 |
| 2 | 6 |
| 2 | 7 |
| 3 | 6 |
| 4 | 6 |
| 5 | 6 |
| 6 | 6 |
| 7 | 6 |
| 8 | 6 |
+--------------+--------+
This kind of query can be written with the use of Group By clause and counting the instance as per the filteration applied in where clause
SELECT userId
FROM user2permission
WHERE permissionId IN (1,2,3,4,5,6,7,8)
GROUP BY userId
HAVING COUNT(*) = 8
You want to only show users that have an entry for all required permissions. Two solutions spring to mind:
select *
from users
where userid in (select userid from user2permission where permissionid = 1)
and userid in (select userid from user2permission where permissionid = 2)
...
and
select userid,
from user2permission
group by userid
having count(case when permissionid = 1 then 1 end) > 0
and count(case when permissionid = 2 then 1 end) > 0
...
And when I say "spring" to mind, I mean exactly that = without much thinking :-) Rizwan's aggregation solution is what you should use.

SQL order by match to specific row

I have a example table below. I am trying to create a SQL query that gets all user_ids besides user_id of the current user and then orders by number of matches to the row with the current user_id
For example, if the user has a user_id of '1', I want to get all of the user_ids corresponding with the rows of id 2-8, and then order the user_ids from most matches to the row of the current user to least matches with the row of the current user
Let's say var current_user = 1
Something like this:
SELECT user_id
FROM assets
WHERE user_id <> `current_user` and
ORDER BY most matches to `current_user`"
The output should get 7,8,3,9,2
I would appreciate anyone's input on how I can effectively achieve this.
Table assets
+----------+---------+-------+--------+-------+
| id | user_id | cars | houses | boats |
+----------+---------+-------+--------+-------+
| 1 | 1 | 3 | 2 | 3 |
| 2 | 8 | 3 | 2 | 5 |
| 3 | 3 | 3 | 2 | 2 |
| 4 | 2 | 5 | 1 | 5 |
| 5 | 9 | 5 | 7 | 3 |
| 8 | 7 | 3 | 2 | 3 |
+----------+---------+-------+--------+-------+
I think you can just do this:
select a.*
from assets a cross join
assets a1
where a1.user_id = 1 and a.user_id <> a1.user_id
order by ( (a.cars = a1.cars) + (a.houses = a1.houses) + (a.boats = a1.boats) ) desc;
In MySQL, a boolean expression is treated as an integer in a numeric context, with 1 for true and 0 for false.
If you want to be fancier, you could order by the total difference:
order by ( abs(a.cars - a1.cars) + abs(a.houses - a1.houses) + abs(a.boats - a1.boats) );
This is called Manhattan distance, and you would be implementing a version of a nearest neighbor model.

MYSQL - Find records from one table which don't exist in another

I've got the following two SQL tables (in MySQL):
Users
| id | name |
|----|------|
| 1 | Luke |
| 2 | Mark |
| 3 | Lucy |
| 4 | Biff |
User category
| user_id | category_id |
|---------|-------------|
| 1 | 5 |
| 1 | 6 |
| 2 | 5 |
| 2 | 7 |
| 3 | 5 |
I want users that are in User category but not if category id is 6.
In this case Mark and Lucy because Luke is in category 6 too and Biff has no category.
There is a way to do it without subquery and only in one query?
You can group by user_id and eliminate those rows where there is atleast one category_id of 6.
select uc.user_id,u.name
from user_category uc
join users u on uc.user_id = u.id
group by uc.user_id,u.name
having sum(case when category_id = 6 then 1 else 0 end) = 0
Join them and check for difference :
SELECT * FROM users
INNER JOIN user_category ON (user_category.user_id = users.id)
WHERE user_category.category_id <> 6
p.s. using group by is not effective, cuz it says to DB engine to do additional group by operation after gathering data.

Find columns which come in pair with multiple/various other-column values

I have a points table, where important columns are:
id userid orderid
1 10 150
2 10 150
3 15 151
4 12 152
5 11 152
I need to find all orderid which have multiple/various userid. The result would be:
id userid orderid
4 12 152
5 11 152
I can do it in PHP, but I hope someone have time to help me with mysql query. What I have tried so far is probably irrelevant.
Use COUNT(DISTINCT) and HAVING to find orderid with multiple various userid.
SqlFiddleDemo
SELECT t.*
FROM tab t
JOIN (SELECT orderid, COUNT(DISTINCT userid)
FROM tab
GROUP BY orderId
HAVING COUNT(DISTINCT userid) > 1) AS sub
ON t.orderid = sub.orderid
ORDER BY t.id
If you want to get just the rows that have same orderid but different userid, use this:
SELECT P1.* FROM points P1
INNER JOIN points P2
ON P1.orderid = P2.orderid and P1.id != P2.id and P1.userid != p2.userid;
Note that this first select returns what you expect in your question:
+----+--------+---------+
| id | userid | orderid |
+----+--------+---------+
| 4 | 12 | 152 |
| 5 | 11 | 152 |
+----+--------+---------+
Now, if you want to return ANY orderid that is the same, regardless of userid, use this:
SELECT P1.* FROM points P1
INNER JOIN points P2
ON P1.orderid = P2.orderid and P1.id != P2.id;
In this case, it won't exclude the result with same id, returning
+----+--------+---------+
| id | userid | orderid |
+----+--------+---------+
| 1 | 10 | 150 |
| 2 | 10 | 150 |
| 4 | 12 | 152 |
| 5 | 11 | 152 |
+----+--------+---------+