How to check diference between two times in two MySQL tables? - mysql

So I've got two tables:
ic:
id | created
---|--------------------
1 | 2016-03-31 16:20:03
2 | 2016-03-31 16:25:18
3 | 2016-03-31 16:28:09
status:
id | ic_id | timestamp
---|--------------------
1 | 1 | 2016-03-31 16:20:03
2 | 5 | 2016-03-31 16:25:18
3 | 5 | 2016-03-31 16:28:09
I now want to find the average difference between the ic.created and the status.timestamp of the first corresponding record in the status table. I started out with this:
SELECT status.`timestamp` - informed_consent.created as difference
FROM status
WHERE status.`timestamp` > '2017-06-19'
AND status.ic_id IN (
SELECT informed_consent.id
FROM informed_consent
WHERE informed_consent.id = status.ic_id;
);
But I immediately get an error in my mysql syntax. I guess I can also use a left join, but I'm kinda lost here.
Could anybody help me out in the right direction?

I think you can use inner join instead of sub query due to informed_consent.created is not present in outer sql,it's in the sub query
SELECT status.`timestamp`,status.`timestamp` - informed_consent.created as difference
FROM status
JOIN informed_consent ON informed_consent.id = status.ic_id
WHERE status.`timestamp` > '2017-06-19'

Related

Find latest value in a comparison of data between 2 tables

I Have 2 tables in my DB and I want to compare values of 2 select queries Ive made on each one
Table 1: click_log
Query table 1:
SELECT *
FROM click_log
Table 2: km_articles
Query table 2:
SELECT km_article_no
FROM km_articles
WHERE km_article_date <= "2017-10-31" AND km_article_status = "Published" AND km_article_view_count <= "5"
The columns I want to compare are table link_clicked for table 1 with km_article_no and I know I will find repeated matched, nevertheless from those repeated matches I want to find the latest one that I want to get from another column in table 1 called "when_clicked" that contains data information, not sure How can i put together those to queries and then narrow them down.
this is how the tables look like:
Table 1:
|link_clicked|when_clicked
KB00001 | 2017-08-02
KB00001 | 2017-12-02
KB00002 | 2017-08-02
KB00002 | 2017-09-02
KB00003 | 2017-09-02
KB00003 | 2017-09-02
Table 2:
km_article_no|km_article_ti|km_article_status|km_article_view_count|km_article_date
KB00001 |outlook IOS | Published | 5 | 2017-01-02
KB00002 |outlook CSS | Published | 4 | 2017-01-05
KB00003 |outlook ZTE | Retired | 3 | 2017-01-09
If I understand correctly, you want to show all km_articlesrows, each with the latest related click_log.when_clicked date. So aggregate your click_log per link_clicked and find the maximum when_clicked. Then join this to km_articles.
select kma.*, cl.last_clicked
from km_articles kma
join
(
select link_clicked, max(when_clicked) as last_clicked
from click_log
group by link_clicked
) cl on cl.link_clicked = kma.km_article_no
where kma.km_article_date <= date '2017-10-31'
and kma.km_article_status = 'Published'
and kma.km_article_view_count <= 5;
(If you also want to show km_articles rows that have no match in click_log, then change join to left join.)

MySQL special case pivot

I cant find an answer to this despite looking for several days!
In MySQL I have 2 Tables
ProcessList contains foreign keys all from the process Table
ID |Operation1|Operation2|Operation3|etc....
---------------------------------------
1 | 1 | 4 | 6 | ....
---------------------------------------
2 | 2 | 4 | 5 |....
---------------------------------------
.
.
.
Process Table
ID | Name
-------------------
1 | Quote
2 | Order
3 | On-Hold
4 | Manufacturing
5 | Final Inpection
6 | Complete
Now, I am new to SQL but I understand that MYSQL doesnt have a pivot function as Ive researched, and I see some examples with UNIONs etc, but I need an SQL expression something like (pseudocode)
SELECT name FROM process
(IF process.id APPEARS in a row of the ProcessList)
WHERE processListID = 2
so I get the result
Order
Manufacturing
Final Inspection
I really need the last line of the query to be
WHERE processListID = ?
because otherwise I will have to completely rewrite my app as the SQL is stored in a String in java, and the app suplies the key index only at the end of the statement.
One option is using union to unpivot the processlist table and joining it to the process table.
select p.name
from process p
join (select id,operation1 as operation from processlist
union all
select id,operation2 from processlist
union all
select id,operation3 from processlist
--add more unions as needed based on the number of operations
) pl
on pl.operation=p.id
where pl.id = ?
If you always consider only a single line in the process list (i.e. procsessListId = x), the following query should do a pretty simple and performant job:
select p.name from process p, list l
where l.id = 2
and (p.id in (l.operation1, l.operation2, l.operation3))

