Select rows based on 2 columns - mysql

I am not the greatest at SQL and I am trying to achieve the following:
I have a table with columns like so:
id | cup_type | cup_id | name
I have a ton of records in the database which will have the same cup_id but different cup_types
I would really like to select records that have the same cup_id but different cup_types
id | cup_type | cup_id | name
1 | TypeOne | 12 | NameOne
2 | TypeTwo | 12 | NameTwo
3 | TypeOne | 13 | NameThree
4 | TypeTwo | 13 | NameFour
5 | TypeOne | 14 | NameFive
6 | TypeOne | 14 | NameSix
When I run the said query it would being me back the following:
id | cup_type | cup_id | name
1 | TypeOne | 12 | NameOne
2 | TypeTwo | 12 | NameTwo
3 | TypeOne | 13 | NameThree
4 | TypeTwo | 13 | NameFour
I hope I have explained this ok and let me know if more clarity is needed.

This query would do the trick
select * from
yourtable a
join (select cup_id, count(distinct cup_type) nbType
from yourTable
group by cup_id) b using(cup_id)
where b.nbType >= 2;
Get a result set from your table where you count the distinct cup_type.
Group that result set by cup_id.
Keep the cup_id so we can join on the same table, using that id.
Return only those where the count of distinct types was at least two.

Try something like this:
select a.id, b.id ....... from t1 as a, t2 as b where a.cup_id=b.cup_id and a.cup_type !=b.cup_type

Related

if with yes or no status mysql query

I have 2 tables, the first table or_f_table data. The second table or_table
or_f_table
f_id | f_o_id | f_u_id
1 | 19 | 1
2 | 5 | 2
3 | 19 | 2
or_table
o_id | o_name
4 | test1
5 | test2
19 | oops2
20 | oops3
SELECT o.o_name,
IF ((SELECT count(*) FROM or_f_table as f
WHERE f.f_u_id = 1 ),'Yes','No') as follow_status
FROM or_table as o
WHERE o.o_name LIKE '%oop%'
I want to do something like this result :-
o_name | follow_status
oops2 | Yes
oops3 | No
I am getting result
o_name | follow_status
oops2 | Yes
oops3 | Yes
Why doesn't it work? And how should I correct it
There will always be a value greater than 0 for your where condition. That is why it is not working.
Try this to get the specified results
SELECT o.o_name,
IF ((SELECT count(*) FROM or_f_table as f
WHERE f.f_o_id = o.o_id ),'Yes','No') as follow_status
FROM or_table as o
WHERE o.o_name LIKE '%oop%'

Getting the sum of several columns from two tables result is not correct

