Find average amount of time from Requisition Submitted to Order Created - mysql

I have two tables requisition_headers and order_headers. I am interested in finding the average time it takes from the time the requisition is submitted (requisition_headers.submitted_at) and the time the order is created (orders.headers_created_at) where the requisition_headers.status <> 'draft'.
I would like the result to look like:
Avg_Req_To_PO_Cycle_Time = 3.2 Days
I have the following script but it's not working:
SELECT Database() as Customer,
AVG(timestampdiff(requisition_headers.submitted_at,order_headers.created_at)) AS REQ_PO_Cycle_Time
FROM order_headers
LEFT JOIN requisition_headers ON order_headers.requisition_header_id = requisition_headers.id
WHERE requisition_headers.status <> 'draft'
Any Ideas?
--UPDATE--
I changed the query to the following and now get a response of 229491.71 my question is- is that days, hours, minutes, seconds?
SELECT DATABASE() AS CUSTOMER,
AVG(TIME_TO_SEC(TIMEDIFF(order_headers.created_at,requisition_headers.submitted_at))) as Cycle_time
FROM order_headers LEFT JOIN requisition_headers ON order_headers.requisition_header_id = requisition_headers.id
where requisition_headers.status <> 'draft'

Make sure you know what a system function returns when you use it. The TimestampDiff function returns the difference between the two dates in the unit you specify in the first argument. You don't specify that unit so I don't know what you get back. I get a compile error.
In your second attempt, you are using TimeDiff which returns an interval value, then converting the result of Avg to seconds. So if you want the result in fractional days just divide by the number of seconds in a day.
You also use a left join when getting the dates. At first I thought you wanted to get all the requisitions whether the orders had been created or not. But you are joining the tables in the wrong order for that. But, assuming that is your intention, if the order has not yet been created you will be putting NULL as one of the parameters. You will get a NULL as an answer so you get nothing. If you want to use a left join, then you should specify a substitute date for any missing Created dates -- after getting the table in the right order, that is.
Here are two options. One ignores orders that have not yet been created by using a regular inner join. The other includes those but substitutes the current date and time.
By asking for the number of minutes between the dates, the final answer in days is found by dividing by the number of minutes in a day.
SQLFiddle
SELECT Customer,
AVG( timestampdiff( minute, r.submitted_at,
o.created_at)) / (24 * 60 )AS REQ_PO_Cycle_Time
FROM requisition_headers r
JOIN order_headers o
ON o.requisition_header_id = r.id
WHERE r.status <> 'draft'
group by Customer;
SELECT Customer,
AVG( timestampdiff( minute, r.submitted_at,
IfNull( o.created_at, CurDate()))) / (24 * 60 )AS REQ_PO_Cycle_Time
FROM requisition_headers r
LEFT JOIN order_headers o
ON o.requisition_header_id = r.id
WHERE r.status <> 'draft'
group by Customer;

Related

Getting all value from every month, put zero if no data of that month