How is mysql interpreting/grouping a duplicate WHERE statement with an OR statement in the middle?

I am using an Laravel's ORM. It is generating a huge query and inside that query I noticed that there is a WHERE statement that repeats itself, and the order of that WHERE statement seems to be very important. I believe it has something to do with how MySQL is grouping the WHERE statements but I don't understand how MySQL works well enough. I'm trying to understand why this works the way it does. How is mysql interpreting/grouping this?
Table
items
-----------------------------------------------
id | status
-----------------------------------------------
19 | 1
20 | 0
21 | 1
Results needed:
-----------------------------------------------
id | status
-----------------------------------------------
19 | 1
21 | 1
The query is much longer than this. But here is the code the ORM is generating that produces the above results needed:
SELECT * FROM campaigns WHERE status = 1 OR id IN ('20') AND status = 1 ORDER BY id DESC;
If I remove the last status = 1 the query does not return the needed results. Is MySQL grouping the WHERE statements like this:
SELECT * FROM campaigns WHERE status = 1 OR (id IN ('20') AND status = 1);
The query the ORM produces is a few pages long, so when reading this it is pretty confusing without the parentheses. It seems like MySQL is grouping it like this. I guess I don't understand well enough how MySQL works. Any recommendations on books to better understand MySQL?
Building up the Query/Trying to understand what MySQL is doing
1)
SELECT * FROM items WHERE status = 1
Results
-----------------------------------------------
id | status
-----------------------------------------------
19 | 1
21 | 1
2)
SELECT * FROM items WHERE status = 1 OR id IN ('20')
Results
-----------------------------------------------
id | status
-----------------------------------------------
19 | 1
20 | 0
21 | 1
3)
SELECT * FROM items WHERE status = 1 OR id IN ('20') AND status = 1
Results
-----------------------------------------------
id | status
-----------------------------------------------
19 | 1
21 | 1
AND has precedence over OR, see also SQL Logic Operator Precedence: And and Or.
For your example, this means
SELECT * FROM campaigns WHERE status = 1 OR id IN ('20') AND status = 1 ;
is automatically interpreted as
SELECT * FROM campaigns WHERE status = 1 OR (id IN ('20') AND status = 1);
even if you don't put the parenthesis.
It is a good idea to always write the parenthesis, even if you know they are not needed, to make the intention clear to other readers of your code (and to the compiler/interpreter, if needed).

Date Difference from Log table

Hello guys I need help with this function, I'm using MySQL database server
version: 5.5.47-0ubuntu0.14.04.1 - (Ubuntu).
I want to be able to get how many "weeks" it took a worker to get hired. i have a table that stores log data whenever the worker's status change.
logid workerid statusid timestamp
1000 10 1(available) 2016-04-10
1001 10 2(Hired) 2016-04-24
what i want to have is :
It took worker 10 two weeks to get hired.
I already looked at DATEDIFF(first date, second date) function but I have to use two different where conditions for each date, I have no idea how to do this?
You need to join same table and to use DATEDIFF():
SELECT
e1.workerid,
DATEDIFF(e2.`timestamp`, e1.`timestamp`) daysDiff,
ROUND(DATEDIFF(e2.`timestamp`, e1.`timestamp`) / 7, 0) weeksDiff
FROM
employees e1
INNER JOIN employees e2 ON e1.workerid = e2.workerid
WHERE
e1.statusid = 1
AND e2.statusid = 2
Output:
+----------+----------+-----------+
| workerid | daysDiff | weeksDiff |
+----------+----------+-----------+
| 10 | 14 | 2 |
+----------+----------+-----------+
1 row in set

How can I get the difference between the individual maximum values of different days?

