Getting UNIX TIME with number - mysql

MySQL Query:
SELECT c.day,
COUNT(site_id)
FROM calendar c
LEFT JOIN
(
SELECT *
FROM visitors
WHERE site_id = 16
) d ON DAYOFMONTH(d.created) = c.day
WHERE c.day BETWEEN DAYOFMONTH('2012-10-01') AND DAYOFMONTH('2012-10-31')
GROUP BY c.day
ORDER BY c.day
My Tables
Calendar
id | day
---------
1 | 1
2 | 2
3 | 3
...
31 | 31
Visitors
id | site_id | created
-----------------------------------
1 | 16 | 2012-10-18 11:14:39
2 | 16 | 2012-10-18 11:15:17
3 | 11 | 2012-10-18 11:49:14
4 | 11 | 2012-10-18 11:49:43
5 | 16 | 2012-10-19 11:54:37
6 | 1 | 2012-10-19 05:56:31
7 | 2 | 2012-10-19 05:57:56
I used the above query to retrieve a daily result of visits to a site. The query solved my question here.
Results:
day | COUNT(*)
-------------
1 | 0
2 | 0
3 | 0
....
18 | 2
19 | 1
...
31 | 0
Although, now, I am having problems retrieving UNIX_TIMESTAMP from the day which I need for graphing purposes.
How do I retrieve it from the c.day in the query?

Edited:
SELECT
UNIX_TIMESTAMP('2012-10-01' + INTERVAL c.day - 1 DAY) unix_ts_day,
COUNT(v.site_id)
FROM
calendar c
LEFT JOIN (
SELECT * FROM visitors
WHERE site_id = 16 AND DATE(created) BETWEEN '2012-10-01' AND '2012-10-31'
) v
ON DAYOFMONTH(v.created) = c.day
GROUP BY
unix_ts_day

Related

Query based on dates

I've got the following table/data (example)
Users
user_id | email
1 | asd#asd.com
2 | asd2#asd.com
3 | asd3#asd.com
4 | asd4#asd.com
5 | asd5#asd.com
Scheduled_Jobs
job_id | user_id | date
1 | 1 | 05/09/2019
2 | 1 | 05/10/2019
3 | 1 | 05/11/2019
4 | 1 | 05/12/2019
5 | 2 | 07/10/2019
6 | 2 | 07/11/2019
7 | 2 | 07/12/2019
8 | 3 | 11/07/2019
9 | 4 | 13/10/2019
10 | 4 | 13/11/2019
11 | 5 | 10/10/2019
12 | 5 | 10/11/2019
13 | 5 | 10/12/2019
Last_Update
update_id | job_id
1 | 1
2 | 2
3 | 3
4 | 5
5 | 9
6 | 11
When a user is created a list of scheduled jobs is created too. When a user completes a job the Last_Update table is getting updated.
I'm trying to show a list of users which got unfinished jobs based on date. For example 1-30 days delay: x users, 31-60 days delay: y users etc
Based on the example above here would be the expected result:
Number of users with no delayed jobs: 2 (users 1 & 4)
1-30 days delay: 2 (users 2 & 5)
31-60 days delay: 0
Over 60 days delay: 1 (user 3)
I'm currently only showing the number of users that got no delayed jobs
SELECT u.user_id
FROM users u
LEFT JOIN (
SELECT j.user_id AS completed
FROM jobs j
LEFT JOIN last_update lu
ON lu.job_id = j.job_id
WHERE j.job_date <= CURDATE()
AND lu.update_id IS NULL
) AS cj
ON u.user_id = cj.completed
WHERE cj.completed IS NULL
You can first join the three tables, aggregate by user_id and compute, for each user
how many unfinished jobs they have
how many unfinished jobs they have within the last 30 days
how many unfinished jobs they have within the last 31-60 days
Then, you can add another level of aggreation and count how many users meet each criteria.
Query:
select
sum(cnt_jobs_unfinished = 0) cnt_users_no_unfinished_jobs,
sum(cnt_jobs_unfinished_30d > 0) cnt_users_unfinished_30d,
sum(cnt_jobs_unfinished_31_60d > 0) cnt_users_unfinished_31_60d
from (
select
u.user_id,
sum(l.job_id is null) cnt_jobs_unfinished,
sum(
l.job_id is null
and j.date >= curdate() - interval 30 day
) cnt_jobs_unfinished_30d,
sum(
l.job_id is null
and j.date < curdate() - interval 30 day
and j.date >= curdate() - interval 60 day
) cnt_jobs_unfinished_31_60d
from users u
inner join scheduled_jobs j
on j.date <= curdate()
and j.user_id = u.user_id
left join last_update l
on l.job_id = j.job_id
group by u.user_id
) t
Demo on DB Fiddle
cnt_users_no_unfinished_jobs | cnt_users_unfinished_30d | cnt_users_unfinished_31_60d
---------------------------: | -----------------------: | --------------------------:
2 | 2 | 1
Note: I had to modify your sample data so job 8, for user 3, has a date within 30-60 days, as it was not the case in your original data).
You can run the subquery independantly to see what it returns:
user_id | cnt_jobs_unfinished | cnt_jobs_unfinished_30d | cnt_jobs_unfinished_31_60d
------: | ------------------: | ----------------------: | -------------------------:
1 | 0 | 0 | 0
2 | 1 | 1 | 0
3 | 1 | 0 | 1
4 | 0 | 0 | 0
5 | 1 | 1 | 0