i'm trying to get data for each month, if there is no data found for a particular month, I will put zero. I already created a calendar table so I can left join it, but I still can't get zero.
Here's my query
SELECT calendar.month, IFNULL(SUM(transaction_payment.total),0) AS total
FROM `transaction`
JOIN `transaction_payment` ON `transaction_payment`.`trans_id` =
`transaction`.`trans_id`
LEFT JOIN `calendar` ON MONTH(transaction.date_created) = calendar.month
WHERE`date_created` LIKE '2017%' ESCAPE '!'
GROUP BY calendar.month
ORDER BY `date_created` ASC
the value in my calendar tables are 1-12(Jan-Dec) int
Result should be something like this
month total
1 0
2 20
3 0
4 2
..
11 0
12 10
UPDATE
The problem seems to be the SUM function
SELECT c.month, COALESCE(t.trans_id, 0) AS total
FROM calendar c
LEFT JOIN transaction t ON month(t.date_created) = c.month AND year(t.date_created) = '2018'
LEFT JOIN transaction_payment tp ON tp.trans_id = t.trans_id
ORDER BY c.month ASC
I tried displaying the ID only and it's running well. but when I add back this function. I can only get months with values.
COALESCE(SUM(tp.total), 0);
This fixes the issues with your query:
SELECT c.month, COALESCE(SUM(tp.total), 0) AS total
FROM calendar c LEFT JOIN
transaction t
ON month(t.date_created) = month(c.month) AND
year(t.date_created) = '2017' LEFT JOIN
transaction_payment tp
ON tp.trans_id = t.trans_id
GROUP BY c.month
ORDER BY MIN(t.date_created) ASC;
This will only work if the "calendar" table has one row per month -- that seems odd, but that might be your data structure.
Note the changes:
Start with the calendar table, because those are the rows you want to keep.
Do not use LIKE with dates. MySQL has proper date functions. Use them.
The filtering conditions on all but the first table should be in the ON clause rather than the WHERE clause.
I prefer COALESCE() to IFNULL() because COALESCE() is ANSI standard.
You need to use right as per your query because you calendar table is present at right side
SELECT calendar.month, IFNULL(SUM(transaction_payment.total),0) AS total
FROM `transaction`
JOIN `transaction_payment` ON `transaction_payment`.`trans_id` =
`transaction`.`trans_id`
RIGHT JOIN `calendar` ON MONTH(transaction.date_created) = calendar.month
WHERE`date_created` LIKE '2017%' ESCAPE '!'
GROUP BY calendar.month
ORDER BY `date_created` ASC

Display zero in group by sql for a particular period

I am trying to run the following query to obtain the sales for each type of job for a particular period. However for certain months where there are no jobs of a particular job type performed no 0 is displayed in sales.
How can i display the zeros in such a condition.
Here is the sql query-
select Year(postedOn), month(postedOn), jobType, sum(price)
from tbl_jobs
group by jobType, year(postedOn), month(postedOn)
order by jobType, year(postedOn), month(postedOn)
Typically, this is where your all-purpose calendar or numbers table comes in to anchor the query with a consistent sequential set:
SELECT job_summary.*
FROM Calendar
CROSS JOIN (
-- you may not have though about this part of the problem, though
-- what about years/months with missing job types?
SELECT distinct jobType FROM tbl_jobs
) AS job_types
LEFT JOIN (
select Year(postedOn) AS year,month(postedOn) as month,jobType ,sum(price)
from tbl_jobs
group by jobType, year(postedOn), month(postedOn)
) job_summary
ON job_summary.jobType = job_types.jobType
AND job_summary.year = Calendar.year
AND job_summary.month = Calendar.month
WHERE Calendar.day = 1 -- Assuming your calendar is every day
AND calendar.date BETWEEN some_range_goes_here -- you don't want all time, right?
order by job_types.jobType, Calendar.year, Calendar.month

Mysql - comparing two strings in the same table on different dates

Relevant table structure is:
id(INT), reference_id(INT), status(VARCHAR(20)), date(TIMESTAMP)
This record is updated once per day.
Problem:
I want to display each record where the status field, which is static most of the time, is different to the one on the preceeding day, thus being able to show the date a status changed and display a history.
How?
Pseudo:
Show * where status for today != status for yesterday
Early logic, but my limited knowledge of mysql is causing me to hit a wall.
SELECT * from table_name WHERE DATE(date) = CURDATE()
UNION
SELECT table_name.status AS yesterday_status WHERE DATE(date) = CURDATE() - 1
I was then going to compare them both in perl, which is not so efficient so I'm hoping somebody can share some enlightenment...
Here is my approach. It is not exactly what you were asking for, but if maybe you will like my solution.
http://sqlfiddle.com/#!9/896b4/7
SELECT
today.*,
yesterday.*
FROM t_status today
LEFT JOIN t_status yesterday
ON DATE(yesterday.date)<DATE(today.date)
AND yesterday.reference_id = today.reference_id
AND yesterday.status != today.status
WHERE DATE(today.date) = CURDATE()
ORDER BY yesterday.date DESC
LIMIT 1
;
UPDATE Or probably I misunderstood your goal, and you need only compare yesterdays status, not all past statuses. If so you can try this INNER JOIN:
http://sqlfiddle.com/#!9/dd61f1/4
SELECT
today.*,
yesterday.*
FROM t_status today
INNER JOIN t_status yesterday
ON DATE_ADD(CURDATE(),INTERVAL -1 DAY) = DATE(yesterday.date)
AND yesterday.reference_id = today.reference_id
AND yesterday.status != today.status
WHERE DATE(today.date) = CURDATE();
You are welcome if any questions.
The below query shows the records along with the previous day's record (I assumed that reference_id is also a join citeria, if not, just remove it)
select t1.*, t2.* from table t1
left join table t2 on t1.reference_id=t2.reference_id and date(t1.date)-1=date(t2.date)
You can even filter it further to display only those pairs, where the previous day's status is different (note that the join changes from left to inner, since if there is no previous day's record, that's not a change is status):
select t1.*, t2.* from table t1
inner join table t2 on t1.reference_id=t2.reference_id and date(t1.date)-1=date(t2.date) and t1.status<>t2.status
I think query should be like
select * from tablename where status <> (select * from tablename where date=Sysdate-1)
Sysdate is use for System date.

