how to merge tables and sum - mysql

I have two tables with some specific data:
users:
+----+------------+
| id | username |
+----+------------+
| 1 | rob |
| 2 | john |
| 3 | jane | <--- jane never has donated
+----+------------+
donations:
+--------------------+------------+
| uid | amount | date |
+---------+----------+------------+
| 1 | 20 | 2013-10-10 |
| 2 | 5 | 2013-10-03 |
| 2 | 50 | 2013-09-25 |
| 2 | 5 | 2013-10-01 |
+---------+----------+------------+
Result I want:
+---------+-------------+---------+-------------+
| id | username | amount | monthly | <- sum of donations this month
+---------+-------------+---------+-------------+
| 1 | rob | 20 | 1 |
| 2 | john | 60 | 3 |
| 3 | jane | 0 | 0 | <- jane added
+---------+-------------+-----------------------+
This is my query:
SELECT t1.*, sum(t2.amount) amount, count(*) as monthly
FROM users t1
inner join donations t2
on t2.uid = t1.id
group by t1.username
EDIT: forgot to add jane, he never has donated.
How I can do this?

Your output is wrong as you didn't filter out the september record in your results (only October 2013 should be taken into account).
Your expected output should be this:
| ID | USERNAME | AMOUNT | MONTHLY |
|----|----------|--------|---------|
| 1 | rob | 20 | 1 |
| 2 | john | 10 | 2 |
| 3 | jane | 0 | 0 |
The query to get the output is:
SELECT
u.id,
u.username,
COALESCE(sum(d.amount), 0) amount,
COUNT(d.uid) monthly
FROM users u
LEFT JOIN donations d
ON u.id = d.uid
AND (month(d.date), year(d.date)) = (month(CURDATE()), year(CURDATE()))
GROUP BY u.id
Assuming users.ID holds unique values you can leave the group by as u.id if it is not then you will have to group by u.id, u.username.
Fiddle here.

SELECT t1.*, sum(t2.amount) as amount, count(t2.amount,t2.`date`) as monthly
FROM users t1
inner join donations t2
on t2.uid = t1.id
where month(t2.`date`)=month(curdate()) and year(t2.`date`)=year(curdate())
group by t1.username

How about this use current date and extract the month and match with the month from column date
CURDATE() , MONTH()
SELECT t1.*, (CASE WHEN SUM(t2.amount) IS NULL THEN 0 ELSE SUM(t2.amount) END) amount,
count(*) as monthly
FROM users t1
left join donations t2
on t2.uid = t1.id
WHERE MONTH(t2.`date`)=MONTH(CURDATE()) AND YEAR(t2.`date`)=YEAR(CURDATE())
group by t1.id

Related

How to select working time by calling time, group id?

I need to select working time - SUM(users_worktime.length) as working_time) when users was calling by the calling time and users group id. How to do that?
Here is my select:
SELECT
users_groups.name as name,
COUNT(DISTINCT calls.id) as calls,
SUM(calls.status = 'ended') as answers,
COUNT(DISTINCT orders.id) as deals,
ROUND(COUNT(DISTINCT orders.id) * 100 / SUM(calls.status = 'ended'),2) as rate,
SUM(case when calls.status = 'ended' then calls.call_length else 0 end) as talking_time,
//SUM(users_worktime.length) as working_time
FROM
users_groups
LEFT JOIN users ON users.group_id = users_groups.id
LEFT JOIN calls ON (calls.user_id = users.id AND calls.created_at >= '2015-12-30 00:00:00' AND calls.created_at <= '2015-12-31 23:59:59')
LEFT JOIN orders ON orders.id = calls.order_id AND orders.status = 'finished'
WHERE 1
AND users.group_id = 1
GROUP BY
users_groups.id
I need result like this:
| name | calls | answers | deals | rate | talking_time| working_time |
------------------------------------------------------------------------
| Group | 4 | 3 | 2 | 75 % | 180 | 355.00 |
And here are my data tables:
users_worktime:
| id | user_id | length | start |
-----------------------------------------------
| 1 | 2 | 130 | 2015-12-30 07:53:38 |
| 2 | 8 | 55 | 2015-12-30 12:53:38 |
| 3 | 8 | 170 | 2015-12-31 22:53:38 |
users:
| id | username | group_id |
----------------------------
| 2 | Thomas | 1 |
| 8 | Haroldas | 1 |
groups:
| id | name |
-------------
| 1 | Group |
calls:
| id | user_id | order_id | status | call_length | created_at |
-------------------------------------------------------------------------
| 1 | 2 | 3 | ended | 35 | 2015-12-30 07:53:38 |
| 2 | 8 | 4 | ended | 100 | 2015-12-31 12:53:38 |
| 3 | 8 | NULL | started | 15 | 2015-12-31 14:53:38 |
| 4 | 8 | NULL | ended | 45 | 2015-12-31 20:53:38 |
orders:
| id | user_id | call_id | start |
-----------------------------------------------
| 3 | 2 |1 | 2015-12-30 07:53:38 |
| 4 | 8 |2 | 2015-12-31 12:53:38 |
Thank you
EDIT:
I trying with subquery like this but is not correct because SUM is only one user of group
SELECT
users_groups.name as name,
COUNT(DISTINCT calls.id) as calls,
SUM(calls.status = 'ended') as answers,
COUNT(DISTINCT orders.id) as deals,
ROUND(COUNT(DISTINCT orders.id) * 100 / SUM(calls.status = 'ended'),2) as rate,
SUM(case when calls.status = 'ended' then calls.call_length else 0 end) as talking_time,
(SELECT SUM(users_worktime.length) FROM users_worktime WHERE users_worktime.user_id = users.id AND users_worktime.start >= '2015-12-30 00:00:00' AND users_worktime.start <= '2015-12-31 23:59:59') as working_time
FROM
users_groups
LEFT JOIN users ON users.group_id = users_groups.id
LEFT JOIN calls ON (calls.user_id = users.id AND calls.created_at >= '2015-12-30 00:00:00' AND calls.created_at <= '2015-12-31 23:59:59')
LEFT JOIN orders ON orders.id = calls.order_id AND orders.status = 'finished'
WHERE 1
AND users.group_id = 1
GROUP BY
users_groups.id

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.

