Select all rows that have same ID - mysql

I have this table:
ID | Part
1 | A
1 | B
1 | C
2 | B
2 | C
3 | A
3 | D
3 | E
4 | B
4 | D
and want a query that will grab all ID's that have an A, and return a list of all other parts with that ID.
e.g: Want Parts related to B:
Part | Count
A | 1
C | 2
D | 1
What I have currently:
SELECT * FROM tble WHERE ID IN (SELECT DISTINCT ID FROM tble t WHERE Part = ?)
GROUP BY Part ORDER BY COUNT(Part) DESC
This works, but is quite slow and I'm looking to improve it, but having difficulty

Your query is not unreasonable, although the distinct is unnecessary and I would use exists rather than in. And, the outer select needs to be fixed for the aggregation
SELECT t.part, COUNT(*)
FROM tble t
WHERE EXISTS (SELECT 1 FROM tble t2 WHERE t2.ID = t.ID AND t2.Part = ?)
GROUP BY t.Part
ORDER BY COUNT(*) DESC;
Then, to optimize this query, you want an index:
create index idx_tble_id_part on tble(id, part);

Simplify this.. Once you have the logic down, then add back in the SELECT * FROM..
SELECT Part, COUNT(Part) As Count_of_Part
GROUP BY Part ORDER BY COUNT(Part) DESC

Do a join from the table back to itself on ID, and then count the distinct values that pop up:
SELECT b.part, COUNT(DISTINCT b.id)
FROM
table as a
INNER JOIN table as b ON
a.id = b.id AND
a.part <> b.part
WHERE
a.part = 'B'
GROUP BY b.part

This can be simply done by joining back to the table:
SELECT t1.part
,count(*)
FROM tble t1
INNER JOIN tble t ON t.id = t1.id
AND t.part = 'B'
AND t1.part <> t.part
GROUP BY t1.part
SQL Fiddle Demo

You should be able to do this by grouping the data.
Try something like this:
SELECT part, COUNT(id) AS TotalCountId
FROM TABLE_NAME
GROUP BY ID

Related

sql query to select records from mysql

Can suggest me the best way to select records from MySQL
customer
--------
id bed_id status
1 1 vocated
2 1 booked
3 2 vocated
bed
-----
id name
1 lower
2 middle
3 upper
I need to select bed which are vacated or not allotted
Here, the expected results are
The empty bed should be: bed_id's = 2 and 3
what is best SQL query to get this kind of result
Join the tables and group by the bed's id and put the conditions in a HAVING clause:
select b.id, b.name
from bed b left join customer c
on c.bed_id = b.id
group by b.id
having (
sum(status = 'vacated') > 0
and
sum(status = 'booked') = 0
) or sum(status is null) > 0
I'm not sure if you need and or or in the conditions
Try this-
SELECT * FROM bed
WHERE ID NOT IN (
SELECT DISTINCT bed_id FROM customer
WHERE Status = 'booked'
)
Note: This wll work for your current data. But if I think practical, you need to check the latest status of a BED in the customer table. That case you need to provide data with more variety and more explanation of your requirement.
You can apply a reverse logic by not exists :
select *
from bed b
where not exists
(
select bed_id
from customer
where status != 'vocated' and status = 'booked'
and bed_id = b.id);
Demo
You could find the most recent status using a correlated sub query and a left join to find rooms that have never had activity
select group_concat(s.t1id) availablerooms
from
(
select t1.id t1id,t1.name,t.id,t.bed_id,t.status
from t1
left join t on t1.id = t.bed_id
where t.id = (select max(id) from t where t1.id = t.bed_id) or
t.id is null
) s
where s.status <> 'booked' or s.status is null;
+----------------+
| availablerooms |
+----------------+
| 2,3 |
+----------------+
1 row in set (0.00 sec)

Use selected column in first query with IN clause in second query

