I'm currently in the process of converting data from one structure to another, and in the process I have to take a status id from the first entry in the group and apply it to the last entry in that same group. I am able to target and update the last item in the group just fine when using a hard-coded value, but I'm hitting a wall when trying to use the status_id from the first entry. Here is an example of the data structure.
-----------------------------------------------------------
| id | ticket_id | status_id | new_status_id | created_at |
-----------------------------------------------------------
| 1 | 10 | NULL | 3 | 2018-06-20 |
| 2 | 10 | 1 | 1 | 2018-06-22 |
| 3 | 10 | 1 | 1 | 2018-06-23 |
| 4 | 10 | 1 | 1 | 2018-06-26 |
-----------------------------------------------------------
So the idea would be to take the new_status_id of ID 1 and apply it to the same field for ID 4.
Here is the query that works when using a hard-coded value
UPDATE Communications_History as ch
JOIN
(
SELECT communication_id, MAX(created_at) max_time, new_status_id
FROM Communications_History
GROUP BY communication_id
) ch2
ON ch.communication_id = ch2.communication_id AND ch.created_at = ch2.max_time
SET ch.new_status_id = 3
But when I use the following query, I get Unknown column ch.communication_id in where clause
UPDATE Communications_History as ch
JOIN
(
SELECT communication_id, MAX(created_at) max_time, new_status_id
FROM Communications_History
GROUP BY communication_id
) ch2
ON ch.communication_id = ch2.communication_id AND ch.created_at = ch2.max_time
SET ch.new_status_id = (
SELECT nsi FROM
(
SELECT new_status_id FROM Communications_History WHERE communication_id = ch.communication_id AND status_id IS NULL
) as ch3
)
Thanks!
So I just figured it out using variables. It turns out the original "solution" only worked when there was one ticket's worth of history in the table, but when all the data was imported, it no longer worked. However, this tweak did seem to fix the issue.
UPDATE Communications_History as ch
JOIN
(
SELECT communication_id, MAX(created_at) max_time, new_status_id
FROM Communications_History
GROUP BY communication_id
) ch2
ON ch.communication_id = ch2.communication_id AND ch.created_at = ch2.max_time
SET ch.new_status_id = ch2.new_status_id;
Related
I'm trying to get records from the stats table and if there is no data for the specific day and reference get the latest known value for a given ref.
stats table:
| ref | date | views |
| --- | -------- | ----- |
| 1 |2022-01-01|1 |
| 2 |2022-01-01|1 |
| 1 |2022-01-02|2 |
| 2 |2022-01-02|1 |
| 1 |2022-01-03|2 |
| 1 |2022-01-04|3 |
| 2 |2022-01-04|3 |
As you see above there the record for ref 2 at 2022-01-03 is missing.
Now I want to sum views for those records and group them by the ref column and since there is one missing record for ref 2 the value for the summation should be taken from the latest record (2022-01-02).
I have also the posts table:
| id | title |
| --- | --------- |
| 1 |title no. 1|
| 2 |title no. 2|
Also, I have to create a timeline from the oldest stat to the current date.
What do I have is:
WITH RECURSIVE timeline (
date
) AS (
SELECT
MIN(date)
FROM
stats
UNION ALL
SELECT
DATE_ADD(date, INTERVAL 1 day)
FROM
timeline
WHERE (timeline.date < CURRENT_DATE),
posts_days AS (
SELECT timeline.date, posts.id
FROM
posts
CROSS JOIN timeline
),
view_stats AS (
SELECT posts_days.date, posts_days.id, stats.views
FROM
posts_days
LEFT JOIN stats ON (stats.ref = posts_days.id and stats.date = posts_days.date)
)
SELECT
view_stats.date, SUM(view_stats.views) AS views
-- ,SUM(prev_stats.views) AS prev_views,
FROM view_stats
LEFT JOIN (
SELECT id, (view_stats.views) as views, date FROM view_stats GROUP BY id, date
) as prev_stats on prev_stats.date = (
SELECT date FROM view_stats s1
WHERE s1.date < view_stats.date and s1.id = view_stats.id ORDER BY date desc limit 1
) and prev_stats.id = view_stats.id
GROUP BY date
ORDER BY date
But it obviously behaves in the wrong way.
I would be appreciated any tips on how to solve this one.
I have a MySQL DB and in it there's a table with activity logs of employees.
+-------------------------------------------------+
| log_id | employee_id | date_time | action_type |
+-------------------------------------------------+
| 1 | 1 | 2015/02/03 | action1 |
| 2 | 2 | 2015/02/01 | action1 |
| 3 | 2 | 2017/01/02 | action2 |
| 4 | 3 | 2016/02/12 | action1 |
| 5 | 1 | 2016/10/12 | action2 |
+-------------------------------------------------+
And I would need 2 queries. First, to get for every employee his last action. So from this example table I would need to get row 3,4 and 5 with all columns. And second, get the latest action only for specified employee.
Any ideas how to achieve this? I'm using Spring Data JPA, but raw SQL Query would be also great.
Thank you in advance.
Ready for a fred ed...
SELECT x.*
FROM my_table x
JOIN
( SELECT employee_id
, MAX(date_time) date_time
FROM my_table
GROUP
BY employee_id
) y
ON y.employee_id = x.employee_id
AND y.date_time = x.date_time;
For your first query. Simply
SELECT t1.*
FROM tableName t1
WHERE t1.log_id = (SELECT MAX(t2.log_id)
FROM tableName t2
WHERE t2.employee_id = t1.employee_id)
For the second one
SELECT t1.*
FROM tableName t1
WHERE t1.employee_id=X and t1.log_id = (SELECT MAX(t2.log_id)
FROM tableName t2
WHERE t2.employee_id = t1.employee_id);
You can get the expected output by doing a self join
select a.*
from demo a
left join demo b on a.employee_id = b.employee_id
and a.date_time < b.date_time
where b.employee_id is null
Note it may return multiple rows for single employee if there are rows with same date_time you might need a CASE statement and another attribute to decide which row should be picked to handle this kind of situation
Demo
I have a table that holds the answers to a question which is asked at entry to the system, at review periods and then at closure. The client can be opened and closed multiple times during their life on the system.
I am trying to get the latest 'entry' result from the table which also has either an associated 'review' or 'close' result.
This is my table (I have just included 1 user but the actual table has thousands of users):
row | user_id | answer | type | date_entered |
----+---------+--------+--------+--------------+
1 | 12 | 3 | entry | 2016-03-13 |
2 | 12 | 1 | review | 2016-03-14 |
3 | 12 | 7 | review | 2016-03-16 |
4 | 12 | 7 | close | 2016-03-17 |
5 | 12 | 8 | entry | 2016-03-20 |
6 | 12 | 2 | review | 2016-03-21 |
7 | 12 | 3 | close | 2016-03-22 |
8 | 12 | 1 | entry | 2016-03-28 |
So for this table the query would just return row 5 because the 'entry' on row 8 doesn't have any 'review' or 'closure' records after it.
Hopefully that makes sense.
SELECT a.*
FROM my_table a
JOIN
( SELECT x.user_id
, MAX(x.date_entered) date_entered
FROM my_table x
JOIN my_table y
ON y.user_id = x.user_id
AND y.date_entered > x.date_entered
AND y.type IN ('review','close')
WHERE x.type = 'entry'
GROUP
BY x.user_id
) b
ON b.user_id = a.user_id
AND b.date_entered = a.date_entered;
Basically you can seperate your query into two sub-queries. First query should get lastest record id (review and closure). Second query should have row_id > found_id.
SELECT *
FROM my_table
WHERE type = 'entry'
AND row_id > (SELECT Max(row_id)
FROM my_table
WHERE ( type = 'review'
OR type = 'close' ))
Please be careful about that; subquery may return zero-set.
I could think of several ways of doing it. But first a note: your date_entered field seems to be just a date. To tell which occurs "later" I'm going to use row because e.g. if both entry and review occurred on the same date, it's not possible to tell from the date_entered which one was later.
I just list a couple of solutions. The first one might be more efficient, but you should measure.
Here's a join against a subquery:
SELECT
m1.*
FROM
mytable m1
JOIN (SELECT
row, user_id
FROM
mytable
WHERE
type IN ('review', 'close') AND
user_id = 12
ORDER BY row DESC LIMIT 1) m2 ON m1.user_id = m2.user_id
WHERE
m1.user_id = 12 AND
m1.row < m2.row
ORDER BY
row DESC LIMIT 1
Here's a subquery for max:
SELECT
*
FROM
mytable
WHERE
row = (SELECT
MAX(m1.row)
FROM
mytable m1,
mytable m2
WHERE
m1.user_id = m2.user_id AND
m1.type = 'entry' AND
m2.type IN ('review', 'close') AND
m1.row < MAX(m2.row))
I have a table like this:
+----+---------+------------+
| id | conn_id | read_date |
+----+---------+------------+
| 1 | 1 | 2010-02-21 |
| 2 | 1 | 2011-02-21 |
| 3 | 2 | 2011-02-21 |
| 4 | 2 | 2013-02-21 |
| 5 | 2 | 2014-02-21 |
+----+---------+------------+
I want the second highest read_date for particular 'conn_id's i.e. I want a group by on conn_id. Please help me figure this out.
Here's a solution for a particular conn_id :
select max (read_date) from my_table
where conn_id=1
and read_date<(
select max (read_date) from my_table
where conn_id=1
)
If you want to get it for all conn_id using group by, do this:
select t.conn_id, (select max(i.read_date) from my_table i
where i.conn_id=t.conn_id and i.read_date<max(t.read_date))
from my_table t group by conn_id;
Following answer should work in MSSQL :
select id,conn_id,read_date from (
select *,ROW_NUMBER() over(Partition by conn_id order by read_date desc) as RN
from my_table
)
where RN =2
There is an intresting article on use of rank functions in MySQL here : ROW_NUMBER() in MySQL
If your table design as ID - date matching (ie a big id always a big date), you can group by id, otherwise do the following:
$sql_max = '(select conn_id, max(read_date) max_date from tab group by 1) as tab_max';
$sql_max2 = "(select tab.conn_id,max(tab.read_date) max_date2 from tab, $sql_max
where tab.conn_id = tab_max.conn_id and tab.read_date < tab_max.max_date
group by 1) as tab_max2";
$sql = "select tab.* from tab, $sql_max2
where tab.conn_id = tab_max2.conn_id and tab.read_date = tab_max2.max_date2";
I have this table:
person table
| id | name |
| 1 | person1 |
| 2 | person2 |
person_grade table
| id | person_id | grade | grade_date |
| 1 | 1 | grade1 | 2010-01-01 |
| 2 | 1 | grade2 | 2012-01-01 |
| 3 | 2 | grade3 | 2010-05-05 |
| 4 | 2 | grade4 | 2012-03-03 |
I want to know person grade at a specific time, say 2012-02-02. How to achieve this?
The closest I got was, with this query:
SELECT t1.id, t1.name,
(SELECT grade FROM (
(SELECT s1.grade, s1.grade_date FROM person_grade AS s1
WHERE s1.grade_date >= '2012-02-01' AND s1.person_id = t1.id
ORDER BY s1.grade_date LIMIT 1)
UNION ALL
(SELECT s1.grade, s1.grade_date FROM person_grade AS s1
WHERE s1.grade_date <= '2012-02-01' AND s1.person_id = t1.id
ORDER BY s1.grade_date DESC LIMIT 1)
) AS ss ORDER BY grade_date LIMIT 1) AS grade_person
FROM person AS t1
But at MySQL that give me an error
"Unknown column 't1.id' in 'where clause'".
Please advise.
TIA
SELECT name,grade FROM person p
INNER JOIN person_grade pg
ON p.id=pg.person_id
WHERE pg.grade_date='2012-02-02'
I dont know about the syntax about the MySql but u can do something like this
SELECT GRADE FROM person_grade WHERE DATE(GRADE_DATE,YEAR) = DATE(SEARCH_DATE,YEAR) AND DATE(GRADE_DATE,MONTH) = DATE(SEARCH_DATE,MONTH) AND DATE(GRADE_DATE,DAY) = DATE(SEARCH_DATE,DAY)
SELECT p.name
, pg.grade
FROM person p
INNER JOIN person_grade pg ON p.id = pg.person_id
WHERE DATE(pg.grade_date) = '2012-02-02'
If this works where #mhasan's answer did not, then it's most likely because of the data type of the grade_date table. If it's DATETIME, then it stores the time element of the date and that makes searching on that field bothersome.
If you don't need the time element, try changing the data type of the column to DATE. It should use less space and make searching easier.
EDIT: Wait, I just read that question again... you don't want records where the date MATCHES the query, you want something slightly trickier. Let me think on this one...
Thanks for the replay everyone, I think I found the solution, move subquery to WHERE clause and use MIN function at date diff. Here is the query :
SELECT p.id, p.name, pg.grade, pg.grade_date
FROM person AS p
LEFT JOIN person_grade AS pg ON p.id = pg.person_id
WHERE DATEDIFF ( '2012-02-02', pg.grade_date ) =
( SELECT MIN ( DATEDIFF ( '2012-02-02', spg.grade_date ) )
FROM person AS sp
LEFT JOIN person_grade AS spg ON sp.id = spg.person_id
WHERE DATEDIFF ( '2012-02-02', spg.grade_date ) > 0 AND sp.id = p.id )
Result:
| id | name | grade | grade_date |
| 1 | person1 | grade2 | 2012-01-01 |
| 2 | person2 | grade3 | 2010-05-05 |
Seems reference to outer table doesn't work under FROM clause, but work elsewhere (at least at MySQL).
Thanks for the hint from other question: Retrieve maximal / minimal record.