MySQL Select From Two Table per Rows of First Query - php

I have two tables with like below codes:
Table: Accounts
id | username | email | registered
1 | player1 | 123#asd.ad| 2012-05-03
2 | goodman | 1345#bs.ad| 2012-06-03
3 | goodbat | asdh#asd.d| 2012-06-05
table:characters
guid | account | name | rank
213 | 1 | fres | 2
214 | 2 | sdg2 | 3
215 | 1 | fgax | 4
216 | 3 | zFvx | 8
217 | 3 | zsvx | 2
...
I want to show accounts with their highest rank character with just one Query .
output (Show Accounts with their Highest rank character)
username : player1 | 123#asd.ad | char: fgax(4)
username : goodman | 1345#bs.ad | char: sdg2(3)
username : goodbat | 134s#bs.ad | char: zFvx(8)
...
My Query:
SELECT username,email,id FROM accounts

You can try this:
SELECT a.username, a.email, c.name
FROM Accounts a, characters c
WHERE a.id=c.account
ORDER BY MAX(c.rank) DESC

SELECT a.username, a.email, a.id, c.name
FROM accounts a
JOIN chars c ON a.id = c.account
ORDER BY a.rank DESC

Try this::
SELECT
a.username as userName,
a.email as email,
a.id as id,
c.name as name
FROM accounts a
INNER JOIN chars c ON (a.id = c.accoun)t
ORDER BY a.rank DESC

What you need is a table join. What table joins do is that they query 2 tables, in your case Table1 and table2. Here is the query and it will be followed by the explanation.
SELECT `t1`.`username`, `t1`.`email`, `t2`.account
FROM `Table1` `t1`, `table2` `t2`
WHERE `t1`.`id` = `t2`.`account` ORDER BY `rank` DESC
LIMIT 0,3
LINE 1: SELECT...
t1.username means username column from t1., and so on...and the t1, t2 notation comes from...
LINE 2: FROM...
Table1 t1 means I am querying from Table1, and assigned it an alias or pointer t1. This is the same for how we assign table2 to t2.
LINE 3: WHERE...
This means that you join the tables based on a common column. In this case, both Table1 and table2 share the same set of values - id for Table1 and account for table2. Hence, you used the above line.
ORDER BY...
This means you want to arrange the records based on a certain criteria, in this case rank. There are 2 directions - ASC which means Ascending (smallest top) or DESC which means Descending.
LINE 4: LIMIT 0,3
This means I want to get the first row (0) and only 3 records. Hence, LIMIT 0,3
This is the most comprehensive explanation I could give.

Try this.
SELECT
t1.username as userName,
t1.email as email,
concat(t2.name, '(', t2.rank, ')') as name
FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.account
ORDER BY t2.rank DESC

Related

mysql join query didnt get correct out put

I have 3 tables
admin_courses
Admin_course_groups
Group_permision
admin_courses
c_id | c_name | c_status
1 | test1 | 1
2 |test2 |1
3 |test3 |1
4 test4 1
Admin_course_groups
a_id | fk_c_id |fk_g_id |start_date |end_date
1 | 1 | 1 | 2018-10-10 |2018-10-20
2 | 5 |1 | 2018-10-10 | 2018-10-20
3 | 4 |3 |2018-10-10 |2018-10-20
Group_permision
gp_id|fk_g_id|user_id
1 1 2
2 3 2
2 1 3
Here total four courses added i want to know how many course assign to each user, i have query
SELECT c_id
, c_name
, COUNT(a_id) AS nam
, MIN(start_date) as start_date
, MIN(end_date) as end_date
FROM admin_courses c
LEFT
JOIN Admin_course_groups g
ON g.fk_c_id = c.c_id
left
join Group_permision h
on g. fk_g_id=h.fk_g_id
and users_id=3
where c.c_status=1
GROUP
BY c_id
So here it will return all course, if course is assigned for user COUNT(a_id) will 1 else it 0.
Now my issue is that if users_id is 3 user assigned only 1 course but i got 3 instead of 1.
Please help me. any help would be appreciated.
You are counting wrong field. To count number of Users in a Course, you need to count user_id; Also, use Count(Distinct ...) to avoid counting a same user multiple times.
Also, note that I have added c.c_name to Group By clause, to be compatible with only_full_group_by mode. Do Read: SELECT list is not in GROUP BY clause and contains nonaggregated column .... incompatible with sql_mode=only_full_group_by
You dont need to join on user_id, to count total number of users. It restricts your data.
Try:
SELECT c.c_id
, c.c_name
, COUNT(DISTINCT h.user_id) AS nam
, MIN(g.start_date) AS start_date
, MIN(g.end_date) AS end_date
FROM admin_courses AS c
LEFT
JOIN Admin_course_groups AS g
ON g.fk_c_id = c.c_id
LEFT
JOIN Group_permision AS h
on g.fk_g_id = h.fk_g_id
WHERE c.c_status=1
GROUP
BY c.c_id,
c.c_name
Your question is missing some crucial information, but if I understood the problem correctly, I would simply try to add Distinct to the count :
SELECT `c_id`, `c_name`, COUNT(distinct `a_id`)
....