subquery returns more than one row error

Okay, there are.. a number.. of questions on SO with the same title, but I couldn't think of how to be more specific.
The reason that this is confusing me is that returning more than one row is a desired effect of (one of) my sub queries
SELECT MAX(theCount) FROM
(SELECT FK_Hour, Count(FK_Hour) As theCount FROM
(Select FK_Hour
From slottime
INNER JOIN time ON slottime.FK_Hour = time.Hour
WHERE FK_Hour =
(SELECT time.Hour FROM time WHERE time.day=0 )
) As C
GROUP By FK_Hour
) AS counts;
I realise that time is a reserved word for MySQL - it is probably something I will have to rectify soon; though I doubt its the problem in this case.
The aim of the query is to select the maximum count of instances of particular hours where day = 0.
The problem is clearly:
WHERE FK_Hour = (SELECT time.Hour FROM time WHERE time.day=0 )
The simplest solution is to change = to in:
WHERE FK_Hour IN (SELECT time.Hour FROM time WHERE time.day=0 )
However, you might want to check your data to determine if this is what you really intend.

Getting Incorrect SUM for left joins and GROUP BY

I am getting wrong results in the sum of total deposits.
I want to output a report of total deposits per campaign_name
and eventually inside a date range.
SELECT IFNULL(campaign_name,'DIRECT'),
IFNULL(TotalDeposit,0)
FROM trackings
LEFT JOIN
(SELECT deposit_amount,
sum(deposit_amount) AS TotalDeposit,
uuid
FROM conversions
LEFT JOIN transactions ON conversions.trader_id = transactions.trader_id
WHERE aff_id =3
AND TYPE='deposit'
GROUP BY transactions.trader_id) AS conversions ON trackings.uuid = conversions.uuid
WHERE aff_id=3
GROUP BY campaign_name
results: missing 200 from trynow campaign??
campaign_name,TotalDeposit
DIRECT,0.00
new_campaign_name,0.00
test march,500.00
testing,0.00
trynow,800.00
expected results:
campaign_name,TotalDeposit
DIRECT,0.00
new_campaign_name,0.00
test march,500.00
testing,0.00
trynow,1000.00
I think your data isn't quite right - using the data that you've supplied, the deposit of 500 for test march is never going to be returned, as it is linked to trader_id 7506, who has no records in the conversions table.
However, the following query is simpler and easier to understand, and correctly returns 1000 for trynow
SELECT
IFNULL(SUM(t.deposit_amount),0) AS total_deposits
, IFNULL(tr.campaign_name,'DIRECT') AS campaign
FROM
trackings tr LEFT JOIN
conversions c ON
tr.uuid = c.uuid LEFT JOIN
transactions t ON
c.trader_id = t.trader_id AND
tr.`aff_id` = t.aff_id AND
t.type = 'Deposit'
WHERE
tr.aff_id = 3 AND
tr.updated_at >= '2015-03-01' AND tr.updated_at < '2015-04-01'
GROUP BY
IFNULL(tr.campaign_name,'DIRECT')
If you can check the test data supplied or otherwise point me in the right direction, I might be able to improve the query to return exactly what you want.
For date filtering, see the addition to the where clause above. NOte that if you need to filter on a date in the transactions table, the date filtering clause must be part of the "on" statement instead (as this table is left-joined, so we can't filter in the main where clause).