how does count work in sql query - qsqlquery

I'm doing a exercise about SQL query and I came up with an error when it comes to SUM. I know what is does, but I somehow get an error...
select
client.LName, client.FName,
COUNT(b.Total)
from
ClientBank client
INNER JOIN
Bank b ON (client.ClientID = b.ClientID)
where
client.LName = 'name' AND client.FName = 'a';
But then I get this error...
Column 'ClientBank.LName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I have tried to do a Group BY, don't really know how to use it well.. Any help would be great!

You have not given the structure of the ClientBank and Bank tables. I am taking that you inserted records something like this:
INSERT INTO `ClientBank`
(`ClientID`, `FName`, `Lname`)
VALUES
(1, 'Abraham', 'Backman'),
(2, 'Carl', 'Dacosta'),
(3, 'Erwin', 'Fabio'),
(4, 'Gabriel', 'Haddon');
INSERT INTO `Bank`
(`DepositID`, `ClientID`, `Deposit`)
VALUES
(1, 1, 100),
(2, 2, 200),
(3, 3, 300),
(4, 4, 400),
(5, 2, 500),
(6, 3, 600);
You can get the total of deposit for each client with this:
SELECT
client.LName, client.FName, SUM(b.Deposit) as Total
FROM
ClientBank client
INNER JOIN
Bank b ON (client.ClientID = b.ClientID)
GROUP By
client.LName, client.FName;
If you want only for a particular client (filtering using their name than Client Id):
SELECT
client.LName, client.FName, SUM(b.Deposit) as Total
FROM
ClientBank client
INNER JOIN
Bank b ON (client.ClientID = b.ClientID)
WHERE
client.LName = 'Fabio' AND client.FName = 'Erwin'
GROUP By
client.LName, client.FName;

Related

How to get the value of a different ID that is acquired during the SELECT statement?

I have created an entity tblPerson and from this entity I need to get the bGroup of t.adminID and the bGroup from the d.personID. I have tried the below query but it's not returning anything.
`
SELECT t.adminID, p.firstName, p.lastName, t.transID, t.transDate, t.donationID, p.bGroup, b.bankName, d.personID AS 'Donor ID', 'Donor BGroup'
FROM tblTrans t
JOIN tblAdmin a ON t.adminID = a.adminID
JOIN tblPerson p ON a.personID = p.personID
JOIN tblDonation d ON t.donationID = d.donationID
JOIN tblBank b ON d.bankID = b.bankID
WHERE 'Donor BGroup' IN
(SELECT p.bGroup
FROM tblPerson p
JOIN tblDonation d ON p.personID = d.personID
JOIN tblTrans t ON d.donationID = t.donationID);
`
When I execute the subquery, it gives me the bGroup of the d.personID, what do you think is going on, and maybe any alternatives, please?
Sample Data
INSERT INTO tblPerson (personID, firstName, lastName, bGroup)
VALUES ('1A', 'John', 'Doe', 'XY'),
('2A', 'Joe', 'Bishop', 'AB'),
('1B', 'Elly', 'James', 'OP'),
('2B', 'Andre', 'Butch', 'XY'),
('3A', 'Amy', 'Gree', 'AB'),
('3B', 'Alfred', 'Black', 'OP'),
('4C', 'James', 'Brown', 'XY');
INSERT INTO tblAdmin (adminID, personID, description)
VALUES (1, '1A', 'Whatever.'),
(2, '1B', ''),
(3, '4C', 'Anything.'),
(4, '1A', '');
INSERT INTO tblDonation (donationID, bankID, personID, donationDate)
VALUES (1, 1, '3B', '2018-12-27'),
(2, 1, '2A', '2022-12-28'),
(3, 2, '3A', '2022-03-23'),
(4, 2, '4C', '2022-06-19'),
(5, 3, '1B', '2022-08-19'),
(6, 3, '2B', '2022-08-08'),
(7, 3, '3B', '2022-07-20'),
(8, 2, '4C', '2022-11-26'),
(9, 1, '3B', '2022-11-26'),
(10, 2, '2A', '2022-01-16');
INSERT INTO tblBank (bankID, bankName)
VALUES (1, 'Bank 1'),
(2, 'Bank 2'),
(3, 'Bank 3');
INSERT INTO tblTrans (transID, transDate, donationID, adminID)
VALUES (1, '2022-12-31', 1, 1),
(2, '2022-01-01', 2, 1),
(3, '2022-05-23', 3, 2),
(4, '2022-05-23', 4, 2),
(5, '2022-07-09', 5, 3),
(6, '2022-08-20', 6 4),
(7, '2022-12-27', 7,4);
Sample ERD Diagram
Expected Output
Example: 1, John, Doe, 1, 2022-12-31, 1, XY, Bank 1, 3B, OP.
Your WHERE 'Donor BGroup' IN (SELECT...) clause evaluates to WHERE false, because you don't have any rows with that value in tblPerson.bGroup. So, your SELECT statement's result set is empty.
It's hard to puzzle out your requirement from your question.
I managed to find the solution. Since I needed to call the same table twice with different IDs I had to create two aliases and JOIN the table twice, like so:
SELECT t.adminID, person.firstName, person.lastName, t.transID, t.transDate, t.donationID, person.bGroup, b.bankName, donor.personID AS 'Donor ID', donor.bGroup AS 'Donor BGroup'
FROM tblTrans t
JOIN tblAdmin a ON t.adminID = a.adminID
JOIN tblPerson person ON a.personID = person.personID
JOIN tblDonation d ON t.donationID = d.donationID
JOIN tblPerson donor ON
JOIN tblBank b ON d.bankID = b.bankID;