How to select first row only in 2nd table of inner join query

I'm using the following query to select data from 3 different tables. tbl_invoices and tbl_clients have unique records. Each tbl_invoices record has multiple tbl_invoice_entries records:
$query = 'SELECT T1.*, T2.*, T3.*
FROM tbl_invoices T1
LEFT JOIN tbl_invoice_entries T2
ON T1.number = T2.invoice_number
LEFT JOIN tbl_clients T3
ON T1.client = T3.client_id
WHERE date_format(date, '%Y') = ".$_POST['year']." AND date_format(date, '%c') = ".$_POST['month']." ORDER BY date, number ASC'
$stmt = $conn->prepare($query)
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
This currently returns all records in tbl_invoice_entries. How do I change my query in order to only return the first tbl_invoice_entries record for each tbl_invoices record.
Here are the tables:
tbl_clients
+----+-----------+----------+
| id | firstname | lastname |
+----+-----------+----------+
| 1 | John | Doe |
| 2 | Jane | Doe |
+----+-----------+----------+
tbl_invoices
+----+--------+--------+------------+
| id | number | client | date |
+----+--------+--------+------------+
| 1 | 14 | 1 | 2015-07-14 |
| 1 | 15 | 2 | 2015-07-14 |
+----+--------+--------+------------+
tbl_invoice_entries
+----+----------------+------------+
| id | invoice_number | produkt |
+----+----------------+------------+
| 1 | 14 | Fish |
| 2 | 14 | Bread |
| 3 | 15 | Vegetables |
| 4 | 15 | Fruit |
+----+----------------+------------+
So the results I'm looking for are:
John Doe 14 Fish 2015-07-14
Jane Doe 15 Vegetables 2015-07-14
Thanks for any help!
By linking the invoice_entries table not directly through the invoice number but by the id of its first entry you can achieve what you want:
SELECT firstname,lastname,number,product,date
FROM tbl_invoices T1
LEFT JOIN tbl_invoice_entries T2
ON T2.id =(select min(id) from tbl_invoice_entries
where invoice_number=number)
LEFT JOIN tbl_clients T3
ON T1.client = T3.id
WHERE ...
You need to tell the RDBMS what you intend by the first row. There is no natural order in tuples. If you want the tuple with lowest ID given the same invoice_number, then it would require another query
SELECT tbl1.* FROM tbl_invoice_entries AS tbl1
JOIN ( SELECT MIN(id) AS id, invoice_number FROM tbl_invoice_entries
GROUP BY invoice_number ) AS tbl2
USING (id);
The above query is equivalent to tbl_invoice_entries but only has the lowest ID of each invoice number. You can do it as a VIEW (actually two, since you can't use subqueries in a VIEW):
CREATE VIEW tbl_invoice_entries_firstnumber AS
SELECT MIN(id) AS id, invoice_number
FROM tbl_invoice_entries
GROUP BY invoice_number;
CREATE VIEW tbl_invoice_entries_first AS
SELECT tbl1.* FROM tbl_invoice_entries AS tbl1
JOIN tbl_invoice_entries_firstnumber
USING (id);
After that you can use tbl_invoice_entries_first instead of tbl_invoice_entries in your current query.
Keep in mind that the view is dynamic, so it is only a shorthand for a more complex query. This means that your current query will become more complicated and require a longer time:
SELECT T1.*, T2.*, T3.*
FROM tbl_invoices AS T1
LEFT JOIN tbl_invoice_entries_first AS T2
ON T1.number = T2.invoice_number
LEFT JOIN tbl_clients AS T3
ON T1.client = T3.id; -- you have no client_id in T3
I have set up a fiddle here.
Or you can modify your query more, and add a JOIN condition on T2 so that it only fetches, again, the minimum ID - or whatever ordering condition you prefer:
SELECT T1.*, T2.*, T3.*
FROM tbl_invoices AS T1
LEFT JOIN tbl_invoice_entries AS T2
ON (
-- (( T1.number = T2.invoice_number AND )) --
T2.id = (
SELECT MIN(id) FROM tbl_invoice_entries
WHERE invoice_number = number
))
LEFT JOIN tbl_clients AS T3
ON T1.client = T3.id;
UPDATE: The check on number was commented out (see also #cars10's solution) because it is carried over by the inner subquery.
Finally you can do this in code, i.e. you save the value of the previous tuple and order the query as needed; then discard all unneeded tuples. If you have few entries per invoice, this might be worthwhile:
// pseudo code
if (prev.client == tuple.client)
and
(prev.invoice == tuple.invoice)
continue;
prev = tuple;
-- use tuple.

Issue with adding fields of multiple tables

I have three tables with same structure.
table1
id | email | count
1 | test1#abc.com | 5
2 | test2#abc.com | 5
3 | test3#abc.com | 5
table2
id | email | count
1 | test1#abc.com | 50
2 | test1#abc.com | 50
3 | test3#abc.com | 50
table3
id | email | count
1 | test1#abc.com | 40
2 | test1#abc.com | 45
3 | test1#abc.com | 50
Now what i want is for table1, for first record "test1#abc.com", I need sum of "count" field of next two tables. So i used below query
SELECT (IFNULL(sum(distinct(table2.count)), 0) +
IFNULL(sum(distinct(table3.count)), 0)) as total
FROM table1
LEFT JOIN table2 ON table1.email = table2.email
LEFT JOIN table3 ON table1.email = table3.email
WHERE table1.email = 'test1#abc.com'
This query gives me below record:
185
But the result should be as below:
235
This is because i have used distinct when adding field. But if i don't use distinct, it gives me 285.
Please help. What should i do?
Your issue is because, first, you're using LEFT JOIN (no sense with summation since NULL-records will provide nothing), second, that's how JOIN works. Illustrate with query:
SELECT
t1.id AS id_1,
t1.email AS email_1,
t1.count AS count_1,
t2.id AS id_2,
t2.email AS email_2,
t2.count AS count_2,
t3.id AS id_3,
t3.email AS email_3,
t3.count AS count_3
FROM
table1 AS t1
INNER JOIN table2 AS t2 ON t1.email=t2.email
INNER JOIN table3 AS t3 ON t1.email=t3.email
WHERE
t1.email='test1#abc.com'
(fiddle is here). As you can see, you'll get repeated id's from second and third tables - and - yes, that's because there are multiple rows for joining condition.
To resolve your issue you may add distinction by id into join (and later filtering that with variables or like that), but I would not recommend it. JOIN is simply not the thing for your issue. Use UNION, like:
SELECT
SUM(`count`) AS s
FROM
(
SELECT
table2.count
FROM
table2
WHERE
email='test1#abc.com'
UNION ALL
SELECT
table3.count
FROM
table3
WHERE
email='test1#abc.com'
) AS u
(see the fiddle)

Show "0" in COUNT column when WHERE does not match?

What I would like to do is retrieve all data from a table, and order them by the number of games the user played in a specific category. Is there any way I can use some sort of "COUNT WHERE" sql statement?
here's what i have so far. it will only return the user if they have played a game in the "fps" category, but I want it to show all users in descending order even if they have not played an fps game. please excuse my crappy tables
SELECT user_data.user, COUNT(played_games.game_cat) as 'count'
FROM user_data, played_games
WHERE user_data.user_id = played_games.user_id and played_games.game_cat = 'fps'
GROUP BY user_data.user_id
ORDER BY 'count' DESC;
user_data table
user_id | user
1 | jeff
2 | herb
3 | dug
played_games table
id | user_id | game | game_cat
1 | 2 | kill | fps
2 | 1 | shoot| fps
3 | 2 | COD | fps
4 | 3 | dogs | cas
You need a LEFT OUTER JOIN to get the records even if a corresponding record does not exist in the other table.
SELECT user, coalesce(count(game_cat), 0) as count
FROM user_data LEFT OUTER JOIN played_games
ON user_data.user_id = played_games.user_id AND played_games.game_cat='fps'
GROUP BY user_data.user_id
ORDER BY count desc;
Gives the following result on my screen
+------+-------+
| user | count |
+------+-------+
| herb | 2 |
| jeff | 1 |
| dug | 0 |
+------+-------+
This is how I'd do it. No subquery, no COALESCE, no COUNTIF junk.
SELECT `users`.`user`, COUNT(`played_games`.id) AS `c`
FROM `users`
LEFT OUTER JOIN `played_games` ON
`users`.`user_id` = `played_games`.`user_id`
AND `played_games`.`game_cat` = "fps"
GROUP BY `users`.`user_id`
ORDER BY `c` DESC, `user` ASC
SQLFiddle (not sure if you can link them like this...)
Try this:
SELECT ud.user, coalesce(sum(pg.game_cat = 'fps'), 0) Total
FROM user_data ud
LEFT JOIN played_games pg ON ud.user_id = pg.user_id
GROUP BY ud.user_id
ORDER BY Total DESC
This will show all users and the amount of times they've played a game with category 'fps'.
The coalesce one is promising, but doesn't work for me, sigh~ I just found NULLIF is a good way to solve this problem. Remember to use LEFT JOIN
COUNT( NULLIF(TABLE.ATTR, 1) ) AS total_count
The TABLE.ATTR is some field that can be NULL, here is an example:
SELECT Posts.*, COUNT( NULLIF(Comments.user_email, 1) ) as comment_num
FROM (`Posts`)
LEFT OUTER JOIN `Comments` ON `Comments`.`post_id` = `Posts`.`id`
GROUP BY `Posts`.`id`
LIMIT 5
Got the idea from http://www.bennadel.com/blog/579-SQL-COUNT-NULLIF-Is-Totally-Awesome.htm
Below query the all game category with user id and order by count
select * from (SELECT user_data.user, COUNT(played_games.game_cat) as 'count'
FROM user_data, played_games
WHERE user_data.user_id = played_games.user_id(+) GROUP BY user_data.user_id)
order by count desc

Mysql Query: error that says subquery returns more than 1 row

I am trying to do a complex query from two tables...It's a question from a skill quiz.
table
**Orders Customer**s
id id
date first_name
shipping_amount last_name
order_status city
customer_id (Customers.id) state
output
-----------+------------+
| State | # Orders |
+-----------+------------+
| NY | 55 |
| CA | 40 |
| NJ | 33 |
| FL | 21 |
| MO | 12 |
+-----------+------------+
I have been working on my query and it looks like this...
select DISTINCT state, (select count(id) Orders
from customers
group by state
ORDER BY Orders DESC) FROM Customers
It gave me an error that says subquery returns more than 1 row
Try this:
SELECT c.state, COUNT(o.id) AS Orders
FROM Customers c, Orders o
WHERE o.customer_id = c.id
GROUP BY state
ORDER BY Orders DESC
The sub query isn't necessary.
SELECT `Customers`.`state`, count(`Orders`.`id`)
as `orders FROM `Customers`
LEFT JOIN `Orders` ON `Customers`.`id` = `Orders`.`customer_id`
GROUP BY `Customers`.`state`
ORDER BY `orders` DESC
Try this:
select DISTINCT state, (select count(id) as cnt, Orders from customers group by
state ORDER BY Orders DESC) Temp FROM Customers
SELECT c.state as State, COUNT(o.id) as NumOrders
FROM orders o
LEFT JOIN customers c ON (c.id = o.customer_id)
GROUP BY c.state

Categories