Problem has been recreated below:
/* query - 1 */
Select id, title from table1;
/* returns */
id | title
-----------
1 | data-1
2 | data-2
3 | data-3
4 | data-4
5 | data-5
I want use this column id's data with IN clause in second query along with join.
Something like this:
Select id, title from table1
JOIN
Select anotherColumn from table2 where table2.id IN (1,2,3,4,5) on table1.id = table2.id
Instead of manually writing 1,2,3,4,5, how can I use the column data selected from first query in second query?
EDIT:
Actual query :
SELECT *
FROM
(
SELECT R.id, U.ic_id as rider, U.name, DP.department_name, R.location,
(R.distance - 1) + 10 as cost , R.timestamp, R.status
FROM requests AS R, iconnect.users AS U, iconnect.departments AS DP
WHERE R.pool = '125' AND R.rider = U.ic_id AND U.department = DP.id
) requestDetails
JOIN
(
SELECT AVG(rider_rating) AS rider_rating,rider
FROM
(
SELECT rider_rating, R.rider
FROM journeys AS J, requests AS R
WHERE J.req_id = R.id AND R.rider IN (12,13) LIMIT 999999
) AS allRatings
GROUP BY rider
) ratingsTable
ON requestDetails.rider = ratingsTable.rider
/* instead of (12,13) I want to use requestDetails.rider selected from the first derived table */
One option would be to use an EXISTS clause:
SELECT id, title
FROM table1 t1
WHERE EXISTS (SELECT 1 FROM table2 t2 WHERE t1.id = t2.id);
Actually, a plain inner join between the two tables would also work. But, you might want to use SELECT DISTINCT in case a given record in table1 could match more than one record in table2. That would leave us with this:
SELECT DISTINCT t1.id, t1.title
FROM table1 t1
INNER JOIN table2 t2
ON t1.id = t2.id;

mysql query that does not return an id with multiple entries

I wasn't sure how to word the title, but here is what I am trying to do. I have a table where the id can have multiple entries
id | number
___________
1 | 90
1 | 88
2 | 88
3 | 88
I want a query that will return all ids that don't contain the number 90, so only 2 and 3 in this example. I have tried the below, but it still returns the id of 1 since it also has a number of 88.
SELECT DISTINCT id FROM table WHERE number NOT IN (90)
One way of getting the result is by using NOT EXISTS. Basically what it does it it gets all ID which has 90 in the inner query and the NOT EXISTS only shows all ID not in the inner query.
SELECT A.*
FROM TableName a
WHERE NOT EXISTS (SELECT NULL
FROM TableName B
WHERE a.ID = b.ID
AND b.number = 90)
Here's a Demo.
An alternative is by using LEFT JOIN which yields the same result as above.
SELECT a.*
FROM TableName a
LEFT JOIN TableName b
ON a.ID = b.ID
AND b.number = 90
WHERE b.id IS NULL
Here's a Demo.
You can use subquery:
SELECT id
FROM table
WHERE id NOT IN (SELECT id FROM table WHERE number = 90)
You can use aggregation as illustrated below for better performance:
SELECT ID
FROM YourTable
GROUP BY ID
HAVING NOT INSTR(GROUP_CONCAT(`number`),'90');
Demo on SQL Fiddle.

How do I count in a left join query

How do I count the number of participants in the event_participants table. This is my table
event_place
id | name
1 | New York
2 | Canada
event_participants
id | event_place_id | name
1 | 1 | Jon
2 | 1 | Mike
3 | 2 | Van
and I am getting a wrong result on my query
SELECT count(*) as count
FROM event_participants as t1
LEFT JOIN event_place as t2
ON t1.event_place_id = t2.id;
and the result is 3
I should be getting a result like this
New York | 2
Canada | 1
your query like this.
select pl.id,pl.name,count(*) from
event_place pl
left join event_participants ep
on pl.id = ep.event_place_id
group by pl.id;
You are getting correct results because you are counting all the records.
If you want the counts per event place, you should GROUP BY event place
SELECT t1.event_place_id, t2.name, count(*) as count
FROM event_participants as t1
LEFT JOIN event_place as t2
ON t1.event_place_id = t2.id
GROUP BY t1.event_place_id, t2.name,;
select a.name, count(1) from event_place a, event_participants b
where b.event_place_id = a.id
group by a.name;
There appear to be a couple of issues.
I presume you want a list of all the even places, and the number of people at each one. If so that suggests that you need to LEFT OUTER JOIN the event_participants table to the event_place table, rather than the other way round. This way you can have places listed which have no participants.
You also need a GROUP BY clause.
And if you use COUNT(*) you are counting the returned rows (prior to the grouping). However if there is no matching participants then a row is still returned for the place, hence you would get 1 as the count. To avoid this specify a column in the COUNT() which is on the participants table. COUNT with a column name counts the number of non NULL values of that column, hence if no participants it will return 0 for that place:-
SELECT t2.name,
COUNT(t1.id) AS count
FROM event_place t2
LEFT JOIN event_participants t1
ON t1.event_place_id = t2.id
GROUP BY t2.name

