find sum of value with the same ID with condition in sql - mysql

This is the salary table
COMPANY_ID | Salary |
=========================
1 | 20000 |
2 | 10000 |
3 | 50000 |
4 | 13000 |
2 | 8000 |
3 | 20000 |
5 | 20000 |
1 | 10000 |
4 | 40000 |
This is the company table
ID | Comapny |
=========================
1 | Apple |
2 | Facebook |
3 | Google |
4 | Microsoft |
5 | Oracle |
my expected output is to find companies that has a average salary > 20000.
Google
Microsoft

select company_name ,avg(tblSalary.salary) average_salary
from tblCompany
Inner join tblSalary on tblcompany.id = tblsalary.company_id
group by company_name
having avg(tblSalary.salary) > 20000

select company from company a, salary b where a.id = b.id and b.salary >= 20000 group by a.company
or
select company from company a inner join salary b on a.id = b.id and b.salary >= 20000 group by a.company
Like others said read your book, this is as basic as it gets.

Related

query to get customer list using JOIN with sum () of the amounts spent in orders

I have the following tables
table anag (customer registry)
id | surname | name | phone |
----------------------------------------------
1 | Brown | Jack | +3989265781 |
2 | Smith | Bill | +3954872358 |
3 | Rogers | Stan | +3912568453 |
4 | Pickford | Eric | +3948521358 |
----------------------------------------------
table levels (table that connects each customer to his salesperson. For database registration reasons, the link between customer and seller is given by the customer's telephone number)
id | client_phone | id_seller |
--------------------------------------
1 | +3989265781 | 4 |
2 | +3954872358 | 7 |
3 | +3912568453 | 7 |
4 | +3948521358 | 8 |
--------------------------------------
table orders (contains all purchases made by customers, of course)
id | id_client | id_item | id_seller | price | status |
--------------------------------------------------------------------
1 | 1 | 2 | 4 | 12.50 | 2 |
2 | 2 | 2 | 7 | 12.50 | 2 |
3 | 2 | 3 | 7 | 10.00 | 3 |
4 | 2 | 3 | 7 | 10.00 | 3 |
5 | 2 | 4 | 7 | 20.50 | 1 |
6 | 3 | 2 | 7 | 12.50 | 1 |
7 | 3 | 5 | 7 | 19.00 | 3 |
8 | 3 | 7 | 7 | 31.00 | 2 |
9 | 4 | 1 | 8 | 5.00 | 1 |
--------------------------------------------------------------------
What I'm trying to do is get from the JOIN of these tables a complete list by seller of his customers sorted in descending order by the amount spent on orders as long as the order status is 2 or 3
Something like this (example seller id 7):
id | surname | name | amaount |
----------------------------------------
3 | Rogers | Stan | 50.00 |
2 | Smith | Bill | 32.50 |
----------------------------------------
I have tried with this query which seems correct to me, but unfortunately it returns me error in fetch_assoc()
SELECT a.id, a.surname, a.name, o.amount FROM levels AS l
JOIN anag AS a ON a.phone = l.client_phone
JOIN {
SELECT id_client, SUM(price) AS amount FROM orders
WHERE id_seller = '7' AND (status = '2' OR status = '3') GROUP BY id_client
} AS o ON o.id_client = a.id
WHERE l.id_seller = '7'
ORDER BY o.amount DESC
If I separate the subquery from the main query, both return the data I expect and it seems strange to me the JOIN between the two does not work properly
I think the only real error is using curly braces instead of parentheses:
SELECT a.id, a.surname, a.name, o.amount
FROM levels l JOIN
anag a
ON a.phone = l.client_phone JOIN
(SELECT id_client, SUM(price) AS amount
FROM orders
WHERE id_seller = '7' AND status IN ('2', '3'))
GROUP BY id_client
) o
ON o.id_client = a.id
WHERE l.id_seller = '7'
ORDER BY o.amount DESC;
In addition:
You can use IN to shorten an equality comparison to multiple values.
Although I left them in, status and id_seller look like numbers. If so, drop the single quotes. Don't mix data types.
Your question is ambiguous on what to do if the seller in orders differs from the seller in anag for a customer. This keeps your logic (the sellers need to match).
SELECT a.id, a.surname, a.name, sum(o.price) 'amount'
FROM anag a
LEFT JOIN levels l ON l.id =a.id
LEFT JOIN orders of ON o.id_seller = l.id_seller AND o.id_client = l.id
GROUP BY o.id_seller
ORDER BY amount DESC

SQL Query: join with condition