Sum childrens in two tables of a table

I Have 3 tables:
a (id,date,ckey) b(id,a.ckey,hht,hha) c(id,a.ckey,date_ini,date_fin)
where B keeps all the activities to be done and their respective hours in 2 places (hht,hha), while c saves the activities carried out with its initial and final date (to determine the hours executed the dates are subtracted).
Now I need to know, for each record in A how many hours you have assigned (B) and how many hours you have completed (C)
actually i have this:
a:
+----------+----------+------------+
| id | date | ckey |
+----------+----------+------------+
| 1 |2018-01-20| 18 |
|----------|----------|------------|
b:
+----------+----------+--------+--------+
| id | a.ckey | hht | hht |
+----------+----------+--------+--------+
| 1 | 18 | 2 | 3 |
| 2 | 18 | 2 | 5 |
| 3 | 18 | 0 | 7 |
+----------+----------+--------+--------+
c:
+----------+----------+----------------------+----------------------+
| id | a.ckey | date_ini | date_fin |
+----------+----------+----------------------+----------------------+
| 1 | 18 | 2019-01-23 13:30:00 | 2019-01-23 14:00:00 |
| 1 | 18 | 2019-01-23 14:00:00 | 2019-01-23 14:30:00 |
+----------+----------+----------------------+----------------------+
I need this:
+----------+----------+----------------------+----------------------+
| id | a.ckey | hours | hours2 |
+----------+----------+----------------------+----------------------+
| 1 | 18 | 19 | 1 |
+----------+----------+----------------------+----------------------+
I get this:
+----------+----------+----------------------+----------------------+
| id | a.ckey | hours | hours2 |
+----------+----------+----------------------+----------------------+
| 1 | 18 | 38 | 37.5 |
+----------+----------+----------------------+----------------------+
This is my query:
SELECT
(b.hht+b.hha) AS hours,
(SUM(b.hht+b.hha) -
FORMAT(IFNULL((TIMESTAMPDIFF(MINUTE, c.date_ini, c.date_fin)/60),0),2)) AS hours2
FROM a
LEFT JOIN b ON a.key=b.akey
INNER JOIN c ON a.key=c.akey
GROUP a.ckey
Because you have multiple rows in tables b and c for each value of ckey you need to do the aggregation within a subquery, otherwise you get duplicated rows leading to incorrect sums.
SELECT a.id, a.key, b.hours, FORMAT(c.minutes/60, 2) AS hours2
FROM a
LEFT JOIN (SELECT akey, SUM(hht+hha) AS hours
FROM b
GROUP BY akey) b ON b.akey = a.key
LEFT JOIN (SELECT akey, SUM(TIMESTAMPDIFF(MINUTE, date_ini, date_fin)) AS minutes
FROM c
GROUP BY akey) c ON c.akey = a.key
ORDER BY a.id
Output:
id key hours hours2
1 18 19 1.00
Demo on SQLFiddle
You're doing an m-to-n-join, try UNION ALL instead:
select ckey, sum(hours) as hours, sum(hours) - sum(hours2) as hours2
from
(
SELECT ckey, (b.hht+b.hha) AS hours, NULL as hours2
FROM b
UNION ALL
SELECT ckey, NULL AS hours,
FORMAT(IFNULL((TIMESTAMPDIFF(MINUTE, c.date_ini, c.date_fin)/60),0),2)) as hours2
FROM c
) as dt
group by ckey
If you actually need columns from table a put this Select in a Derived Table and join to it.
please check this
SELECT
(SELECT SUM(hha + hht) from b where b.ckey = a.ckey) hours,
FORMAT((SELECT SUM(TIMESTAMPDIFF(MINUTE, c.date_ini, c.date_fin)/60) from c where c.ckey = a.ckey),2) as hours2
FROM A
Fiddle

