good morning,
I have a nagging issue I cannot really solve.. I have a database table like this, showing resources spent (value) in a date range by person:
id,name,startdate,enddate,value
--------------------------------
10,John,2012-01-14,2012-10-30,200000
11,Jack,2012-02-01,2012-08-01,70000
12,John,2012-05-01,2012-06-01,2000
I need a query that creates the result like this, summarizing the 'value' by month, taking partial months into account
month, name, value
------------------
2012-01, John, 9000
2012-02, John, 18000
2012-03, John, 18000
2012-04, John, 18000
2012-05, John, 20000
2012-06, John, 18000
2012-07, John, 18000
2012-08, John, 18000
2012-01, John, 18000
2012-02, Jack, 10000
2012-03, Jack, 10000
2012-04, Jack, 10000
2012-05, Jack, 10000
2012-06, Jack, 10000
2012-07, Jack, 10000
2012-08, Jack, 0
Now I know how I'd do this procedurally (like with PHP) with a loop: get the daily amount, then check month by month how many days spent there according to the range and multiply it by the daily amount.
thanks
peter
If you don't have a calendar table and can't create one, you can simulate a virtual calendar table in your query. Here's a query that should answer your question, that makes use of such a virtual table:
select m.startmonth,
e.name,
coalesce(sum(r.value *
datediff(case when adddate(m.startmonth, interval 1 month) <
r.enddate
then adddate(m.startmonth, interval 1 month)
else r.enddate end,
case when m.startmonth > r.startdate
then m.startmonth else r.startdate end) /
datediff(r.enddate,r.startdate)),0) valueshare
from
(select cast('2012-01-01' as date) startmonth union all
select cast('2012-02-01' as date) startmonth union all
select cast('2012-03-01' as date) startmonth union all
select cast('2012-04-01' as date) startmonth union all
select cast('2012-05-01' as date) startmonth union all
select cast('2012-06-01' as date) startmonth union all
select cast('2012-07-01' as date) startmonth union all
select cast('2012-08-01' as date) startmonth union all
select cast('2012-09-01' as date) startmonth union all
select cast('2012-10-01' as date) startmonth) m
cross join employees e
left join resources_spent r
on r.enddate > m.startmonth and
r.startdate < adddate(m.startmonth, interval 1 month) and
r.name = e.name
group by m.startmonth, e.name
order by 2,1
SQLFiddle here.
I think you need a calendar table with one row for each date. Other fields would be whatever is useful to you, such as fiscal periods, holidays, whatever.
Then, for your report, you could create a temp table and populate it like this:
insert into YourTempTable
(id, date, amount)
select id, c.datefield, amount
from YourTable join Calendar c on datefield >= startdate
and datefield <= enddate
where whatever
From there, you select from YourTempTable and YourTable, joining on the id.
Related
I have the entries of monthly dues like,
Table name : month_dues,
Columns:
customer_id,
due_date,
due_amount
These table have lot of due entries.
customer_id due_date due_amount
--------------------------------------
1 2018-12-01 100
1 2019-01-01 100
1 2019-02-01 100
1 2019-10-01 100
so, how to select pending due months from these record?
in my table customer 1 not paid dues for these months,
2019-03,2019-04,2019-05,2019-06,2019-07,2019-08, 2019-09
customer pay the due every month so
For select paid dues from table using,
SELECT customer_id, due_date, due_amount FROM month_dues where customer_id='1' where due_date>='2019-01-01' and due_date<='2019-10-18';
How to get pending due month and year using this table?
Which means, find month and year not in this record.
IF you are searching between the two dates
YOu can use this
select * from month_dues
where due_date between '2012-03-11 00:00:00' and '2012-05-11
23:59:00' && customer_id='1'
order by month_dues desc;
If you want to search the date(due_date) lower than today
SELECT * FROM month_dues WHERE due_date < CURDATE();
And you are refeering to the record that is not belong to the query you can find some NOT IN query
Like
`SELECT * FROM month_dues NOT IN ( select * from month_dues
where due_date between '2012-03-11 00:00:00' and '2012-05-11
23:59:00' && customer_id='1'
order by month_dues desc;
)`
So basically you need to validate your table against some kind of calendar, here is a simple solution that only works for the current year, maybe you can use it as a start or someone else could improve it
SELECT m.MONTH
FROM (SELECT 1 AS MONTH
UNION SELECT 2 AS MONTH
UNION SELECT 3 AS MONTH
UNION SELECT 4 AS MONTH
UNION SELECT 5 AS MONTH
UNION SELECT 6 AS MONTH
UNION SELECT 7 AS MONTH
UNION SELECT 8 AS MONTH
UNION SELECT 9 AS MONTH
UNION SELECT 10 AS MONTH
UNION SELECT 11 AS MONTH
UNION SELECT 12 AS MONTH) as m
WHERE m.MONTH NOT IN (SELECT MONTH(due_date)
FROM due_months
WHERE customer_id = 1
AND YEAR(due_date) = YEAR(CURDATE()))
AND m.MONTH < MONTH(CURDATE()) -- needs to be improved as well
I am very new to SQL and I need to write a query that selects data for a specific part. However, It should select only the part that is the most recent(given by date) and anything that is only 30 days prior to it. Please consider the table below:
PartID | Part_NAME | DATE
-----------------------------
1 AAA 6/16/2015
2 BBB 6/15/2015
3 AAA 6/11/2015
4 AAA 1/1/2008
I need a query that gives me:
PartID | Part_NAME | DATE
-----------------------------
1 AAA 6/16/2015
3 AAA 6/11/2015
I have tried:
select * from ( select * from sales_table where Part_NAME = 'AAA') where DATE BETWEEN (max(DATE) and (max(DATE)-30))
I have read some articles saying that I cannot use WHERE and functions like max() together and advised me to use group by or having but it didn't work for me as well. Thank you.
IF you want data from the last 30 days of the current day, you can do :
SELECT *
FROM sales_table
WHERE
[DATE] >= DATEADD(DAY, -30,GETDATE())
AND [DATE] <= GETDATE()
AND Part_NAME = 'AAA'
IF you want data from the last 30 days from the last date of sale of each Part_NAME (this will take the max recorded date of sale for each Part_NAME and get the last 30 days records of each one of them.)
SELECT *
FROM (
SELECT *,
MAX([DATE]) OVER(PARTITION BY Part_NAME ORDER BY PartID) AS RecentDate
FROM sales_table
) D
WHERE
[DATE] >= DATEADD(DAY, -30, RecentDate)
AND [DATE] <= RecentDate
AND Part_NAME = 'AAA'
You can accomplish by using datediff and getdate() and a subquery.
SELECT * FROM (
SELECT *,DATEDIFF(DD,[DATE],GETDATE()) AS DAYSBETWEEN FROM sales_table
) AS X
WHERE DAYSBETWEEN <= 30
If you want data from the last 30 days, it would be:
select st.*
from sales_table st join
(select top (1) st2.*
from sales_table st2
order by st2.date desc
) st2
on st2.part_name = st.part_name and
st.date >= dateadd(day, -30, cast(getdate() as date));
RDBMS: MySQL
The time column(s) datatype is of datetime
For every hour of the 24 hour day I need to retrieve the number of rows in which their start_time matches the hour OR the end_time is great than or equal to the hour.
Below is the current query I have which returns the data I need but only based off of one hour. I can loop through and do 24 separate queries for each hour of the day but I would love to have this in one query.
SELECT COUNT(*) as total_online
FROM broadcasts
WHERE DATE(start_time) = '2018-01-01' AND (HOUR(start_time) = '0' OR
HOUR(end_time) >= '0')
Is there a better way of querying the data I need? Perhaps by using group by somehow? Thank you.
Not exactly sure if i am following, but try something like this:
select datepart(hh, getdate()) , count(*)
from broadcasts
where datepart(hh, starttime) <=datepart(hh, endtime)
and cast(starttime as date)=cast(getdate() as date) and cast(endtime as date)=cast(getdate() as date)
group by datepart(hh, getdate())
Join with a subquery that returns all the hour numbers:
SELECT h.hour_num, COUNT(*) AS total_online
FROM (SELECT 0 AS hour_num UNION SELECT 1 UNION SELECT 2 ... UNION SELECT 23) AS h
JOIN broadcasts AS b ON HOUR(b.start_time) = h.hour_num OR HOUR(b.end_time) >= h.hour_num
WHERE DATE(b.start_time) = '2018-01-01'
GROUP BY h.hour_num
I have a mySQL database with each row containing an activate and a deactivate date. This refers to the period of time when the object the row represents was active.
activate deactivate id
2015-03-01 2015-05-10 1
2013-02-04 2014-08-23 2
I want to find the number of rows that were active at any time during each month. Ex.
Jan: 4
Feb: 2
Mar: 1
etc...
I figured out how to do this for a single month, but I'm struggling with how to do it for all 12 months in a year in a single query. The reason I would like it in a single query is for performance, as information is used immediately and caching wouldn't make sense in this scenario. Here's the code I have for a month at a time. It checks if the activate date comes before the end of the month in question and that the deactivate date was not before the beginning of the period in question.
SELECT * from tblName WHERE activate <= DATE_SUB(NOW(), INTERVAL 1 MONTH)
AND deactivate >= DATE_SUB(NOW(), INTERVAL 2 MONTH)
If anybody has any idea how to change this and do grouping such that I can do this for an indefinite number of months I'd appreciate it. I'm at a loss as to how to group.
If you have a table of months that you care about, you can do:
select m.*,
(select count(*)
from table t
where t.activate_date <= m.month_end and
t.deactivate_date >= m.month_start
) as Actives
from months m;
If you don't have such a table handy, you can create one on the fly:
select m.*,
(select count(*)
from table t
where t.activate_date <= m.month_end and
t.deactivate_date >= m.month_start
) as Actives
from (select date('2015-01-01') as month_start, date('2015-01-31') as month_end union all
select date('2015-02-01') as month_start, date('2015-02-28') as month_end union all
select date('2015-03-01') as month_start, date('2015-03-31') as month_end union all
select date('2015-04-01') as month_start, date('2015-04-30') as month_end
) m;
EDIT:
A potentially faster way is to calculate a cumulative sum of activations and deactivations and then take the maximum per month:
select year(date), month(date), max(cumes)
from (select d, (#s := #s + inc) as cumes
from (select activate_date as d, 1 as inc from table t union all
select deactivate_date, -1 as inc from table t
) t cross join
(select #s := 0) param
order by d
) s
group by year(date), month(date);
I have a MySQL table ATT which has EMP_ID,ATT_DATE,ATT_STATUS with ATT_STATUS with different values 1-Present,2-Absent,3-Weekly-off. I want to find out those EMP_ID's which have status 2 consecutively for 10 days in a given date range.
Please help
Please have a try with this:
SELECT EMP_ID FROM (
SELECT
IF((#prevDate!=(q.ATT_DATE - INTERVAL 1 DAY)) OR (#prevEmp!=q.EMP_ID) OR (q.ATT_STATUS != 2), #rownum:=#rownum+1, #rownum:=#rownum) AS rownumber, #prevDate:=q.ATT_DATE, #prevEmp:=q.EMP_ID, q.*
FROM (
SELECT
EMP_ID
, ATT_DATE
, ATT_STATUS
FROM
org_tb_dailyattendance, (SELECT #rownum:=0, #prevDate:='', #prevEmp:=0) vars
WHERE ATT_DATE BETWEEN '2013-01-01' AND '2013-02-15'
ORDER BY EMP_ID, ATT_DATE, ATT_STATUS
) q
) sq
GROUP BY EMP_ID, rownumber
HAVING COUNT(*) >= 10
The logic is, to first sort the table by employee id and the dates. Then introduce a rownumber which increases only if
the days are not consecutive or
the employee id is not the previous one or
the status is not 2
Then I just grouped by this rownumber and counted if there are 10 rows in each group. That should be the ones who were absent for 10 days or more.
Have you tried something like this
SELECT EMP_ID count(*) as consecutive_count min(ATT_DATE)
FROM (SELECT * FROM ATT ORDER BY EMP_ID)
GROUP BY EMP_ID, ATT_DATE
WHERE ATT_STATUS = 2
HAVING consecutive_count > 10