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.
Related
I have a problem when I have to select everything from one table (persons) then count how many objects they own by counting their occurrences on other tables (pens, chairs, books)
The current data is as followed:
select * from persons;
+----+-------+
| id | name |
+----+-------+
| 1 | Alex |
| 2 | Brad |
| 3 | Cathy |
+----+-------+
select * from pens;
+----+-----------+
| id | person_id |
+----+-----------+
| 1 | 2 |
| 2 | 2 |
| 3 | 2 |
| 4 | 3 |
+----+-----------+
select * from chairs;
+----+-----------+
| id | person_id |
+----+-----------+
| 1 | 1 |
+----+-----------+
select * from books;
+----+-----------+
| id | person_id |
+----+-----------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+-----------+
I want the result to be something like this
+----+-------+-----------------------+-------------------------+------------------------+
| id | name | count(pens.person_id) | count(chairs.person_id) | count(books.person_id) |
+----+-------+-----------------------+-------------------------+------------------------+
| 1 | Alex | 0 | 1 | 1 |
| 2 | Brad | 3 | 0 | 1 |
| 3 | Cathy | 1 | 0 | 1 |
+----+-------+-----------------------+-------------------------+------------------------+
I have tried using inner join and left outer join, but join gave me an empty set (since no person matches all of the objects) and left outer join gave me incorrect results:
> select persons.*, count(pens.person_id),count(chairs.person_id),count(books.person_id) from persons join pens on pens.person_id=persons.id join books on books.person_id=persons.id join chairs on chairs.person_id=persons.id group by persons.id;
Empty set (0.002 sec)
> select persons.*, count(pens.person_id),count(chairs.person_id),count(books.person_id) from persons left outer join pens on pens.person_id=persons.id left outer join books on books.person_id=persons.id left outer join chairs on chairs.person_id=persons.id group by persons.id;
# +----+-------+-----------------------+-------------------------+------------------------+
id | name | count(pens.person_id) | count(chairs.person_id) | count(books.person_id) |
# +----+-------+-----------------------+-------------------------+------------------------+
1 | Alex | 0 | 1 | 1 |
2 | Brad | 3 | 0 | 3 |
3 | Cathy | 1 | 0 | 1 |
# +----+-------+-----------------------+-------------------------+------------------------+
Any suggestions will be greatly appreciated, sorry if it's obvious, I'm fairly new at this.
Using a left join approach to subqueries on each table we can try:
SELECT
p.id,
p.name,
COALESCE(ps.cnt, 0) AS cnt_pens,
COALESCE(c.cnt, 0) AS cnt_chairs,
COALESCE(b.cnt, 0) AS cnt_books
FROM persons p
LEFT JOIN
(
SELECT person_id, COUNT(*) AS cnt
FROM pens
GROUP BY person_id
) ps
ON ps.person_id = p.id
LEFT JOIN
(
SELECT person_id, COUNT(*) AS cnt
FROM chairs
GROUP BY person_id
) c
ON c.person_id = p.id
LEFT JOIN
(
SELECT person_id, COUNT(*) AS cnt
FROM books
GROUP BY person_id
) b
ON b.person_id = p.id
ORDER BY
p.id;
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
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.
I have 2 tables:
table a
+----------+------------+------------+
|session_id| product_id | orders |
+----------+------------+------------+
| 1 | 11 | 0 |
| 1 | 22 | 2 |
| 1 | 34 | 1 |
| 2 | 11 | 0 |
| 3 | 43 | 0 |
| 3 | 11 | 1 |
+----------+------------+------------+
table b:
+-----------+--------------+
|product_id |category_id |
+-----------+--------------+
| 11 | 100 |
| 12 | 101 |
| 34 | 102 |
| 22 | 103 |
| 43 | 104 |
| 13 | 105 |
+-----------+--------------+
What I want is a table which consists of how many category_id were there in each session_id and also total orders placed in that session_id
+-----------+--------------------+--------+
|session_id | count(category_id) | orders |
+-----------+--------------------+--------+
| 1 | 3 | 3 |
| 2 | 1 | 0 |
| 3 | 2 | 1 |
+-----------+--------------------+--------+
I tried:
select a.session_id,count(b.category_id),sum(a.orders) from a
join table b
on a.product_id = b.product id
is this query right?
Please help me. I am a beginner
I tried with 2 methods
1)...SELECT a.session_id,COUNT(b.category_id),SUM(a.orders) FROM #a a
LEFT JOIN #b b
ON a.product_id = b.product_id GROUP BY a.session_id
GROUP BY a.Session_ID
2...) SELECT D.SESSION_ID,COUNT(CATEGORY_ID),SUM(D.ORDERS) FROM #A D
OUTER APPLY
(
SELECT CATEGORY_ID,PRODUCT_ID FROM #B B
WHERE D.PRODUCT_ID = B.PRODUCT_ID
) A
GROUP BY D.SESSION_ID
GO
Just use left join for showing all result from table A
by using only join its show the result exist in both table only.
SELECT a.session_id,COUNT(b.category_id),SUM(a.orders) FROM a
LEFT JOIN b
ON a.product_id = b.product_id GROUP BY a.`session_id`
Ofcourse you have t join tha tables, then group with the field you want.
SELECT a.Session_ID, Count(Category_ID) CategoryCount, SUM(Orders) NumberOfOrders
FROM a
LEFT OUTER JOIN b
ON a.Product_ID = b. Product ID
GROUP BY a.Session_ID
Personally, and since I don't have any info on the data structure I prefered using the LEft outer join since in case the product_id had no category, then no results of this product will show.
(unless each product should have a category, or the user needs only the products that has a category, you have to use the INNER JOIN)
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