I have the following tables:
Customer
| c_id | name |
| -------- | -------------- |
| 1 | Adam |
| 2 | Bradley |
| 3 | Chandler |
| 4 | Damian |
| 5 | Eric |
| 6 | Frank |
orders
| order_id | c_id | amount
| -------- | -------------- | -------------- |
| 1 | 1 | 50
| 2 | 1 | 2
| 3 | 2 | 15
| 4 | 2 | 22
| 5 | 2 | 10
| 6 | 2 | 7
| 7 | 3 | 7
| 8 | 3 | 2
| 9 | 5 | 18
| 10 | 5 | 24
| 11 | 6 | 60
| 12 | 6 | 1
I want to create a list of users who have order amounts over 50.
This list should include c_id, name and the sum of all their orders including those under 50.
so it should look like this:
| c_id | name | amount
| -------- | -------------- | -------------- |
| 1 |Adam | 52
| 6 | Frank | 61
You can use group by and having:
select c.c_id, c.name, sum(o.amount)
from orders o join
customers c
on o.c_id = c.c_id
group by c.c_id, c.name
having max(o.amount) > 50;
SELECT
c_id
, name
, SUM(amount) AS total_amount
FROM
orders a
INNER JOIN customer b
ON b.c_id = a.user_id
WHERE
c_id IN (
SELECT
user_id
FROM
orders
WHERE
amount >= 50)
GROUP BY c_id, name
Best to break this down into chunks:
Customers who have a total amount over 50:
SELECT user_id FROM orders GROUP BY user_id HAVING sum(amount) >= 50;
Sum of the amounts for each order for customers that meet the criteria above:
SELECT user_id, sum(amount) as order_total
FROM orders
WHERE user_id IN (SELECT user_id FROM orders HAVING sum(amount) >= 50 GROUP BY user_id)
GROUP BY user_id;
You can just join over to your customer table to grab the name. Didn't include since that is the more straightforward ask here.

MySQL return distinct accounts from one table, average rating from another, all based on service area in another table

as the title states, I'm trying to return a query which gets account details from the accounts table, gets the average rating for the account from the reviews table, and limits the rows to the service location associated to the account.
Here are the simplified tables:
accounts
+----+------------+-----------+
| id | first_name | last_name |
+----+------------+-----------+
| 1 | John | Smith |
| 2 | Bob | Doe |
| 3 | Alice | McLovin |
| 4 | Bruce | Wayne |
+----+------------+-----------+
reviews
+----+-------------+-----+--------+
| id | acccount_id | ... | rating |
+----+-------------+-----+--------+
| 1 | 1 | ... | 9 |
| 2 | 1 | ... | 10 |
| 3 | 2 | ... | 7 |
| 4 | 1 | ... | 2 |
| 5 | 4 | ... | 6 |
+----+-------------+-----+--------+
service_area
+----+-------------+---------+
| id | acccount_id | city_id |
+----+-------------+---------+
| 1 | 1 | 1140 |
| 2 | 1 | 1001 |
| 3 | 2 | 1140 |
| 4 | 1 | 1086 |
| 5 | 4 | 1001 |
+----+-------------+---------+
For example, the user may request to view all accounts which have a service area of city_id 1140. The query should then return the first_name, last_name, and average rating for each account within the specified service area. Note that accounts can have multiple service areas (see service_area table).
Thanks in advance!
UPDATE:
The following QUERY did the trick! I needed a LEFT JOIN for the reviews table!
SELECT a.first_name, a.last_name, AVG(r.rating) avg_rating
FROM accounts a
JOIN service_area sa
ON a.id = sa.account_id AND sa.city_id = 1140
LEFT JOIN reviews r
ON a.id = r.account_id
GROUP BY a.id
You can use joins and simple aggregation with group by
SELECT a.*,
AVG(r.rating) avg_rating
FROM accounts a
JOIN reviews r ON a.id = r.acccount_id
JOIN service_area s ON a.id = s.acccount_id
WHERE s.city_id = 1140
GROUP BY a.id
Result set will be like
id first_name last_name avg_rating
------ ---------- --------- ------------
1 John Smith 7.0000
2 Bob Doe 7.0000
Use LEFT join for when there are no reviews available
SELECT a.*,
COALESCE(AVG(r.rating),0) avg_rating
FROM accounts a
LEFT JOIN reviews r ON a.id = r.acccount_id
JOIN service_area s ON a.id = s.acccount_id
WHERE s.city_id = 1140
GROUP BY a.id
DEMO

show alternating rows in mysql

