How to make cross select in one table? - mysql

Consider this table:
I need to make a SQL query which returns highlighted rows. In other words: rows which are linked to each other by idContactTo.
Example:
1 has contact to 2, 2 has contact to 1 - they are linked and should be in result table. But even 1 has contact to 3 it doesn't mean that 3 has contact to 1 - they aren't linked.

You can do it via INNER JOIN,
SELECT a.*
FROM tableName a
INNER JOIN tableName b
ON a.idContantOwner = b.idContactTo AND
b.idContantOwner = a.idContactTo
SQLFiddle Demo

Another way to do it
SELECT t.*
FROM
(
SELECT MiN(id) min_id, MAX(id) max_id
FROM Table1
GROUP BY LEAST(idContactOwner, idContactTo),
GREATEST(idContactOwner, idContactTo)
HAVING COUNT(*) = 2
) q JOIN Table1 t
ON t.id IN(q.min_id, q.max_id)
Output:
| ID | IDCONTACTOWNER | IDCONTACTTO |
|----|----------------|-------------|
| 1 | 1 | 2 |
| 2 | 2 | 1 |
| 4 | 3 | 4 |
| 5 | 4 | 3 |
Here is SQLFiddle demo

Related

Mysql sum count occurrences in multiple columns from another table

I need to find the sum of occurrences of ids in a join table. The id could be present in two different columns (id_type_1 and id_type_2).
Table types
id | name
1 | Test1
2 | Test2
3 | Test3
Table products
id | name | id_type_1 | id_type_2
1 | Product1 | 1 | 2
2 | Product2 | 3 | 1
3 | Product3 | 1 | 3
I need to get a result like this:
Type | Total
Test1 | 3
Test2 | 1
Test3 | 2
Here's my query, but it takes several seconds to execute:
SELECT t.name,
(SELECT COUNT(p.id) FROM products p WHERE p.id_type_1 = t.id || p.id_type_2 = t.id) AS total
FROM types t
WHERE 1
ORDER BY total DESC
Is there a more effective way to achieve the result?
Join the tables and aggregate:
select t.id, t.name,
sum((t.id = p.id_type_1) + (t.id = p.id_type_2)) Total
from types t inner join products p
on t.id in (p.id_type_1, p.id_type_2)
group by t.id, t.name
If there is no case for the id to exist in both id_type_1 and id_type_2 in the same row then:
select t.id, t.name,
count(*) Total
from types t inner join products p
on t.id in (p.id_type_1, p.id_type_2)
group by t.id, t.name
See the demo.
Results:
> id | name | Total
> -: | :---- | ----:
> 1 | Test1 | 3
> 2 | Test2 | 1
> 3 | Test3 | 2

How to avoid duplicate records in one-to-many association without using distinct?

I have two tables issues and time_entries and they have one-to-many association between them. We can created multiple time_entries for an issue.
here is some example data,
issue
id | subject | description
------------------------------
1 | test | test
2 | test1 | test1
3 | test2 | test2
Time entries
id | issue_id | hours | spent_on | created_on
---------------------------------------------------
1 | 1 | 2 | 2016-12-23 | 2016-12-23
2 | 1 | 2 | 2016-12-23 | 2016-12-23
3 | 2 | 3 | 2016-12-23 | 2016-12-23
4 | 2 | 5 | 2016-12-23 | 2016-12-23
5 | 4 | 4 | 2016-12-23 | 2016-12-23
Now I want to fetch all the issues which have spent time after a particular date.
SELECT *
FROM "issues"
INNER JOIN "time_entries" ON "time_entries"."issue_id" = "issues"."id"
WHERE time_entries.created_on > '2016-12-22'
It's returning multiple records for issues which have more than one entries.
id | subject | description
-----------------------------
1 | test | test
1 | test | test
2 | test1 | test1
2 | test1 | test1
3 | test2 | test2
How can I avoid these duplicate records without using distinct. I can't use distinct due to technical reasons in my application.
Any help will be highly appreciated.
One option is to use SELECT DISTINCT:
SELECT DISTINCT t1.id,
t1.subject,
t1.description
FROM issues t1
INNER JOIN time_entries t2
ON t2.issue_id = t1.id
WHERE t2.created_on > '2016-12-22'
If you can't use DISTINCT or GROUP BY, then one other option would be to use a subquery which aggregates over issues in the time_entries table and determines which issues meet the requirement. Something like this:
SELECT t1.id,
t1.subject,
t1.description
FROM issues t1
INNER JOIN
(
SELECT issue_id
FROM time_entries
GROUP BY issue_id
HAVING SUM(CASE WHEN created_on > '2016-12-22' THEN 1 ELSE 0 END) > 0
) t2
ON t2.issue_id = t1.id
SELECT * FROM "issues"
INNER JOIN "time_entries" ON "time_entries"."issue_id" = "issues"."id"
WHERE time_entries.created_on > '2016-12-22'
group by id