I'am trying to get the sum of the two columns from different tables, however i have found great posts on stack. some of them helped me out. but i still can't solve this problem out..
This query somehow down below returns incorrect total of the sum of the coulmns, ( rate Coulmn - materialprice Column )
mysql> Tbl as_servicetickets;
+----------+----------+
|ticket_id | rate |
+----------+----------+
| 11 | 250.00 |
| 11 | 300.00 |
| 11 | 400.00 |
| 9 | 300.00 |
| 9 | 300.00 |
| 9 | 1500.00 |
| 9 | 250.00 |
+----------+----------+
total is 2 350.00
mysql> Tbl as_ticketmaterials;
+----------+---------------+
|ticket_id | materialprice |
+----------+---------------+
| 11 | 100 |
| 9 | 20 |
| 9 | 50 |
+----------+---------------+
total is 70.00
query---------------------////
SELECT SUM(`as_servicetickets`.`rate`) AS `sercnt`, SUM(`as_ticketmaterials`.`materialprice`) AS `sercnt`
FROM `as_servicetickets`, `as_ticketmaterials`
WHERE `as_servicetickets`.`ticket_id` = 9
AND `as_ticketmaterials`.`ticket_id` = 9
GROUP BY `as_servicetickets`.`ticket_id`, `as_ticketmaterials`.`ticket_id
result ------------------///// this is not correct
+---------+--------+
| sercnt | sercnt |
+---------+--------+
| 4700.00 | 280 |
+---------+--------+
This is not the correct way to achieve the desired result. Try this rather:-
SELECT (SELECT SUM(`as_servicetickets`.`rate`) AS `sercnt`
FROM `as_servicetickets`
WHERE `as_servicetickets`.`ticket_id` = 9),
(SELECT SUM(`as_ticketmaterials`.`materialprice`) AS `sercnt`
FROM `as_ticketmaterials`
WHERE `as_ticketmaterials`.`ticket_id` = 9);
Try using explicit join as implicit joins are discouraged (You where condition has issue)
SELECT `as_servicetickets`.`ticket_id`, SUM(`as_servicetickets`.`rate`) AS `sercnt`, SUM(`as_ticketmaterials`.`materialprice`) AS `sercnt`
FROM `as_servicetickets` INNER JOIN `as_ticketmaterials`
ON `as_servicetickets`.`ticket_id` = `as_ticketmaterials`.`ticket_id`
WHERE `as_servicetickets`.`ticket_id` = 9
GROUP BY `as_servicetickets`.`ticket_id`
select sum(a.rate) as sercnt, sum(b.materialprice) as sercnt from
as_servicetickets a inner join as_ticketmaterials b on
a.ticket_id = b.ticket_id where a.ticket_id = 9

Remove duplicates from one column keeping whole rows

id | userid | total_points_spent
1 | 1 | 10
2 | 2 | 15
3 | 2 | 50
4 | 3 | 5
5 | 1 | 15
With the above table, I would first like to remove duplicates of userid keeping the rows with the largest total_points_spent, like so:
id | userid | total_points_spent
3 | 2 | 50
4 | 3 | 5
5 | 1 | 15
And then I would like to sum the values of total_points_spent, which would be the easy part, resulting in 70.
I am not really sure the "remove" you meant is to delete or to select. Here is the query for select only max totalpointspend record respectively.
SELECT tblA.*
FROM ( SELECT userid, MAX(totalpointspend) AS maxtotal
FROM tblA
GROUP BY userid ) AS dt
INNER JOIN tblA
ON tblA.userid = dt.userid
AND tblA.totalpointspend = dt.maxtotal
ORDER BY tblA.userid

GROUP BY with aggregate and an INNER JOIN

I tried to narrow down the problem as much as possible, it is still quite something. This is the query that doesn't work the way I want it:
SELECT *, MAX(tbl_stopover.dist)
FROM tbl_stopover
INNER JOIN
(SELECT edges1.id id1, edges2.id id2, COUNT(edges1.id) numConn
FROM tbl_edges edges1
INNER JOIN tbl_edges edges2
ON edges1.nodeB = edges2.nodeA
GROUP BY edges1.id HAVING numConn = 1) AS tbl_conn
ON tbl_stopover.id_edge = tbl_conn.id1
GROUP BY id_edge
Here is what I get:
|id | edge | dist | id1 | id2 | numConn | MAX(tbl_stopover.dist) |
------------------------------------------------------------------
|2 | 23 | 2 | 23 | 35 | 1 | 9 |
|4 | 24 | 5 | 24 | 46 | 1 | 9 |
------------------------------------------------------------------
and this is what I would want:
|id | edge | dist | id1 | id2 | numConn | MAX(tbl_stopover.dist) |
------------------------------------------------------------------
|3 | 23 | 9 | 23 | 35 | 1 | 9 |
|5 | 24 | 9 | 24 | 46 | 1 | 9 |
------------------------------------------------------------------
But let me elaborate a bit...
I have a graph, let's say as such:
node1
|
node2
/ \
node3 node4
| |
node5 node6
Therefore I have a table I call tbl_edges like this:
| id | nodeA | node B |
------------------------
| 12 | 1 | 2 |
| 23 | 2 | 3 |
| 24 | 2 | 4 |
| 35 | 3 | 5 |
| 46 | 4 | 6 |
------------------------
Now each edge has "stop_overs" at a certain distance (to nodeA). Therefore I have a table tbl_stopover like this:
| id | edge | dist |
------------------------
| 1 | 12 | 5 |
| 2 | 23 | 2 |
| 3 | 23 | 9 |
| 4 | 24 | 5 |
| 5 | 24 | 9 |
| 6 | 35 | 5 |
| 7 | 46 | 5 |
------------------------
Why this query?
Let's assume I want to calculate the distance between the stop_overs. Within one edge that is no problem. Across edges it gets more difficult. But if I have two edges that are connected and there is no other connection I can also calculate the distance. Here an example assuming all edges have a length of 10. :
edge23 has a stop_over(id=3) at dist=9, edge35 has a stop_over(id=6) at dist=5. Therefore the distance between these two stop_overs is:
dist = (length - dist_id3) + dist_id5 = (10-9) + 5
I am not sure if I made my self clear. If this is not understandable, feel free to ask question and I will do my best to make this more understandable.
MySQL allows you to do something silly - display fields in an aggregate query that are not a part of the GROUP BY or an aggregate function like MAX. When you do this, you get random (as you said) results for the remaining fields.
In your query you are doing this twice - once in your inner query (id2 is not part of a GROUP BY or aggregate) and once in the outer.
Prepare for random results!
To fix it, try something like this:
SELECT tbl_stopover.id,
tbl_stopover.dist,
tbl_conn.id1,
tbl_conn.id2,
tbl_conn.numConn,
MAX(tbl_stopover.dist)
FROM tbl_stopover
INNER JOIN
(SELECT edges1.id id1, edges2.id id2, COUNT(edges1.id) numConn
FROM tbl_edges edges1
INNER JOIN tbl_edges edges2
ON edges1.nodeB = edges2.nodeA
GROUP BY edges1.id, edges2.id
HAVING numConn = 1) AS tbl_conn
ON tbl_stopover.id_edge = tbl_conn.id1
GROUP BY tbl_stopover.id,
tbl_stopover.dist,
tbl_conn.id1,
tbl_conn.id2,
tbl_conn.numConn
The major changes are the explicit field list (note that I removed the id_edge since you are joining on id1 and already have that field), and addition of additional fields to both the inner and outer GROUP BY clauses.
If this gives you more rows than you want then you may need to explain more about your desired result set. Something like this is the only way to ensure you get appropriate groupings.
Okay. This seems to be the answer to my question. I will do some further "investigation" though, because I'm not sure if this is reliable. If anybody has some though on this, please leave a comment.
SELECT tbl.id, tbl.dist, tbl.id1, tbl.id2, MAX(dist) maxDist
FROM
(
SELECT tbl_stopover.id,
tbl_stopover.dist,
tbl_conn.id1,
tbl_conn.id2,
tbl_conn.numConn
FROM tbl_stopover
INNER JOIN
(SELECT edges1.id id1, edges2.id id2, COUNT(edges1.id) numConn
FROM tbl_edges edges1
INNER JOIN tbl_edges edges2
ON edges1.nodeB = edges2.nodeA
GROUP BY edges1.id
HAVING numConn = 1) AS tbl_conn
ON tbl_stopover.id_edge = tbl_conn.id1
GROUP BY tbl_stopover.dist, tbl_conn.id1
ORDER BY dist DESC) AS tbl
GROUP BY tbl.id1, tbl.id2
Thanks to JNK (my colleague at work) without whom I wouldn't have gotten this far.

Querying specific data from 3 tables

I'm having trouble coming up with a query that returns the player's id, name along with the player's first match date, matchid and opponent.
I want the same information for player's last match as well.
`players`
id | name
1 | playername10
2 | playername22
3 | playername33
4 | playername45
5 | playername55
`matches`
id | gamedate | opponent
1 | 2011-01-01 | opponent1
2 | 2011-01-02 | opponent2
3 | 2011-01-03 | opponent3
4 | 2011-01-04 | opponent4
5 | 2011-01-05 | opponent5
`playermatchscores`
id | matchid | player | goals
1 | 1 | playername10 | 1
2 | 1 | playername22 | 2
3 | 2 | playername10 | 1
4 | 1 | playername33 | 1
5 | 3 | playername45 | 2
6 | 4 | playername55 | 1
7 | 2 | playername55 | 1
8 | 3 | playername22 | 2
9 | 5 | playername55 | 1
Where matchid is a foreign key to the id in table matches.
I tried several queries but I may be approaching it the the wrong way. How can I write a way to get the information I want?
Information about LEFT JOIN: http://www.w3schools.com/sql/sql_join_left.asp
SELECT players.id, MAX(matches.gamedate) AS first_match, MIN(matches.gamedate) AS last_match
FROM playermatchscores
LEFT JOIN players ON players.player = playermatchscores.player
LEFT JOIN matches ON matches.id = playermatchscores.matchid
GROUP BY players.player
I haven't tested this select.
P.S. You should use foreign key for players table too with player_id in playermatchscores.
After the changes in question:
SELECT players.*, matches.*,
FROM playermatchscores
LEFT JOIN players ON players.name = playermatchscores.player
LEFT JOIN matches ON matches.id = playermatchscores.matchid
ORDER BY matches.gamedate ASC
WHERE players.id = 3
LIMIT 1
For the last match replace ASC with DESC.
P.S. This is not the best way to do it but it should work.