MySQL: Get the totals from two columns organised by category

Considering the following tables in a MYSQL database:
table1:
+------+-----------+----------------------+
| id | atual | category_id | user |
+------+-----------+--------------|-------+
| 1 | 100 | 1 | 1 |
| 2 | 150 | 2 | 1 |
| 3 | 50 | 1 | 2 |
+------+-----------+--------------|-------+
table2:
+------+-----------+----------------------+
| id | budget | category_id | user |
+------+-----------+--------------|-------+
| 1 | 100 | 2 | 1 |
| 2 | 150 | 1 | 2 |
| 3 | 50 | 1 | 1 |
+------+-----------+--------------|-------+
table3:
+------+-----------+
| id | name |
+------+-----------+
| 1 | one |
| 2 | two |
| 3 | three |
+------+-----------+
I want to calculate the totals for 'atual' and 'budget' given in tables 1 and 2 for a given user (1 in my example), organized by category name:
I tried the following query, which is giving me the totals for atual and budget regardless of the categories:
SELECT table2.id, table3.name AS name_category, SUM( budget ) ,
(SELECT SUM( atual) FROM table1 WHERE user =1)
FROM table2 INNER JOIN table3
ON table2.category_id=table3.id
Here is a method:
select t3.id, t3.name, sum(actual) as actual, sum(budget) as budget
from ((select category_id, sum(actual) as actual, NULL as budget
from table1
where user = 1
group by category_id
) union all
(select category_id, NULL as actual, sum(budget) as budget
from table2
where user = 1
group by category_id
)
) ab join
table3 t3
on ab.category_id = t3.id
group by t3.id, t3.name;

SQL Statement Construction: Selecting Unique Records

I currently have a table of Users, and at what time they connected to a device (e.g. a Wifi Router).
+-------------+-----------+---------+------------+---------------------+
| location_id | device_id | user_id | dwell_time | date |
+-------------+-----------+---------+------------+---------------------+
| 14 | 1 | 1 | 27.000000 | 2014-01-04 00:51:12 |
| 15 | 2 | 1 | 12.000000 | 2014-01-04 01:08:56 |
| 16 | 1 | 1 | 12.000000 | 2014-01-04 01:09:26 |
| 17 | 2 | 1 | 318.000000 | 2014-01-04 01:09:38 |
| 18 | 1 | 2 | 20.000000 | 2014-01-04 01:30:03 |
| 19 | 2 | 3 | 20.000000 | 2014-01-04 01:30:03 |
+-------------+-----------+---------+------------+---------------------+
I need to write a query title "Get Latest User Connections".
Basically, it needs to go through the history table shown above, and pick the latest record (based on Date) for each user and display it. In the example above, the result should be:
+-------------+-----------+---------+------------+---------------------+
| location_id | device_id | user_id | dwell_time | date |
+-------------+-----------+---------+------------+---------------------+
| 17 | 2 | 1 | 318.000000 | 2014-01-04 01:09:38 |
| 18 | 1 | 2 | 20.000000 | 2014-01-04 01:30:03 |
| 19 | 2 | 3 | 20.000000 | 2014-01-04 01:30:03 |
+-------------+-----------+---------+------------+---------------------+
Can someone please help me write a SQL statement that does this?
Assuming the combination of user_id and date is unique in the table, you could
SELECT
tablename.*
FROM tablename
INNER JOIN (
SELECT user_id, MAX(`date`) AS maxdate
FROM tablename
GROUP BY user_id
) AS selector
ON tablename.user_id=selector.user_id AND tablename.`date`=selector.maxdate
select *
from users
inner join (select user_id,max(date) as maxdate
from users
group by user_id)T1
on T1.user_id = users.user_id
AND T1.maxdate = users.date
or if you don't want to have a subquery, you can user #variables like this query below
SELECT location_id,device_id,user_id,dwell_time,date,
IF(#prevUserId IS NULL OR #prevUserId != user_id,#row:=1,#row:=#row+1) as row,
#prevUserId := user_id
FROM users
HAVING row = 1
ORDER BY user_id,date DESC
here's the sqlFiddle
Try this:
SELECT u.location_id, u.device_id, u.user_id, u.dwell_time, u.datec
FROM (SELECT u.location_id, u.device_id, u.user_id, u.dwell_time, u.date
FROM users u ORDER BY u.user_id, u.date DESC
) A
GROUP BY u.user_id
OR
SELECT u.location_id, u.device_id, u.user_id, u.dwell_time, u.date
FROM users u
INNER JOIN (SELECT u.user_id, MAX(u.date) AS latestDate
FROM users u GROUP BY u.user_id
) A ON u.user_id = A.user_id AND A.latestDate = u.date

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