In MySQL, return records with specific counts by year

I have an orders data set. I'd like to get email addresses where the count of orders are specific counts for each year. Let's say 2000 = 1, 2001 = 5 or less, 2002 = 3.
select email
from orders
where year in (2000,2001,2002)
That's where I'm stuck. My thought process is pushing me towards using a having clause or a case statement, but I'm at a wall with the condition of considering the counts by year.
In pseudo SQL it'd be:
select email
from orders
where count(year = 2000) = 1
and count(year = 2001) <= 5
and count(year = 2002) = 3
You can't do this in the where clause, you have to group by email and apply your condition in a having clause (or have your group by query as a subquery and use a where condition in an outer query).
select email
from orders
where year in (2000,2001,2003)
group by email
having sum(year = 2000) = 1
and sum(year = 2001) <= 5
and sum(year = 2002) = 3
You can do it as bellow.
Note that you can change the filtred values wthin the where condition for the count value and the associated year.
-- create a table
CREATE TABLE Orders (
id INTEGER PRIMARY KEY,
email VARCHAR(30) NOT NULL,
year int NOT NULL
);
-- insert some values
INSERT INTO Orders VALUES (1, 'test1#mail.com', 2000);
INSERT INTO Orders VALUES (2, 'test2#mail.com', 2001);
INSERT INTO Orders VALUES (3, 'test2#mail.com', 2001);
INSERT INTO Orders VALUES (4, 'test3#mail.com', 2002);
INSERT INTO Orders VALUES (5, 'test2#mail.com', 2001);
INSERT INTO Orders VALUES (6, 'test3#mail.com', 2002);
INSERT INTO Orders VALUES (7, 'test2#mail.com', 2001);
INSERT INTO Orders VALUES (9, 'test2#mail.com', 2001);
INSERT INTO Orders VALUES (10, 'test3#mail.com', 2002);
INSERT INTO Orders VALUES (11, 'test4#mail.com', 2002);
INSERT INTO Orders VALUES (12, 'test4#mail.com', 2001);
INSERT INTO Orders VALUES (13, 'test4#mail.com', 2002);
--sql statement
select result.email from (
select email, year, count(*) As count from Orders where year in (2000,2001,2002)
group by year, email
)result
where
(result.count = 1 and year = 2000)
;
Output:
email
test1#mail.com

Get reply numbers in mysql