Select Matched Pairs from Two Tables

I need to select matched pairs from two tables containing similarly structured data. "Matched Pair" here means two rows that reference each other in the 'match' column.
A single-table matched pair example:
TABLE
----
id | matchid
1 | 2
2 | 1
ID 1 and 2 are a matched pair because each has a match entry for the other.
Now the real question: what is the best (fastest) way to select the matched pairs that appear in both tables:
Table ONE (id, matchid)
Table TWO (id, matchid)
Example data:
ONE TWO
---- ----
id | matchid id | matchid
1 | 2 2 | 3
2 | 3 3 | 2
3 | 2
4 | 5
5 | 4
The desired result is a single row with IDs 2 and 3.
RESULT
----
id | id
2 | 3
This is because 2 & 3 are a matched pair in table ONE and in table TWO. 4 & 5 are a matched pair in table ONE but not TWO, so we don't select them. 1 and 2 are not a match pair at all since 2 does not have a matching entry for 1.
I can get the matched pairs from one table with this:
SELECT a.id, b.id
FROM ONE a JOIN ONE b
ON a.id = b.matchid AND a.matchid = b.id
WHERE a.id < b.id
How should I build a query that selects only the matching pairs that appear in both tables?
Should I:
Select the query above for each table and WHERE EXISTS them together?
Select the query above for each table and JOIN them together?
Select the query above then JOIN table TWO twice, once for 'id' and once for 'matchid'?
Select the query above for each table and loop through to compare them back in php?
Somehow filter table TWO down so we only have to look at the IDs in matched pairs in table ONE?
Do something totally different?
(Since this is a question of efficiency, it is worth noting that the matches will be quite sparse, maybe 1/1000 or less, and each table will have 100,000+ rows.)
I think I get your point. You want to filter the records in which the pairs exists on both tables.
SELECT LEAST(a.ID, a.MatchID) ID, GREATEST(a.ID, a.MatchID) MatchID
FROM One a
INNER JOIN Two b
ON a.ID = b.ID AND
a.matchID = b.matchID
GROUP BY LEAST(a.ID, a.MatchID), GREATEST(a.ID, a.MatchID)
HAVING COUNT(*) > 1
SQLFiddle Demo
Try this Query:
select
O.id,
O.matchid
from
ONE O
where
(CAST(O.id as CHAR(50))+'~'+CAST(O.matchid as CHAR(50)))
in (select CAST(T.id as CHAR(50))+'~'+CAST(T.matchid as CHAR(50)) from TWO T)
Edited Query:
select distinct
Least(O.id,O.matchid) ID,
Greatest(O.id,O.matchid) MatchID
from
ONE O
where
(CAST(O.id as CHAR(50))+'~'+CAST(O.matchid as CHAR(50)))
in (select CAST(T.id as CHAR(50))+'~'+CAST(T.matchid as CHAR(50)) from TWO T)
and (CAST(O.matchid as CHAR(50))+'~'+CAST(O.id as CHAR(50)))
in (select CAST(T.id as CHAR(50))+'~'+CAST(T.matchid as CHAR(50)) from TWO T)
SQL Fiddle
Naive version, which checks all the four rows that need to exist:
-- EXPLAIN ANALYZE
WITH both_one AS (
SELECT o.id, o.matchid
FROM one o
WHERE o.id < o.matchid
AND EXISTS ( SELECT * FROM one x WHERE x.id = o.matchid AND x.matchid = o.id)
)
, both_two AS (
SELECT t.id, t.matchid
FROM two t
WHERE t.id < t.matchid
AND EXISTS ( SELECT * FROM two x WHERE x.id = t.matchid AND x.matchid = t.id)
)
SELECT *
FROM both_one oo
WHERE EXISTS (
SELECT *
FROM both_two tt
WHERE tt.id = oo.id AND tt.matchid = oo.matchid
);
This one is simpler :
-- EXPLAIN ANALYZE
WITH pair AS (
SELECT o.id, o.matchid
FROM one o
WHERE EXISTS ( SELECT * FROM two x WHERE x.id = o.id AND x.matchid = o.matchid)
)
SELECT *
FROM pair pp
WHERE EXISTS (
SELECT *
FROM pair xx
WHERE xx.id = pp.matchid AND xx.matchid = pp.id
)
AND pp.id < pp.matchid
;