Join returning zeroes for a column that should have values

I believe I have formatted my query incorrectly but my Google skills haven't come up with a solution that works. This is my query:
use movement;
select t1.StoreNumber, t1.saleDate, t1.departmentNumber, sum(t1.dollarsSold), sum(ifnull(t2.loss,0))
from movement.movement t1
left join knownLoss.producekl t2 ON t1.StoreNumber = t2.Store
where t1.StoreNumber = 3
AND (t1.departmentNumber = 10 OR t1.departmentNumber = 20 OR t1.departmentNumber = 27 OR t1.departmentNumber = 30 OR t1.departmentNumber = 40 OR t1.departmentNumber = 50 OR t1.departmentNumber = 51 OR t1.departmentNumber = 60 OR t1.departmentNumber = 70 OR t1.departmentNumber = 80 OR t1.departmentNumber = 81 OR t1.departmentNumber = 82 OR t1.departmentNumber = 90 OR t1.departmentNumber = 95 OR t1.departmentNumber = 96 OR t1.departmentNumber = 97)
AND t1.saleDate > date_sub(curdate(), interval 7 day)
group by t1.saleDate, t1.StoreNumber, t1.departmentNumber;
My intended output is to give a table grouped by date of sale, store, and department summing sales totals and sales losses in the final two columns
My expected output should look like this:
-------------------------------------------------------------
| Store Number | Sale Date | Dept Num | Dollars Sold | Loss |
-------------------------------------------------------------
| 1 | 2017-3-9 | 10 | 7435.26 | 0.00 |
-------------------------------------------------------------
| 1 | 2017-3-9 | 20 | 30.50 | 3.00 |
-------------------------------------------------------------
| 1 | 2017-3-10 | 10 | 2503.22 | 4.00 |
-------------------------------------------------------------
| 2 | 2017-3-11 | 10 | 5685.49 |17.50 |
-------------------------------------------------------------
| 3 | 2017-3-9 | 10 | 75.26 | 4.55 |
-------------------------------------------------------------
| 4 | 2017-3-9 | 10 | 7435.26 | 0.00 |
-------------------------------------------------------------
| 4 | 2017-3-13 | 30 | 20.45 | 1.99 |
-------------------------------------------------------------
Instead of my expected output the loss column the loss column is all zeroes.
-------------------------------------------------------------
| Store Number | Sale Date | Dept Num | Dollars Sold | Loss |
-------------------------------------------------------------
| 1 | 2017-3-9 | 10 | 7435.26 | 0.00 |
-------------------------------------------------------------
| 1 | 2017-3-9 | 20 | 30.50 | 0.00 |
-------------------------------------------------------------
| 1 | 2017-3-10 | 10 | 2503.22 | 0.00 |
-------------------------------------------------------------
| 2 | 2017-3-11 | 10 | 5685.49 | 0.00 |
-------------------------------------------------------------
| 3 | 2017-3-9 | 10 | 75.26 | 0.00 |
-------------------------------------------------------------
| 4 | 2017-3-9 | 10 | 7435.26 | 0.00 |
-------------------------------------------------------------
| 4 | 2017-3-13 | 30 | 20.45 | 0.00 |
-------------------------------------------------------------
Even though when I query t2 alone it returns results
use knownLoss;
select t2.Store, t2.Department, t2.klDate, sum(t2.loss)
from producekl t2
group by klDate, Store, Department;
So my join must be messed up but I can't figure out how. Any ideas?
FWIW, I find this easier to read...
I'm unfamiliar with the curdatee() function, so I substituted it for something else...
SELECT t1.StoreNumber
, t1.saleDate
, t1.departmentNumber
, SUM(t1.dollarsSold)
, SUM(IFNULL(t2.loss,0))
FROM movement.movement t1
LEFT
JOIN knownLoss.producekl t2
ON t1.StoreNumber = t2.Store
WHERE t1.StoreNumber = 3
AND t1.departmentNumber IN(10,20,27,30,40,50,51,60,70,80,81,82,90,95,96,97)
AND t1.saleDate > DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY t1.saleDate
, t1.StoreNumber
, t1.departmentNumber;
Note that saledate is missing from the GROUP BY. BAD.
I finally worked the issue out. Neither of the tables I was joining had unique values, therefore I had to use subqueries to produce the unique values. Here is the final query that resulted in the output I expected.
SELECT t2.StoreNumber
, t2.departmentNumber
, sum(t2.Sales) AS netSales
, ifnull(sum(t3.loss),0) AS knownLoss
, ifnull(round(avg(t3.loss / t2.Sales),4),0) AS percentLoss
from ( SELECT t1.StoreNumber
, t1.departmentNumber
, SUM(t1.dollarsSold) AS Sales
FROM movement.movement t1
WHERE t1.StoreNumber = 1
AND t1.departmentNumber = 80
AND t1.saleDate >= date_sub(SUBDATE(curdate(), WEEKDAY(curdate())), interval 7 day)
AND t1.saleDate < SUBDATE(curdate(), WEEKDAY(curdate()))
GROUP BY t1.StoreNumber
, t1.departmentNumber) t2
left join
(select Store, Department, sum(loss) AS loss
from producekl
where Department = 80
AND Store = 1
AND klDate >= date_sub(SUBDATE(curdate(), WEEKDAY(curdate())), interval 7 day)
AND klDate < SUBDATE(curdate(), WEEKDAY(curdate()))
group by Store, Department) t3 ON t2.StoreNumber = t3.Store
GROUP BY t2.StoreNumber, t2.departmentNumber
Thanks to Strawberry for encouraging good formatting, it helped me resolve my issue faster.