how to select all of duplicate record in mysql

My records is:
name | id | AVG(point) as point
a | 1 | 6
b | 2 | 6
c | 3 | 5
d | 4 | 5
e | 5 | 4
f | 6 | 3
g | 7 | 2
How to select record below:
1.I want to select top 3 record, result follow:
name | id | AVG(point) as point
a | 1 | 6
b | 2 | 6
c | 3 | 5
d | 4 | 5
e | 5 | 4
2.I want to select record not into top 3, result follow:
name | id | AVG(point) as point
f | 6 | 3
g | 7 | 2
How can I do?
There are several ways to do these. Here's a couple using in and not in.
For the top 3, you can use in:
select *
from yourtable
where point in (select distinct point
from yourtable
order by 1 desc
limit 3)
For the rest, use not in instead:
select *
from yourtable
where point not in (select distinct point
from yourtable
order by 1 desc
limit 3)
Other methods include exists with not exists and distinct with joins.
select *
from yourtable as t1
inner join (select distinct point
from yourtable
order by 1 desc
limit 3) as t2
on t1.point = t2.point
For the second part of your question, do not use
desc

Check multiple columns for duplicate and list all records

I have a table with columns ID, Content and Day. I am trying to find all rows that have duplicate Content and Day values and display all rows
SELECT ID,Content, `Day`, Count(*)
FROM table
GROUP BY Content,`Day`
HAVING COUNT(*) > 1
The current code will return a list of duplicate Content and 'Day' values for instance:
ID|Content|Day
1 | a | 1
2 | a | 1
3 | a | 1
4 | b | 2
5 | b | 2
6 | c | 3
7 | c | 4
Will result in:
ID|Content|Day|Count
1 | a | 1 | 3
4 | b | 2 | 2
But I want to display all the unique IDs as well;
ID|Content|Day
1 | a | 1
2 | a | 1
3 | a | 1
4 | b | 2
5 | b | 2
Just make a Sub-Query
select *
from table
where `day` in
(
SELECT ID
FROM table
GROUP BY Content,`Day`
HAVING COUNT(*) > 1
) A
Use that query as a subquery to join against the table again:-
SELECT table.ID, table.Content, table.`Day`
FROM table
INNER JOIN
(
SELECT Content, `Day`, Count(*)
FROM table
GROUP BY Content,`Day`
HAVING COUNT(*) > 1
) sub0
ON sub0.Content = table.Content
AND sub0.`Day` = table.`Day`

Count multiple columns with same WHERE condition

I have a users table with columns: user_id, teacher_id1, teacher_id2, teacher_id3
and
teachers table with id
Each user can have the same id's for teacher_id1, teacher_id2, teacher_id3
I would like to count how many users have same teacher.
User table
+----------------------------------------+
| user_Id teacher_id1 teacher_id2 teacher_id3 |
+----------------------------------------+
| 1 1 1 1 |
| 2 2 1 3 |
| 3 2 3 3 |
| 4 2 2 2 |
+----------------------------------------+
Teacher table
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
Count for $id1 is: 2
Count for $id2 is: 3
Count for $id3 is: 2
I tried something like this, but it is not correct!
SELECT COUNT(*) FROM users WHERE concat_ws('',teacher_id1 OR teacher_id2
OR teacher_id3) like '{$id}' ";
You have data in three different columns. You need to combine it into one column, to get the distinct counts that you want. For this, you can use union all. Then the count is simply count(distinct):
select teacher_id, COUNT(distinct USER_ID)
from ((select user_id, teacher_id1 as teacher_id
from t
) union all
(select user_id, teacher_id2
from t
) union all
(select user_id, teacher_id3
from t
)
) s
group by teacher_id;
Try this query
select b.id, count(*)
from
tbl1 a
inner join
tbl2 b
on b.id = teacher_id1 or b.id = teacher_id2 or b.id = teacher_id3
group by b.id
SQL FIDDLE:
| ID | COUNT(*) |
-----------------
| 1 | 2 |
| 2 | 3 |
| 3 | 2 |