Let's say I have these tables:
tblPerson
id | name |
1 | A |
2 | B |
3 | C |
tblB
id | personId | loan |
1 | 1 | 100 |
2 | 1 | 50 |
3 | 2 | 25 |
tblC
id | personId | payment |
1 | 1 | 20 |
2 | 1 | 10 |
How do I produce this output:
Output
id | name | loan | payment | balance |
1 | A | 100 | 0 | 100 |
1 | A | 0 | 20 | 80 |
1 | A | 50 | 0 | 130 |
1 | A | 0 | 10 | 120 |
2 | B | 25 | 0 | 25 |
I need the output to sbow the loan first then the payment the loan again and so on.
This sort of query (http://sqlfiddle.com/#!2/759df4/3/0) will generate an interleaved set of loans and payments.
SELECT id,name,loan,payment
FROM (
SELECT p.id id,
p.name name,
0 type,
b.id detail_id,
b.loan loan,
0 payment
FROM person p
JOIN b ON p.id = b.personId
UNION ALL
SELECT p.id id,
p.name name,
1 type,
c.id detail_id,
0 loan,
c.payment payment
FROM person p
JOIN c ON p.id = c.personId
) q
ORDER BY id, detail_id, type
Then, I suppose you can use variables to generate the running totals. But Dr. Linoff is right (see his comment) that the dataset you've shown doesn't have enough information reliably to interleave loan and payment records. I've used ID fields to do this. The last ORDER BY really ought to mention posting_date or some other information instead of detail_id, if you have it elsewhere in your tables
try this:
select *, (sum(tb.loan) / sum(tc.payment)) as balance
from tblPerson tp
join tblB tb on tp.id = tb.personId
join tblC tc on tp.id = tc.personId
this is what comes to my head.

SELECT the SUM of multiple values to which user is subscibed

Table: assignments
=======================
|customerid |tariffid |
=======================
| 1 | 2 |
| 2 | 2 |
| 1 | 4 |
| 3 | 4 |
=======================
Table: cash
=======================
|customerid | value |
=======================
| 1 | 2 |
| 1 | 9 |
| 1 | -15 |
| 2 | -9 |
| 2 | 2 |
| 2 | 2 |
| 2 | -9 |
| 3 | 9 |
=======================
Table: customers
=================================================
| id | lastname| name | cutoffstop | deleted |
=================================================
| 1 | Doe | John | 10 | 0 |
| 2 | Foo | Jack | 10 | 0 |
| 3 | Zoo | Jenny| 20 | 0 |
| 4 | Boo | Jane | 5 | 0 |
=================================================
Table: tariffs
================
| id | value|
================
| 1 | 0 |
| 2 | 2 |
| 3 | 0 |
| 4 | 9 |
================
I have four tables. Also I have two queries that work, but I need to merge the queries somehow.
The first query gives me a row of customerid(id) - lastname - name - balance[=sum(cash.value)]
SELECT customers.id AS id, UPPER(lastname) AS lastname, name, SUM(cash.value) AS balance
FROM customers
JOIN cash ON customers.id = cash.customerid
WHERE deleted = 0 AND cutoffstop < 50
GROUP BY customers.id, lastname, name
HAVING SUM(cash.value) < $limit
ORDER BY lastname, name
Example resulting row first query:
id lastname name balance
1 DOE John -4 (=2+9+-15)
The second query gives me a row of customerid(id) - maxdept [=sum(tariffs.value)]
SELECT SUM(tariffs.value) AS maxdebt, customers.id AS id
FROM tariffs
INNER JOIN assignments ON tariffs.id = assignments.tariffid
INNER JOIN customers ON assignments.customerid = customers.id
GROUP BY id
Example resulting row second query:
id maxdept
1 11 (=9+2)
Note: maxdept = $limit
Now, what I actually want is a a combined query where $limit in the first query IS the outcome of the second
query -> the sum of tariffs.value (=maxdept) per customerid. (Now the $limit is statically defined in a config-file.)
Thanks in advance!
SELECT a.id, a.lastname, a.name, a.balance, b.maxdebt
FROM (SELECT customers.id AS id, UPPER(lastname) AS lastname, name, SUM(cash.value) AS balance
FROM customers
JOIN cash ON customers.id = cash.customerid
WHERE deleted = 0 AND cutoffstop < 50
GROUP BY customers.id, lastname, name) a
INNER JOIN (SELECT SUM(tariffs.value) AS maxdebt, customers.id AS id
FROM tariffs
INNER JOIN assignments ON tariffs.id = assignments.tariffid
INNER JOIN customers ON assignments.customerid = customers.id
GROUP BY id ) b ON a.id = b.id and a.balance < b.maxdebt