I have a tagging system for my events system I would like to create a 'tag cloud'.
I have Events, which can have multiple 'categories'.
Here's the table structure:
**Event_Categories** (Stores Tags / Categories)
| id | name |
+-----------------+
+ 1 | sport |
+ 2 | charity |
+ 3 | other_tag |
**Events_Categories** (Linking Table)
| event_id | event_category_id |
+-------------------------------+
+ 1 | 1 |
+ 2 | 2 |
+ 3 | 1 |
+ 3 | 2 |
Summary:
Event ID 1 -> Sport
Event ID 2 -> Charity
Event ID 3 -> Sport, Charity
I'd like to return the following:
| tag_name | occurrences |
+-----------+-------------+
| sport | 2 |
| society | 2 |
other_tag - Not actually returned, as it has 0 occurrences
Thanks! :)
this will work:
SELECT c.name AS tag_name, COUNT(ec.event_id) AS occurrences
FROM Event_Categories c
INNER JOIN Events_Categories ec ON c.id = ec.event_category_id
GROUP BY c.id
change the INNER JOIN to LEFT JOIN if you want to include categories with 0 occurances
How about something like
SELECT e.name,
COUNT(1)
FROM Event_Categories e INNER JOIN
Events_Categories_Linking ec ON e.id = ec.event_category_id
GROUP BY e.name
SQL Fiddle DEMO
Related
I work with PHP and PDO.
So I have 2 tables like,
Table 1
| id | name | age |
| 1 | John | 25 |
| 2 | Tom | 32 |
| 3 | James| 45 |
Table 2
| id | Comment | Link |
| 1 | some text | 3 |
| 2 | some text | 3 |
| 3 | some text | 1 |
So, Link column numbers represent id's in table1. For example Link = 3s in table 2 represent James in table 1. I need a query which brings all table1's data and also a number of repeated value for related Link column which comes from table2.
For example, the query should give me (let's choose James),
| id | name | age | Value |
| 3 | James | 45 | 2 |
value=2, because there are two 3s in link column which related to James
I tried somethings but got lots of errors.
I think you just need the GROUP BY
SELECT a.id,
a.name,
a.age,
count(*) as value
FROM table1 a
JOIN table2 b ON a.id = b.link
GROUP BY a.id, a.name, a.age
If you really want just one row then add WHERE
SELECT a.id,
a.name,
a.age,
count(*) as value
FROM table1 a
JOIN table2 b ON a.id = b.link
WHERE a.name = 'James'
GROUP BY a.id, a.name, a.age
or use subquery
SELECT a.id,
a.name,
a.age,
(SELECT count(*) FROM table2 b WHERE a.id = b.link) as value
FROM table1 a
WHERE a.name = 'James'
I have a database with tables like below:
Reviews
id | review | companyid
companies
id | name
Now i want to get the data back so that i can show each company name with the total number of reviews for the company. Like seen below:
company 1 (company name) | 345
company 2 (company name) | 28
company 3 (company name) | 794
From here i will make a table using php to display the results
How can i achieve this with MYSQl?
Try this way:
SELECT Count(`r`.`review`) AS `total_reviews`,
`c`.`company`
FROM `reviews` AS `r`
JOIN `companies` AS `c`
ON `c`.`id` = `r`.`companyid`
Use COUNT and GROUP BY to count the reviews per company and use JOIN to get the company name from the other table.
Query
select t2.name as companyName,coalesce(t1.`count`,0) as `count` from
(
select companyid,count(companyid) as `count`
from reviews
group by companyid
)t1
right join companies t2
on t1.companyid= t2.id;
Sample Output
Table - reviews
+----+--------+-----------+
| id | review | companyid |
+----+--------+-----------+
| 1 | r1 | 1 |
| 2 | r2 | 2 |
| 3 | r3 | 1 |
+----+--------+-----------+
Table - companies
+----+------+
| id | name |
+----+------+
| 1 | C1 |
| 2 | C2 |
| 3 | C3 |
+----+------+
Output
+------+-------+
| name | count |
+------+-------+
| C1 | 2 |
| C2 | 1 |
| C3 | 0 |
+------+-------+
SQL Fiddle
You need to use a GROUP BY
SELECT r.companyid, c.name, count(r.id) as nb_review
FROM reviews r
INNER JOIN companies c ON (r.companyid = c.id)
GROUP BY r.companyid, c.name;
If you also want to see the companies with no reviews, do :
SELECT c.id, c.name, count(r.id) as nb_review
FROM companies c
LEFT JOIN reviews r ON (r.companyid = c.id)
GROUP BY c.id, c.name;
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.
In MySQL is it possible to select columns from one table while also creating a column for COUNT(*) based on other tables? That way a summary of the results from all tables can be returned. This might be a bit confusing to explain in words so I made some sample tables instead:
events_tbl
----------------------------
id | eventname
1 | Anime Festival
2 | Food Festival
----------------------------
booths_tbl
-------------------------
id | boothname
1 | Walmart
2 | Pizza Hut
3 | Nike
4 | North Face
-------------------------
participants_tbl
-----------------------------
id | participantname
1 | John
2 | Mike
3 | Rambo
4 | Minnie
-----------------------------
event_booths_tbl
--------------------------------
event_id | booth_id
1 | 1
1 | 2
1 | 5
2 | 3
2 | 4
--------------------------------
event_participants_tbl
-------------------------------------
event_id | booth_id
1 | 1
1 | 2
1 | 3
1 | 4
-------------------------------------
Is there a way to get results like this in MySQL:
summary_tbl
------------------------------------------------------------------------
id | eventname | booth_count | participant_count
1 | Anime Festival | 3 | 4
2 | Food Festival | 2 | 0
------------------------------------------------------------------------
The event_participants_tbl should contain participant_id instead of booth_id.
Its irrelevant otherwise.
Your MySQL query would be like this :
select
et.id,
et.eventname,
count(distinct ebt.booth_id) as booth_count,
count(distinct ept.participant_id) as participant_count
from
event_booths_tbl ebt
left join events_tbl et on et.id=ebt.event_id
left join event_participants_tbl ept on ept.event_id=ebt.event_id
group by et.event_id;
Join with subqueries that count in each table:
SELECT e.id, e.event_name,
IFNULL(b.booth_count, 0) AS booth_count,
IFNULL(p.participant_count, 0) AS participant_count
FROM events_table AS e
LEFT JOIN (SELECT event_id, COUNT(*) AS booth_count
FROM event_booths_table
GROUP BY event_id) AS b ON e.id = b.event_id
LEFT JOIN (SELECT event_id, COUNT(*) AS participant_count
FROM event_participants_table
GROUP BY event_id) AS p ON e.id = p.event_id
Try this :
select event.id,
event.name,
count(distinct eventBooth.booth_id),
count(distinct eventParitcipant.booth_id)
from events_tbl event
LEFT JOIN event_booths_tbl eventBooth on eventBooth.event_id=event.id
LEFT JOIN event_participants_tbl eventParitcipant
on eventParitcipant.event_id=event.id
group by event.id
I have two tables : ticket & history_ticket
Table ticket :
ticket_id | ticket_desc
1 | software
2 | hardware
3 | other
Table history_ticket :
history_id | ticket_id | message | status
1 | 1 | text | process
2 | 2 | text | solve
3 | 3 | text | process
4 | 3 | text | solve
I want result like this
ticket_id | ticket_desc | status
1 | software | process
2 | hardware | solve
3 | other | solve
I've tried various joins and subselects, but no luck
Any help/directions will be much appreciated!
UPDATE : How if i change the result, like this
ticket_id | ticket_desc | last_status | count_message
1 | software | process | 1
2 | hardware | solve | 1
3 | other | solve | 2
Try this:
SELECT
t.ticket_id,
ticket_desc,
ht.status
FROM ticket AS t
INNER JOIN history_ticket AS ht ON t.ticket_id = ht.ticket_id
INNER JOIN
(
SELECT ticket_id, MAX(history_id) maxid
FROM history_ticket
GROUP BY ticket_id
) AS ht2 ON ht.history_id = ht2.maxid;
SQL Fiddle Demo
This will give you:
| TICKET_ID | TICKET_DESC | STATUS |
-------------------------------------
| 1 | software | process |
| 2 | hardware | solve |
| 3 | Problem | solve |
UPDATE 1
To get the count of messages for each ticket, you can simply include COUNT(history_id) AS sum_message in the subquery like this:
SELECT
t.ticket_id,
ticket_desc,
ht.status,
ht2.sum_message
FROM ticket AS t
INNER JOIN history_ticket ht ON t.ticket_id = ht.ticket_id
INNER JOIN
(
SELECT
ticket_id,
MAX(history_id) maxid,
COUNT(history_id) AS sum_message
FROM history_ticket
GROUP BY ticket_id
) AS ht2 ON ht.history_id = ht2.maxid;
Updated SQL Fiddle Demo
This will give you:
| TICKET_ID | TICKET_DESC | STATUS | SUM_MESSAGE |
---------------------------------------------------
| 1 | software | process | 1 |
| 2 | hardware | solve | 1 |
| 3 | Problem | solve | 2 |
Update 2
If you want to select names for the ids divisi_id, for simple values, you can use the CASE expression for this:
SELECT
t.ticket_id,
ticket_desc,
CASE
WHEN t.divisi_id = 101 THEN 'Divisi A'
WHEN t.divisi_id = 102 THEN 'Divisi B'
END AS 'Divisi',
ht.status,
ht2.sum_message
FROM ticket AS t
INNER JOIN history_ticket ht ON t.ticket_id = ht.hticket_id
INNER JOIN
(
SELECT hticket_id, MAX(history_id) maxid, COUNT(history_id) AS sum_message
FROM history_ticket
GROUP BY hticket_id
) AS ht2 ON ht.history_id = ht2.maxid;
Updated SQL Fiddle Demo
This will give you:
| TICKET_ID | TICKET_DESC | DIVISI | STATUS | SUM_MESSAGE |
--------------------------------------------------------------
| 1 | software | Divisi A | process | 1 |
| 2 | hardware | Divisi B | solve | 1 |
| 3 | Problem | Divisi A | solve | 2 |
For multiple values, you can put them in a temp table, or you can select them in a subquery and join the table to get the name like this:
SELECT
t.ticket_id,
ticket_desc,
d.Divisi,
ht.status,
ht2.sum_message
FROM ticket AS t
INNER JOIN history_ticket ht ON t.ticket_id = ht.hticket_id
INNER JOIN
(
SELECT hticket_id, MAX(history_id) maxid, COUNT(history_id) AS sum_message
FROM history_ticket
GROUP BY hticket_id
) AS ht2 ON ht.history_id = ht2.maxid
INNER JOIN
(
SELECT 101 AS divisi_id, 'Divisi A' AS Divisi
UNION ALL
SELECT 102 , 'Divisi B'
... -- here you put other values or you can join a temp table instead
) AS D ON t.divisi_id = D.divisi_id;
Updated SQL Fiddle Demo
select distinct ticket.ticket_id, ticket.ticket_desc, history_ticket.status
from ticket
join history_ticket on ticket_id
This, as far as I remember, will choose a description and status at random if you have more than one. If you want to apply a specific rule to which one to pick, give more info and we can help you on that.
Try
SELECT DISTINCT
tk.ticket_id,
tk.ticket_desc,
ht.status
FROM ticket tk JOIN history_ticket ht ON tk.ticket_id = tk.ticket_id
ORDER BY tk.ticket_id
Try,
Select distinct t.ticket_id, t.ticket_desc, h.status
from ticket t, history_ticket h
where t.ticket_id = h.ticket_id
order by t.ticket_id