I have the following table with data:
t1 (results): card_id group_id project_id user_id
The tables that contain actual labels are:
t2 (groups): id project_id label
t3 (cards): id project_id label
There could be multiple entries by different users.
I need help with writing a query to display the results in a table format with totals counts corresponding card/group. Here's my start but I'm not sure that I'm on the right track...
SELECT COUNT(card_id) AS cTotal, COUNT(group_id) AS gTotal
WHERE project_id = $projID
Unless I'm mistaken, it seems that all you need to do is group by card_id and group_id for the given project_id and pull out the count for each group
SELECT card_id, group_id, COUNT(user_id) FROM mytable
WHERE project_id = 001
GROUP BY (card_id, group_id);
EDIT:
Taking into account the card and group tables involves some joins, but the query is fundamentally the same. Still grouping by card and group, and constraining by project id
SELECT c.label, g.label, COUNT(t1.user_id) FROM mytable t1
JOIN groups g ON t1.group_id=g.id
JOIN cards c ON t1.card_is=c.id
WHERE t1.project_id = 001
GROUP BY (c.card_id, g.group_id)
ORDER BY (c.card_id, g.group_id);
I don't think you can get a table as you want with just SQL. You'll have to render the table in code by iterating over the results. How you do that depends on what language/platform you are using.
if you know for a fixed fact that there are nine groups, then just include those groups in subqueries - similar to this:
select cTotal, g1.gTotal as Group1, g2.gTotal as Group2... etc
from
( SELECT COUNT(card_id) AS cTotal
, COUNT(group_id) AS gTotal
WHERE project_id = $projID
AND group_id = 1 ) g1
, ( SELECT COUNT(card_id) AS cTotal
, COUNT(group_id) AS gTotal
WHERE project_id = $projID
AND group_id = 2 ) g2
etc.
Related
As I'm SQL beginner, I can't describe a problem in a simple way, so let me show you an example:
3 Tables:
PRODUCT
id
group_id
person_id
GROUP
id
name
PERSON
id
group_id
As you see, GROUP can have multiple PERSONs and PRODUCT can be connected with GROUP and PERSON.
From this point, I would like to count number of PERSONs having a PRODUCT within a GROUP
I don't really understand the background of IN or using another SELECT within FROM, so if that's the point, then I'm happy that I was one step before it lol.
SELECT
group.name as GROUP_name,
COUNT(DISTINCT person_id) AS PERSON_having_min_one_PRODUCT
FROM products
LEFT JOIN groups ON groups.id = products.group_id
LEFT JOIN persons ON persons.id = products.person_id;
With this data:
GROUP
ExampleGroupName1 has 3 PERSONs, but 2 of them has >0 PRODUCTS
ExampleGroupName2 has 3 PERSONs and all of them has >0 PRODUCTS
ExampleGroupName3 has 2 PERSONs, but none of them has the PRODUCT
ExampleGroupName4 has 2 PERSONs, but only 1 has >0 PRODUCT
I would like to have an output like this:
GROUP_name | PERSON_having_min_one_PRODUCT
ExampleGroupName1 | 2
ExampleGroupName2 | 3
ExampleGroupName4 | 1
I would like to count number of PERSONs having a PRODUCT within a GROUP
Note: I will assume the table product does not have the column group_id, since it is redundant and can lead to a lot of errors.
The following query will show you the result you want by joining the tables person and product:
select
count(distinct x.id)
from person x
join product p on p.person_id = x.id
where x.group_id = 123 -- choosing a specific group
and p.id = 456 -- choosing a specific product
This would rather be simple like below meaning all the groups with some group_id with count(persons) and those count who has some product via id used in having clause
Select group_id,
count( distinct id ) AS "PERSON_WITH_PRODUCT"
from
person group by group_id having id
in (Select id from product);
I am working on an auction script with a table that looks like the attached image.
Within an auction two users can place the same bid amount, for example two players could place a bid of '1' which would give that bid amount a total count of two.
I need a query which gets all of a users single bid amount along with the total count of that bid amount within the scope of the auction id.
As it stands I first get the users bids:
SELECT bid_amount FROM all_bids WHERE auction_id = '129' AND user_id = '9'
And then I am looping through each amount in PHP and doing the following
SELECT COUNT(*) FROM all_bids WHERE auction_id = '129' AND bid_amount = 'xxx'
But this is of course very power hungry and I am sure it can be done all in one query.
I have got as far as
SELECT bid_amount,COUNT(*) FROM (SELECT bid_amount FROM all_bids WHERE auction_id = '129' AND user_id ='9') as foo GROUP BY bid_amount
Which returned the correct bid amounts but the counts were all 1 which is wrong as I guess my incorrect query is only counting the values within the subquery and not outside of the bids that just that user placed
SELECT a.*, b.cnt from all_bids a
join (select bid_amount,COUNT(*) cnt from all_bids group by bid_amount) b
on a.bid_amount=b.bid_amount
WHERE a.auction_id = '123' AND a.player_id = '456'
I think you want group by:
select bid_amount, count(*)
from all_bids
where auction_id = 123 and player_id = 456
group by bid_amount;
Note that you do not need single quotes for a numeric constant.
Hmmm. You might want this phrased as:
select ab.bid_amount, count(*)
from all_bids ab
where ab.auction_id = 123 and
ab.bid_amount in (select ab2.bid_amount
from all_bids ab2
where ab2.auction_id = ab.auction_id and ab2.player_id = 456
)
group by ab.bid_amount;
I have a relation between users and groups. Users can be in a group or not.
EDIT : Added some stuff to the model to make it more convenient.
Let's say I have a rule to add users in a group considering it has a specific town, and a custom metadata like age 18).
Curently, I do that to know which users I have to add in the group of the people living in Paris who are 18:
SELECT user.id AS 'id'
FROM user
LEFT JOIN
(
SELECT user_id
FROM user_has_role_group
WHERE role_group_id = 1 -- Group for Paris
)
AS T1
ON user.id = T1.user_id
WHERE
(
user.town = 'Paris' AND JSON_EXTRACT('custom_metadata', '$.age') = 18
)
AND T1.user_id IS NULL
It works & gives me the IDs of the users to insert in group.
But when I have 50 groups to proceed, like for 50 town or various ages, it forces me to do 50 requests, it's very slow and not efficient for my Database.
How could I generate a result for each group ?
Something like :
role_group_id user_to_add
1 1
1 2
2 1
2 3
The only way I know to do that for now is to do an UNION on several sub queries like the one above, but of course it's very slow.
Note that the custom_metadata field is a user defined field. I can't create specific columns or tables.
Thanks a lot for your help.
if I good understood you:
select user.id, grp.id
from user, role_group grp
where (user.id, grp.id) not in (select user_id, role_group_id from user_has_role_group) and user.town in ('Paris', 'Warsav')
that code give list of users and group which they not belong from one of towns..
To add the missing entries to user_has_role_group, you might want to have some mapping between those town names and their group_id's.
The example below is just using a subquery with unions for that.
But you could replace that with a select from a table.
Maybe even from role_group, if those names correlate with the user town names.
insert into user_has_role_group (user_id, group_id)
select u.user_id, g.group_id
from user u
join (
select 'Paris' as name, 1 as group_id union all
select 'Rome', 2
-- add more towns here
) g on (u.town = g.name)
left join user_has_role_group ug
on (ug.user_id = u.user_id and ug.role_group_id = g.group_id)
where u.town in ('Paris','Rome') -- add more towns here
and json_extract(u.custom_metadata, '$.age') = 18
and ug.id is null;
I have this problem with SQL and I can't figure it out.
Imagine that I have 3 tables as follows
Names
Nameid name
1 Starbucks Coffee
2 Johns Restaurant
3 Davids Restaurant
user_likes
userid Nameid
1 1
2 1
2 3
user_visited
userid Nameid
1 2
I want to find the places with the most number of (likes+visited). I also want to select all places not just those who have been liked or visited
I do:
SELECT n.nameid, n.name , COUNT(f.nameid) AS freq
FROM names AS n
LEFT JOIN user_likes ON n.nameid=user_likes.nameid
LEFT JOIN user_visited ON n.nameid=user_visited.nameid
ORDER BY freq DESC
But it doesn't give me the total frequency. The problem is, if a place is both visited and liked, it is counted only once, while I want it to be counted twice.
Any suggestions?
I've made a quick test and although I prefer Serge's solution, this one seemed to perform faster as the amount of items to join will be less:
SELECT n.nameId, n.name, coalesce(sum(likesCount), 0) totalCount FROM NAMES n
LEFT JOIN (
SELECT nameId, count(*) likesCount FROM user_likes
GROUP BY nameId
UNION ALL
SELECT nameId, count(*) visitsCount FROM user_visited
GROUP BY nameId
) s ON n.nameId = s.nameId
GROUP BY n.nameId
ORDER BY totalCount DESC
I'm assuming the following indexes:
alter table names add index(nameid);
alter table user_likes add index(nameid);
alter table user_visited add index(nameid);
Probably the OP can compare the efficiency of both queries with actual data and provide feedback.
SELECT n.name, t.nameid, COUNT(t.nameid) AS freq
FROM Names n
JOIN (
SELECT nameid FROM user_likes
UNION ALL
SELECT nameid FROM user_visited
) t
ON n.nameid = t.nameid
GROUP BY t.nameid ORDER BY freq DESC
Mosty, your usage of coalesce() gave me an idea and I came up with this:
SELECT n.nameid, n.name ,
SUM((IFNULL(user_likes.userid,0)>0)+(IFNULL(user_visited.userid,0)>0) ) AS freq
FROM names AS n LEFT JOIN user_likes ON n.nameid=user_likes.nameid LEFT JOIN
user_visited ON n.nameid=user_visited.nameid ORDER BY freq DESC
Since my example here was a simplification of my problem (I have to join more than two tables to the main table) I'm reluctant to use SELECT inside SELECT, because I know it's not very efficient. Do you see any fundamental problem with my solution?
I have a table similar to the following:
ID PAYEE CATEGORY
001 Costco Grocery
002 See's Candy
003 Costco Repair
005 Costco Grocery
006 Costco
007 Costco
008 See's
Using MySQL withOUT the aid of a programming language, is there a query (nested or not) that would set the category of the three new rows to the most often used category for those payees?
For example, one of the Costco records (ID 003) has Repair as its category, whereas the other two Costco rows (ID 001 and ID 005) have Grocery as their category. Thus the desired result would be that the new Costco rows (ID 006 and ID 007) would be set to Grocery since that's the most often used category for that payee.
sure.. just change 'your_table' to the name of your table
UPDATE your_table
LEFT JOIN (SELECT payee, category
FROM
(SELECT payee, category FROM your_table WHERE category != '' AND category IS NOT NULL GROUP BY payee, category ORDER BY count(*) DESC) AS tbl2
GROUP BY payee
) AS tbl2 USING (payee)
SET your_table.category = tbl2.category;
this will change the costco that is categorized as repair to 'grocery' as well.. if you dont want this, add:
WHERE your_table.category IS NULL OR your_table.category = ''
to the very end of the query
This would work
UPDATE test t,
(SELECT category,
payee,
count(*)
FROM test ORDER BY count(*) desc LIMIT 1) t1
SET t.category = t1.category
WHERE t.payee = t1.payee
AND (t.category = ''
OR t.category IS NULL)
Sqlfiddle at http://www.sqlfiddle.com/#!2/ed5b0/1/0
I just couldn't figure out a way without repeating the creation of a derived table:
UPDATE t JOIN (
SELECT s1.payee, s1.category FROM (
SELECT payee, category, count(*) cat_count FROM t
WHERE category IS NOT NULL
GROUP BY payee, category
) s1
LEFT JOIN (
SELECT payee, category, count(*) cat_count FROM t
WHERE category IS NOT NULL
GROUP BY payee, category
) s2
ON s1.payee = s2.payee AND s1.cat_count < s2.cat_count
WHERE s2.cat_count IS NULL
) s
ON t.payee = s.payee
SET t.category = s.category
WHERE t.category IS NULL;
Fiddle here
Use mysql's multi-table update:
UPDATE mytable t
JOIN (SELECT payee, category
FROM (SELECT payee, category
FROM mytable
GROUP BY 1, 2
ORDER BY count(*) desc) x
GROUP BY 1) y
ON y.payee = t.payee
SET t.category = y.category
WHERE ifnull(t.category, '') = ''
There's a little bit of kung fu tucked away in there that makes it work: the outer group by returns the first row encountered for the group, which due to the ordering for the inner-most query will be the category with the highest count.