How to identify entities which have repeated values in sequence using MySQL?

I have a table:
UNIT_ID | YEAR | MONTH | VAR
---------+------+-------+------
1 | 2015 | 1 | 0
1 | 2015 | 2 | 0
1 | 2015 | 3 | 0
2 | 2015 | 1 | 10
2 | 2015 | 2 | 10
2 | 2015 | 3 | 10
1 | 2015 | 4 | 5
1 | 2015 | 5 | 5
1 | 2015 | 6 | 5
2 | 2015 | 4 | 10
2 | 2015 | 5 | 3
2 | 2015 | 6 | 3
3 | 2016 | 1 | 3
3 | 2016 | 2 | 3
3 | 2016 | 3 | 3
3 | 2016 | 4 | 3
2 | 2016 | 6 | 0
2 | 2016 | 7 | 0
2 | 2016 | 8 | 0
I want to know which units have a sequence bigger than 3 zeros or bigger than 4 values repeated. Grouped by year. So, my result table would be like this:
1 | 2015 | true
2 | 2015 | true
2 | 2016 | true
I have found this solution but unfortunately I could not adapt to my case. I need also that the query is in MySQL.
You could just join them 4 times. Last join is a left join to allow the case for 3 0's.
select a.unit_id, a.year, 'true'
from tbl a
join tbl b on a.unit_id = b.unit_id and a.year = b.year and a.month+1 = b.month and a.var = b.var
join tbl c on b.unit_id = c.unit_id and b.year = c.year and b.month+1 = c.month and b.var = c.var
left join tbl d on c.unit_id = d.unit_id and c.year = d.year and c.month+1 = d.month and c.var = d.var
where a.var = 0 or d.var is not null;
Faster and more generic solution. It scans the table only once, and uses user defined variables (#pu for previous unit_id, #py for previous year, etc) to remember the previous row:
select distinct unit_id, year
from (
select unit_id, `year`, `month`, `var`,
if(unit_id=#pu and `year`=#py and `month`=#pm+1 and `var`=#pv, #i:=#i+1, #i:=1)*
if(#pu:=unit_id,1,1)*if(#py:=`year`,1,1)*if(#pm:=`month`,1,1)*if(#pv:=`var`,1,1) as c
from table1 a
join (select #pu:=null, #py:=null, #pm:=null, #pv:=null, #i:=1) b
order by unit_id, `year`, `month`, `var`) a
group by unit_id, `year`, `var`
having (`var` = 0 and max(c) >= 3) or (`var` != 0 and max(c) >= 4);
fiddle

Query date column from join table

Here is the schema:
Customer (Customer_ID, Name, Address, Phone),
Porder (Customer_ID, Pizza_ID, Quantity, Order_Date),
Pizza (Pizza_ID, Name, Price).
I want to get all customers that ordered a pizza in the last 30 days, based on the Order_Date & who spent the most money in the last 30 days. Can these be combined into one?
Here is what I am trying and I am not sure about DATEDIFF or how the query would calculate the total money.
SELECT customer.customer_ID, customer.name FROM customer
JOIN porder ON customer.customer_ID = porder.customer_ID
GROUP BY customer.customer_ID, customer.name
WHERE DATEDIFF(porder.porder_date,getdate()) between 0 and 30
Who spent the most money last 30 days?
SELECT porder.customer_ID, porder.pizza_id, porder.quantity FROM order
JOIN pizza ON porder.pizza_ID = pizza.pizza_ID
GROUP BY porder.customer_ID
WHERE MAX((porder.quantity * pizza.price)) && DATEDIFF(porder.porder_date,getdate()) between 0 and 30
Remember that functions are blackboxes to query optimizer, so you better make the query fit the index, and not the other way around.
WHERE DATEDIFF(order.order_date,getdate()) between 0 and 30
can be rewritten, so that the query would use plain index on order_date
WHERE order.order_date >= CURRENT_DATE - INTERVAL 30 DAY
Who spent the most money in the last 30 days
SELECT
o.customer_id, SUM(p.price * o.quantity)
FROM
order o
INNER JOIN pizza p
ON o.pizza_id = p.pizza_id
WHERE
order_date >= CURRENT_DATE - INTERVAL 30 DAY
GROUP BY o.customer_id
ORDER BY SUM(p.price * o.quantity) DESC
LIMIT 1
Something to think about once you've sorted out your tables, and separated order details from orders.
SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
SELECT x.*
, IF(x.i = y.maxi,1,0) is_biggest
FROM ints x
LEFT
JOIN (SELECT MAX(i) maxi FROM ints) y
ON y.maxi = x.i;
+---+------------+
| i | is_biggest |
+---+------------+
| 0 | 0 |
| 1 | 0 |
| 2 | 0 |
| 3 | 0 |
| 4 | 0 |
| 5 | 0 |
| 6 | 0 |
| 7 | 0 |
| 8 | 0 |
| 9 | 1 |
+---+------------+