I am working on a product review page where it will display several submitted reviews as well as the number of comments to each of them.
I thought I could use
SELECT title AS review_title,COUNT(id_group) AS Approved_reply_number
WHERE approved <> '0'
GROUP BY id_group`
but read somewhere that it isn't possible to copy the id values into another row on the insert process. So if someone submits a review, the id_group field for the reviews has to be left empty.
Here is the table example:
CREATE TABLE product_review
(`ID` int, `title` varchar(21), `id_group` int,`approved` int)
;
INSERT INTO product_review
(`ID`, `title`, `id_group`,`approved`)
VALUES
(1, 'AAA', Null,1),
(2, 'BBB', 1,1),
(3, 'CCC', Null,1),
(4, 'DDD', 3,0),
(5, 'EEE', 1,1),
(6, 'FFF', Null,1),
(7, 'GGG', 6,1),
(8, 'HHH',1,1),
(9, 'III', 6,1)
;
Those that are Null in id_group are the submitted reviews. The rest are replies and they contain the id of their corresponding reviews. I was wondering how can I get an output like this:
review_title approved_reply_number
AAA 3
CCC 0
FFF 2
You can use a self join and count query with group by and also a where clause to filter out reviews only
select t.title review_title ,count(*) approved_reply_number
from product_review t
left join product_review t1 on(t.id = t1.id_group)
where t.id_group is null
group by t.id
Demo

MySQL JOIN returning unrelated rows when combined with LEFT JOIN, WHERE and OR

I have the following table structure. The idea is that users have permissions to a forum either by their class or specific user overrides. ('action' in both cases is an enum with values 'read' & 'write')
user (id, class)
forum (id, name)
forum_permissions (forum_id, class_id, action)
forum_user_permissions (forum_id, user_id, action)
With the following query, I'm getting extra results based on rows in forum_permissions that I don't expect. By this I mean that every row on forum_permissions with forum_id = 3 is returned even though the class_id does not match.
SELECT forum.id AS forum_id, forum.name
FROM forum
JOIN forum_permissions ON forum_permissions.forum_id = forum.id
LEFT JOIN forum_user_permissions ON (
forum_user_permissions.forum_id = forum.id AND forum_user_permissions.user_id = 3 )
WHERE (( forum_permissions.class_id = 1 AND forum_permissions.action = 'read' )
OR
( forum_user_permissions.action = 'read' ))
e.g. I get this:
FORUM_ID NAME
1 chat
2 support
3 secret
3 secret
3 secret
3 secret
but expected this:
FORUM_ID NAME
1 chat
2 support
3 secret
I have made an SQL Fiddle with the specific example including data http://sqlfiddle.com/#!2/75c3a/5/0
Your left join is adding those extra lines. mybe if you change the WHERE
WHERE forum_user_permissions.user_id is not null and (
(forum_permissions.class_id = 1 AND forum_permissions.action = 'read')
OR
(forum_user_permissions.action = 'read')
)
Or
SELECT
forum.id AS forum_id, forum.name
FROM
forum
JOIN
forum_permissions
ON
forum_permissions.forum_id = forum.id
LEFT JOIN
forum_user_permissions
ON (
forum_user_permissions.forum_id = forum.id
)
WHERE forum_user_permissions.user_id = 3 and (
(forum_permissions.class_id = 1 AND forum_permissions.action = 'read')
OR
(forum_user_permissions.action = 'read')
)
But it depends on the results your are trying to get
Okay, I solved it myself by using LEFT JOIN's for both permission tables, rather than put the logic in a WHERE clause. I'm not very sure if this is a better approach than my first attempt and will gladly upvote if someone can explain.
SELECT forum.id AS forum_id, forum.name
FROM forum
LEFT JOIN forum_permissions
ON ( forum_permissions.forum_id = forum.id
AND forum_permissions.class_id = 1
AND forum_permissions.action = 'read' )
LEFT JOIN forum_user_permissions
ON ( forum_user_permissions.forum_id = forum.id
AND forum_user_permissions.user_id = 3
AND forum_user_permissions.action = 'read' )
WHERE forum_permissions.forum_id IS NOT null OR forum_user_permissions.forum_id IS NOT null
The full dataset is included below as I guess the fiddle will expire at some point.
INSERT INTO user
(`id`, `class`)
VALUES
(1, 1), (2, 1), (3, 1), (4, 2);
INSERT INTO forum
(`id`, `name`)
VALUES
(1, 'chat'), (2, 'support'), (3, 'secret');
INSERT INTO forum_permissions
(`forum_id`, `class_id`, `action`)
VALUES
(1, 1, 'read'), (1, 1, 'write'),
(1, 2, 'read'), (1, 2, 'write'),
(2, 1, 'read'), (2, 1, 'write'),
(2, 2, 'read'), (2, 2, 'write'),
(3, 2, 'read'), (3, 2, 'write'),
(3, 3, 'read'), (3, 3, 'write');
INSERT INTO forum_user_permissions
(`forum_id`, `user_id`, `action`)
VALUES
(3, 3, 'read'), (3, 3, 'write');

top contibuting users for particular category

I would like to find top contributors of particular state:
The candidates below have gathered particular votes for that state.
Find Top candidates for that states.
create table uservotes(id int, name varchar(50), vote int,state int);
INSERT INTO uservotes VALUES
(1, 'A', 34,1),
(2, 'B', 80,1),
(3, 'bA', 30,1),
(4, 'C', 8,1),
(5, 'D', 4,1),
(6, 'E', 14,2),
(7, 'F', 304,2),
(8, 'AA', 42,3),
(9, 'Ab', 6,3),
(10, 'Aa', 10,3);
States
create table states(state_id int, name_state varchar(50));
INSERT INTO states VALUES
(1, 'CA'),
(2, 'AL'),
(3, 'AZ'),
I am looking for:
for
CAL
2
1
3
4
5
based on the ranks of contribution.
How do I get that.
I really appreciate any help.
Thanks in Advance.
Code tried :
select uv.*, (#rank := #rank + 1) as rank
from uservotes uv,states s cross join
(select #rank := 0) const on uv.statesid = s.state_id
where name_state = 'CAL'
order by vote desc;
This is easy. You can use join and a group_concat():
select name_state, substring_index(group_concat(id order by votes desc), ',', 5)
from uservotes uv join
states s
on uv.state = s.state
group by name_state;
group_concat() will put all the id's in order with the highest votes first. substring_index() will extract the first five.
EDIT:
To get the top ranked users in one row, just add a where name_state = 'CA' to the above query.
To get them in different rows:
select uv.*
from uservotes uv join
states s
on uv.state = s.state
where state = 'CA'
order by votes desc
limit 5;