I have used this sql statement in my database that uses COUNT and UNION ALL
SELECT tem.book_id, COUNT( * )
FROM(SELECT book_id FROM borrowdetails
WHERE borrowdetails.borrow_status = 'returned'
UNION ALL
SELECT book_id from reserve) as tem
GROUP BY book_id
ORDER BY book_id DESC
then i used this code to name the id in the PHP table
while($row=mysql_fetch_array($user_query)){
$id=$row['book_id'];
$book_query = mysql_query("select * from book where book_id = '$id'")or die(mysql_error());
}
it works fine but it doesn't unite the data with the same name because it has different id's like this
+------+------+-------+
| id | name | count |
+------+------+-------+
|1 |A | 3 | the id here is not shown at the table in PHP just
+------+------+-------+ inside the database but the A is duplicate.
|2 |A | 1 |
+------+------+-------+
|3 |B | 2 |
+------+------+-------+
my desired output should be like this without the id showing in the table.
+------+-------+
| name | count |
+------+-------+
|A | 4 |
+------+-------+ this is the table that should be shown in PHP
|B | 2 |
+------+-------+
as you could see the name A's count becomes four because i want also to add the COUNT(*) of both A's.
What am i going to do in order to achieve the desired outcome?
btw this is the db tables that are used.
+------+------+ +---------+---------+ +-------+-------+
| book table | |borrowdetails table| | reserve table |
+------+------+ +---------+---------+ +-------+-------+
| id | name | |brw_dt_id| book_id | |res_id |book_id|
+------+------+ +---------+---------+ +-------+-------+
|1 |A | | 1 | 2 | | 1 | 1 |
+------+------+ +---------+---------+ +-------+-------+
|2 |A | | 2 | 3 | | 2 | 1 |
+------+------+ +---------+---------+ +-------+-------+
|3 |B | | 3 | 3 | | 3 | 1 |
+------+------+ +---------+---------+ +-------+-------+
You would want to use book_name rather than using book_id.
I haven't tried this, but it should work
Select book_name, count(*) as cnt from books
where book_id IN (
SELECT book_id FROM borrowdetails
WHERE borrowdetails.borrow_status = 'returned'
UNION ALL
SELECT book_id from reserve
)
GROUP BY Book_Name
ORDER BY Cnt
We would normally write that this way
SELECT book_name
, count(*) cnt
FROM books x
JOIN
( SELECT book_id
FROM borrowdetails
WHERE borrowdetails.borrow_status = 'returned'
UNION ALL
SELECT book_id from reserve
) y
ON y.book_id = x.book_id
GROUP BY Book_Name -- this assumes that book_name is unique
ORDER BY Cnt
Related
I have two table, Temp_Table and Actual_Table. I upload csv file that only contain field home_id for the first time and will insert to Temp_Table then insert to Actual_Table. Field id is auto incremented and home_run is field that will generate after user input process.
This is the code i use to generate home_run based on home_id then insert to actual table.
$query1 = "UPDATE Temp_Table AS p JOIN (
SELECT t.id,(SELECT count(*) FROM Temp_Table
WHERE home_id = t.home_id AND id <= t.id) AS home_run FROM Temp_Table t)
AS g ON p.id = g.id SET p.home_id = g.home_id";
$query2 = "INSERT INTO Actual_Table (home_id, home_run) SELECT (home_id, home_run) FROM Temp_Table";
$query3 = "SELECT MAX(home_run) FROM Actual_Table GROUP BY home_id";
This is example of data in Actual_Table after first time i upload the csv file.
Data in Actual_Table (Table 1)
+---------------------------+
|id | home_id | home_run |
|1 | H01 | 1 |
|2 | H01 | 2 |
|3 | H01 | 3 |
|4 | H02 | 1 |
+---------------------------+
Let say, i upload csv file for second time and this is the data in Temp_Table.
Example Data in Temp_Table (Table 2)
+---------------------------+
|id | home_id | home_run |
|1 | H01 | 1 |
|2 | H01 | 2 |
|3 | H02 | 1 |
+---------------------------+
I need to insert value from Temp_Table to Actual_Table and continuously count the home_run. Example from the Table 1, i get the highest home_run for each id. H01 = 3, H02 = 1.
So i plan to do calculation based on home_id: (Highest home_run) 3 + (Temp_Table home_run) x. x is 1 and 2 for H01 and x is 1 for H02.
At the end, the Actual_Table will be like this
ORDER BY id
+---------------------------+
|id | home_id | home_run |
|1 | H01 | 1 |
|2 | H01 | 2 |
|3 | H01 | 3 |
|4 | H02 | 1 |
|5 | H01 | 4 |
|6 | H01 | 5 |
|7 | H02 | 2 |
+---------------------------+
ORDER BY home_run
+---------------------------+
|id | home_id | home_run |
|1 | H01 | 1 |
|2 | H01 | 2 |
|3 | H01 | 3 |
|5 | H01 | 4 |
|6 | H01 | 5 |
|4 | H02 | 1 |
|7 | H02 | 2 |
+---------------------------+
It is possible to do this? I am stuck and do not have idea to create the query for the calculation.
Below are my ways of achieving this but I'm sure there are better solutions out there.
1st of all, get the maximum ID out of actual table (Mark as A):
SELECT MAX(id) FROM Actual_Table
Then, get the maximum home_run of each home_id (Mark as B):
SELECT MAX(home_run) FROM Actual_Table Group By home_id
Finally, join them together into a SELECT statement:
SELECT MAX(A.id) + T.id, T.home_id, T.home_run + MAX(B.home_run)
FROM Temp_Table T, Actual_Table A, Actual_Table B
WHERE T.home_id = B.home_id
GROUP BY T.id, T.home_id, T.home_run
The rest is just simply changing the SELECT statement into INSERT statement.
INSERT INTO Actual_Table
SELECT MAX(A.id) + T.id, T.home_id, T.home_run + MAX(B.home_run)
FROM Temp_Table T, Actual_Table A, Actual_Table B
WHERE T.home_id = B.home_id
GROUP BY T.id, T.home_id, T.home_run
I have these tables...
GROUP_MEMBERS
+---------------------------------+
| id | group_id | member_id |
+---------------------------------+
| 1 | 1 | 1 |
| 2 | 1 | 4 |
+---------------------------------+
MEMBERS
+-------------------------------------+
| id | first | last | role_id |
+-------------------------------------+
| 1 | Jack | Jones | 1 |
| 2 | Jane | Doe | 2 |
| 3 | Bob | Bee | 2 |
| 4 | Jen | Nee | 1 |
+-------------------------------------+
GROUPS
+-----------------+
| id | name |
+-----------------+
| 1 | group1 |
| 2 | group2 |
+-----------------+
As it is, I am using the following query...
SELECT
(members.id) AS memid,
members.first,
members.last,
members.role_id
FROM
members
LEFT JOIN group_members ON
members.id = group_members.member_id
WHERE
group_members.member_id IS NULL
GROUP BY
members.id;
This outputs the members (Jane and Bob) who are not in the 'GROUP_MEMBERS' table as it should, but what I am trying get working is if I am on and another group ($_GET['group_id']), how can I show all members that do not have rows that match group_id and member_id on the 'GROUP_MEMBERS' table...
i.e if group_id = '2' show all members
I have tried adding in WHERE clause... AND group_members.group_id IS NULL.. but it shows nothing then.
Does anyone have a query which would get the output I'm looking for?
Thanks
[EDITED]
Just to clarify...
If my url had 'group_id=1'
I should see:
Bob
Jane
If my url has 'group_id=2'
I should see:
Jack
Jane
Bob
Jen
So it only shows 'members' that do not exist( with the 'group_id' in the url) in the 'GROUP_MEMBERS' table
If I have understood the question correctly, you are looking for something like I have made on this fiddle:
DB Fiddle
The query I use is:
$sql = 'SELECT * FROM groups
RIGHT JOIN group_members ON groups.id = group_id
RIGHT JOIN members ON member_id = members.id
WHERE group_id <> ? OR group_id is NULL;'
$group_id = $_GET['group_id'];
$query = $mysqli->prepare($sql);
$query->bind_param('i', $group_id);
In short, this query will select from the groups table, ensuring that we will select every group in your database.
Then we will join the other two tables completely (using the RIGHT JOIN).
Finally, we are going to select every member that isn't the specified the one provided by the URL, or any member that is not in a group.
You can use a sub-query
how can I show all members that do not have rows that match 'group_id'
$group_id= $_GET['group_id'];
$q = "SELECT * FROM MEMBERS WHERE MEMBERS.id NOT IN(
SELECT member_id FROM GROUP_MEMBERS WHERE group_id='$group_id'
);";
Explanation
SELECT member_id FROM GROUP_MEMBERS WHERE group_id='$grID'
this will get all the members in this group by a given ID
then you select all members that are not among them.
SELECT * FROM MEMBERS WHERE MEMBERS.id NOT IN()
this one will give members data except the ids inside the brackets
the sub query will get the ids of members in a given group
no need for joining the three tables since you are using id of the group existing in GROUP_MEMBERS and linking the GROUP and MEMBERS
one side note
if you have a group name and what all users not in this group you then will need to use the GROUPS table
SELECT * FROM MEMBERS WHERE MEMBERS.id NOT IN(
SELECT member_id FROM GROUP_MEMBERS WHERE group_id = (
SELECT id from GROUPS WHERE name = '$Group_Name'
)
);
you may use WHERE group_id IN (...) it will work the same
This is a demonstration, I created same database with same data and tested the queries
+----+-------+-------+---------+
| id | first | last | role_id |
+----+-------+-------+---------+
| 1 | Jack | Jones | 1 |
| 2 | Jane | Doe | 2 |
| 3 | Bob | Bee | 2 |
| 4 | Jen | Nee | 2 |
+----+-------+-------+---------+
+----+--------+
| id | name |
+----+--------+
| 1 | group1 |
| 2 | group2 |
+----+--------+
+----+----------+-----------+
| id | group_id | member_id |
+----+----------+-----------+
| 1 | 1 | 1 |
| 2 | 1 | 4 |
+----+----------+-----------+
I run the sub-query as above and the results as expected,
MariaDB []> select * from members where id not in
(select member_id from group_members where group_id = 1);
+----+-------+------+---------+
| id | first | last | role_id |
+----+-------+------+---------+
| 2 | Jane | Doe | 2 |
| 3 | Bob | Bee | 2 |
+----+-------+------+---------+
similar for when you have group name
MariaDB []> select * from members where id not in
(select member_id from group_members where group_id =
(select id from groups where name='group1'));
+----+-------+------+---------+
| id | first | last | role_id |
+----+-------+------+---------+
| 2 | Jane | Doe | 2 |
| 3 | Bob | Bee | 2 |
+----+-------+------+---------+
I have 2 tables in database:
How can I get total user for each group. i.e: group 1: total are 2 users;
group2: total are 2 users;
group3: total is 1 user
You need normalization and never store comma-separated data.
Consider the following
mysql> select * from user_table ;
+---------+---------------+
| user_id | user_group_id |
+---------+---------------+
| 1 | 1,2 |
| 2 | 2 |
| 3 | 1,3 |
+---------+---------------+
3 rows in set (0.00 sec)
mysql> select * from group_table ;
+----------+------------+
| group_id | group_name |
+----------+------------+
| 1 | a |
| 2 | b |
| 3 | c |
+----------+------------+
3 rows in set (0.00 sec)
The above data is not normalized and to get the desired result out of these you need to use some in-efficient query as
select
g.group_id,
count(*) as total
from group_table g
left join user_table u on find_in_set(g.group_id,u.user_group_id) > 0
group by g.group_id ;
+----------+-------+
| group_id | total |
+----------+-------+
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
+----------+-------+
Now lets do normalization and store user-group data in a different table as
mysql> select * from user_to_group ;
+---------+----------+
| user_id | group_id |
+---------+----------+
| 1 | 1 |
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
| 3 | 3 |
+---------+----------+
You can easily write different queries from these tables now and here are some examples
select group_id,count(*) as tot from user_to_group group by group_id ;
+----------+-----+
| group_id | tot |
+----------+-----+
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
+----------+-----+
Joining the tables would even more easy
select
g.group_id,
g.group_name,
count(*) as tot
from user_to_group ug
join group_table g on g.group_id = ug.group_id
join user_table u on u.user_id = ug.user_id
group by g.group_id
+----------+------------+-----+
| group_id | group_name | tot |
+----------+------------+-----+
| 1 | a | 2 |
| 2 | b | 2 |
| 3 | c | 1 |
+----------+------------+-----+
SELECT group_name, COUNT(*) FROM user_table u, group_table g WHERE u.user_group_id LIKE %g.group_id% GROUP BY g.group_name;
this should work and give you a list of all groups and how many users are in them.
I will recommend you to create a third table which holds the information about which users are in which groups.
CREATE TABLE users_in_groups
(
user_id INT
, group_id INT
);
Then you can join like this:
SELECT
gt.group_id
, count(ut.user_id)
FROM
user_table AS ut
, INNER JOIN users_in_groups AS uig ON uig.user_id = ut.user_id
, INNER JOIN group_table AS gt ON gt.group_id = uig.group_id
GROUP BY
gt.group_id
;
To use the table you have now will you have to do something like this (in mysql):
SELECT
gt.group_id
, count(ut.user_id)
FROM
user_table AS ut
, INNER JOIN group_table AS gt ON LOCATE(gt.group_id, ut.user_group_id) > 0
GROUP BY
gt.group_id
Remember, when using group by, always locate what makes your group unique!
This is not an answer to your specific question but rather an alternative data structure proposal that might be better.
Introduce a new table members that looks like
# members
user_id | group_id
1 | 1
1 | 2
2 | 2
3 | 1
3 | 3
Then you could SELECT group_id, count(*) FROM members GROUP BY group_id
+----------+----------+
| group_id | count(*) |
+----------+----------+
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
+----------+----------+
This structure might also make it easier for you to manage your memberships. user_id + group_id should be unique. And if supported let them be foreign keys.
I'm trying to build a query using data from 4 tables: Bookings, Users, Events, Locations
Bookings :
+---------------------------------+
|book_id | event_id | person_id |
+---------------------------------+
|1 | 1 | 2 |
|2 | 2 | 1 |
|3 | 2 | 2 |
|4 | 1 | 3 |
|5 | 3 | 1 |
|6 | 3 | 2 |
+---------------------------------+
Users :
+----------------------+
| user_id | name |
+----------------------+
| 1 | Joe |
| 2 | Jack |
| 3 | Jane |
+----------------------+
Events :
+------------------------+
| event_id | location_id |
+------------------------+
| 1 | 1 |
| 2 | 3 |
| 3 | 1 |
+------------------------+
Locations :
+---------------------------+
| location_id | name |
+---------------------------+
| 1 | Lombard |
| 2 | NYC |
| 3 | LA |
+---------------------------+
The query that I can't seem to write should get me to display a table like this :
+------------------------------+
+Name |Lombard|NYC|LA|Total|
+------------------------------+
+Joe |1 |0 |1 |2 |
+Jack |2 |0 |1 |3 |
+Jane |1 |0 |0 |1 |
+------------------------------+
+Totals |4 |0 |2 |6 |
+------------------------------+
What I got to work is displaying how many booking have been made per user but not per user AND per location using this query:
$query='
SELECT
bookings.person_id,
COUNT(bookings.person_id) AS total,
bookings.event_id,
users.display_name
FROM bookings
INNER JOIN users ON bookings.person_id=users.id
WHERE users.id=bookings.person_id
GROUP BY bookings.person_id';
$result = mysql_query($query);
if($result) {
while($row = mysql_fetch_array($result))
{
/* total bookings per user */
$value = $row['total'];
$sum += $value;
/* Displaying results */
echo "<tr width='500'>";
echo "<td>".$row['person_id']."</td>";
echo "<td>".$row['display_name']."</td>";
echo "<td>".$row['total']."</td>";
echo "</tr>";
}
This works okay and displays :
+-----------------------------------+
| ID | NAME | Total Bookings |
+-----------------------------------+
| 7 | Bob | 3 |
| 5 | Jane | 2 |
| 3 | Joe | 1 |
+-----------------------------------+
Could you please help me getting there. Thanks.
You are looking for a pivot table style query. Here's one way you can do it.
select u.name,
count(case when l.name = 'Lombard' then 1 end) as lombard,
count(case when l.name = 'NYC' then 1 end) as nyc,
count(case when l.name = 'LA' then 1 end) la,
count(u.name) total
from bookings b
inner join events e
on b.event_id = e.event_id
inner join locations l
on e.location_id = l.location_id
inner join users u
on u.user_id = b.person_id
group by u.name
with rollup
fiddle here
It gets a lot harder (and is generally easier to do in the application) if you dont know the possible column (location) values when you are writing the query.
http://sqlfiddle.com/#!9/92d50
SELECT u.name,
SUM(l.name = 'Lombard') lombard,
SUM(l.name = 'NYC') nyc,
SUM(l.name = 'LA') la,
COUNT(*) total
FROM bookings b
LEFT JOIN `events` e
ON b.event_id = e.event_id
LEFT JOIN locations l
ON e.location_id = l.location_id
LEFT JOIN users u
ON u.user_id = b.person_id
GROUP BY u.name
WITH ROLLUP
I having two tables
table 1: users
| id | username |
| 1 | john |
| 2 | marry |
| 3 | deep |
| 4 | query |
| 5 | value|
and
table 2:users_2
| table_2_id | user_id |
| 1 | 2,4 |
I need required something like this
| table_2_id | username |
| 1 | marry,query |
anyone can help me for this output in mysql
Is this what you are looking ?
select
`users_2`.`table_2_id` , GROUP_CONCAT(`users`.`username`) as `usernames`
from `users_2`
inner join `users` on FIND_IN_SET(`users`.`id`,`users_2`.`user_id`)
Check output here
http://sqlfiddle.com/#!2/c498bc/3
select a.table_2_id,b.username
from users b,users_2 a
where a.table_2_id=b.id
and b.id in(a.user_id)
group by a.table_2_id
First of all, you should not store a multiple value in a single field. For table users_2, the data should be:
table_2_id user_id
1 2
1 4
After you normalized your table, you can use mysql GROUP_CONCAT() to get the result in the format you mentioned
SELECT
users_2.table_2_id,
GROUP_CONCAT(users.username) AS username
FROM
users_2
JOIN
users ON users.id = users_2.user_id
GROUP BY
users_2.table_2_id
;