I am new in MySQL, I am trying to find:
The difference between a given day's maximum value occurred and the previous day's maximum value.
I was able to get the maximum values for dates via:
select max(`bundle_count`), `Production_date`
from `table`
group by `Production_date`
But I don't know how to use SQL to calculate the differences between maximums for two given dates.
am expecting output like this
Please help me.
Update 1: Here is a fiddle, http://sqlfiddle.com/#!2/818ad/2, that I used for testing.
Update 2: Here is a fiddle, http://sqlfiddle.com/#!2/3f78d/10 that I used for further refining/fixing, based on Sandy's comments.
Update 3: For some reason the case where there is no previous day was not being dealt with correctly. I thought it was. However, I've updated to make sure that works (a bit cumbersome--but it appears to be right. Last fiddle: http://sqlfiddle.com/#!2/3f78d/45
I think #Grijesh conceptually got you the main thing you needed via the self-join of the input data (so make sure you vote up his answer!). I've cleaned up his query a bit on syntax (building off of his query!):
SELECT
DATE(t1.`Production_date`) as theDate,
MAX( t1.`bundle_count` ) AS 'max(bundle_count)',
MAX( t1.`bundle_count` ) -
IF(
EXISTS
(
SELECT date(t2.production_date)
FROM input_example t2
WHERE t2.machine_no = 1 AND
date_sub(date(t1.production_date), interval 1 day) = date(t2.production_date)
),
(
SELECT MAX(t3.bundle_count)
FROM input_example t3
WHERE t3.machine_no = 1 AND
date_sub(date(t1.production_date), interval 1 day) = date(t3.production_date)
GROUP BY DATE(t3.production_date)
), 0
)
AS Total_Bundles_Used
FROM `input_example` t1
WHERE t1.machine_no = 1
GROUP BY DATE( t1.`production_date` )
Note 1: I think #Grijesh and I were cleaning up the query syntax issues at the same time. It's encouraging that we ended up with very similar versions after we were both doing cleanup. My version differs in using IFNULL() for when there is no preceding data. I also ended up with a DATE_SUB, and I made sure to reduce various dates to mere dates without time component, via DATE()
Note 2: I originally had not fully understood your source tables, so I thought I needed to implement a running count in the query. But upon better inspection, it's clear that your source data already has a running count, so I took that stuff back out.
I am not sure but you need something like this, Hope it will be helpful to you upto some extend:
Try this:
SELECT t1.`Production_date` ,
MAX(t1.`bundle_count`) - MAX(t2.`bundle_count`) ,
COUNT(t1.`bundle_count`)
FROM `table_name` AS t1
INNER JOIN `table_name` AS t2
ON ABS(DATEDIFF(t1.`Production_date` , t2.`Production_date`)) = 1
GROUP BY t1.`Production_date`
EDIT
I create a table name = 'table_name', as below,
mysql> SELECT * FROM `table_name`;
+---------------------+--------------+
| Production_date | bundle_count |
+---------------------+--------------+
| 2004-12-01 20:37:22 | 1 |
| 2004-12-01 20:37:22 | 2 |
| 2004-12-01 20:37:22 | 3 |
| 2004-12-02 20:37:22 | 2 |
| 2004-12-02 20:37:22 | 5 |
| 2004-12-02 20:37:22 | 7 |
| 2004-12-03 20:37:22 | 6 |
| 2004-12-03 20:37:22 | 7 |
| 2004-12-03 20:37:22 | 2 |
| 2004-12-04 20:37:22 | 1 |
| 2004-12-04 20:37:22 | 9 |
+---------------------+--------------+
11 rows in set (0.00 sec)
My query: to find difference in bundle_count between two consecutive dates:
SELECT t1.`Production_date` ,
MAX(t2.`bundle_count`) - MAX(t1.`bundle_count`) ,
COUNT(t1.`bundle_count`)
FROM `table_name` AS t1
INNER JOIN `table_name` AS t2
ON ABS(DATEDIFF(t1.`Production_date` , t2.`Production_date`)) = 1
GROUP BY t1.Production_date;
its output:
+---------------------+-------------------------------------------------+--------------------------+
| Production_date | MAX(t2.`bundle_count`) - MAX(t1.`bundle_count`) | COUNT(t1.`bundle_count`) |
+---------------------+-------------------------------------------------+--------------------------+
| 2004-12-01 20:37:22 | 4 | 9 |
| 2004-12-02 20:37:22 | 0 | 18 |
| 2004-12-03 20:37:22 | 2 | 15 |
| 2004-12-04 20:37:22 | -2 | 6 |
+---------------------+-------------------------------------------------+--------------------------+
4 rows in set (0.00 sec)
This is PostgreSQL syntax (sorry; it's what I'm familiar with) but should fundamentally work in either database. Note this doesn't exactly run in PostgreSQL either because group is not a valid table name (it's a reserved keyword). The approach is a self-join as others have mentioned but I've used a view to handle the max-by-day and the difference as separate steps.
create view max_by_day as
select
date_trunc('day', production_date) as production_date,
max(bundle_count) as bundle_count
from
group
group by
date_trunc('day', production_date);
select
today.production_date as production_date,
today.bundle_count,
today.bundle_count - coalesce(yesterday.bundle_count, 0)
from
max_by_day as today
left join max_by_day yesterday on (yesterday.production_date = today.production_date - '1 day'::interval)
order by
production_date;
PostgreSQL also has a construct called window functions which is useful for this and a bit easier to understand. Just had to stick in a bit of advocacy for a superior database. :-P
select
date_trunc('day', production_date),
max(bundle_count),
max(bundle_count) - lag(max(bundle_count), 1, 0)
over
(order by date_trunc('day', production_date))
from
group
group by
date_trunc('day', production_date);
These two approaches differ in how they handle missing days in the data - the first will treat it as a 0, the second will use the previous day which is present. There wasn't a case like this in your sample so I don't know if this is something you care about.