Update Statement Using Max Date and userid as the criteria - mysql

So I am trying to Update a contract table where the Contract Start Date is the latest date and the relevant employee id. The Contract Table stores all past information about the employee.
eg.
contract_tbl
+------------+------------+--------------------+-----------------+---------------+
|Contractid |EmployeeId |ContractStartDate |ContractEndDate | Position |
+------------+------------+--------------------+-----------------+---------------+
| 1 | 1 | 2012-12-13 | 2013-12-12 | Data Entry |
+------------+------------+--------------------+-----------------+---------------+
| 2 | 1 | 2014-01-26 | 2015-01-25 | Data Entry |
+------------+------------+--------------------+-----------------+---------------+
| 3 | 2 | 2014-01-26 | 2015-01-25 | Data Entry |
+------------+------------+--------------------+-----------------+---------------+
This is the SQL that I have but it does not work. (using a mysql db)
UPDATE contract_tbl
SET Position='Data Analyst'
WHERE EmployeeId = 1 And ContractStartDate= (
select max(ContractStartDate
FROM contract_tbl))
So it should Update the second row shown above with Data Analyst in the Position column but I am getting an error.
Does anybody have any idea how to fix this?
Thanks in advance

This will also do:
UPDATE contract_tbl a
JOIN (
SELECT MAX(ContractStartDate) m
FROM contract_tbl
WHERE EmployeeId = 1) b ON a.ContractStartDate = b.m AND a.EmployeeId = 1
SET a.Position='Data Analyst';

Probably this is what you want:
UPDATE contract_tbl c1
SET Position='Data Analyst'
WHERE EmployeeId = 1 And ContractStartDate= (
SELECT max(ContractStartDate)
FROM contract_tbl c2
WHERE c2.EmployeeId = c1.EmployeeId
)

Related

MySQL query based on results of another query

I have a table in MySQL which looks like this.
+---------+------------+--------------+
| user_id | key | value |
+---------+------------+--------------+
| 1 | full_name | John Smith |
+---------+------------+--------------+
| 1 | is_active | 1 |
+---------+------------+--------------+
| 1 | user_level |Administrator |
+---------+------------+--------------+
I need to get value of key full_name where user_id is 1, but only if value of key is_active is 1. I can do it with 2 separate queries, but I would like to know if it is possible to do it in a single query.
Note: I cannot change the structure of the table.
One method is to use joins:
select tn.value
from t tn join
t ta
on tn.user_id = ta.user_id and ta.key = 'active'
where tn.key = 'fullname';
i think you need below query by using exists
select t.value from your_table t where
exists ( select 1 from your_table t1
where t1.user_id=t.user_id
and t1.key='is_active'
) and t.key='full_name'
DEMO IN MYSQL 8
value
john smith

Update last row in group with data from first row in group

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;

Select only latest record for every employees and for specific employee in MySQL

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

Removing duplicates based on one column, and keeping the row that has value in different column, and if there isn't any, keep lowest ID row

Using MySQL 5.7 on Google Cloud, I'm trying to deduplicate MySQL data based on an "EmailAddress" column, but some of the rows have a value in the "FullName" column and some of them don't. I want to keep the ones that have a value in the FullName column, but if none of the rows with that EmailAddress value a FullName value, then just keep the duplicate with the lowest ID number (first column - primary key).
I've finally broken it down into two separate queries, one to first remove the rows with no value in the FullName column IF there's another duplicate row that does have a value in the FullName column:
DELETE
FROM customer_info
WHERE id IN
(
SELECT *
FROM
(
SELECT c1.id
FROM customer_info c1
INNER JOIN customer_info c2 on c1.EmailAddress=c2.EmailAddress and c1.id!=c2.id
WHERE
(trim(c1.FullName)='' or c1.FullName is NULL)
and c2.FullName is not NULL
and length(trim(c2.FullName))!=0
) t
)
and another query to remove the rows with the bigger IDs where no value was found in the FullName column:
DELETE
FROM customer_info
WHERE id IN
(
SELECT *
FROM
(
SELECT c1.id
FROM customer_info c1
INNER JOIN customer_info c2 on c1.EmailAddress=c2.EmailAddress and c1.id>c2.id
) t
)
This "works", but not really. It worked one time when I left it running overnight for a smaller segment of the data, and when I woke up there was an error, but I looked at the data and it was complete.
Am I missing something in my query that's making it highly inefficient, or is it just par for the course for this type of query, and there's no optimization possible in my code that would make a tangible improvement? I've maxed out a Google Cloud SQL instance to their db-n1-highmem-32 size, with 32 GB of memory and 1000 GB of storage space, and it still chokes up and spits out a 2013 error after running for an hour. I need to do this for a total of a little over 3 million rows.
For example, this:
id | FullName | EmailAddress |
----------------------------------------------
1 | John Doe | john.doe#email.com |
2 | null | janedoe#box.com |
3 | null | billybob#bobby.com |
4 | null | john.doe#email.com |
5 | John Lennon | jlennon#yoohoo.com |
6 | null | james.smith#coolmail.com|
7 | null | billybob#bobby.com |
8 | Jane Doe | janedoe#box.com |
would result in this:
id | FullName | EmailAddress |
----------------------------------------------
1 | John Doe | john.doe#email.com |
3 | null | billybob#bobby.com |
5 | John Lennon | jlennon#yoohoo.com |
6 | null | james.smith#coolmail.com|
8 | Jane Doe | janedoe#box.com |
using exists() might be simpler in this situation
delete
from customer_info c
where (trim(c.FullName)='' or c.FullName is null)
and exists (
select 1
from customer_info i
where i.Email = c.EmailAddress
and trim(i.FullName)>''
)
delete
from customer_info c
where exists (
select 1
from customer_info i
where i.Email = c.EmailAddress
and i.id < c.id
)

MySQL - Combine SELECT and UPDATE?

I would like MySQL to compare the values of 2 columns in a table. If both values are the same, an UPDATE-statement must be executed on another table. These are my 2 tables:
TABLE: EMPLOYEES
EMPLOYEE_ID | NAME | CREDIT
---------------------------
1 | John | 5
2 | Bill | 10
3 | Mark | 7
TABLE: BONUSES
BONUS_ID | EMPLOYEE_ID | A | B | AMOUNT
---------------------------------------
1 | 1 | x | x | 6
2 | 2 | x | y | 19
3 | 2 | y | x | 4
4 | 3 | y | y | 12
5 | 3 | x | x | 15
If in the bonuses-table the value of column A is equal to the value of column B, the "amount" value of that row must be added to the employees credit in the employees-table. In SQL, it would be something like this:
SELECT * FROM bonuses WHERE A = B;
..and after that:
UPDATE employees SET credit = credit + bonuses.amount
-> For example:
In the "bonuses" table, the first row value A is euqal to value B. That means that the employee with EMPLOYEE_ID 1 (John) must have added 6 to their credit. The same goes for the 4th row where value A is equal to value B. In that case, the employee with EMPLOYEE_ID 3 (Mark) must have added 12 to their credit.
Does anyone know how to do this? Thanks!
You can use a multiple-table update to join the tables:
UPDATE EMPLOYEES JOIN BONUSES USING (EMPLOYEE_ID)
SET EMPLOYEES.CREDIT = EMPLOYEES.CREDIT + BONUSES.AMOUNT
WHERE BONUSES.A = BONUSES.B
However, you may wish to consider whether this logic would be better implemented in a trigger:
CREATE TRIGGER foo AFTER INSERT ON BONUSES FOR EACH ROW
IF NEW.A = NEW.B THEN
UPDATE EMPLOYEES
SET CREDIT = CREDIT + NEW.AMOUNT
WHERE EMPLOYEE_ID = NEW.EMPLOYEE_ID
END IF
;
Try this query
update EMPLOYEE E
inner join BONUSES B on
E.EMPLOYEE_ID = B.EMPLOYEE_ID AND B.A = B.B
set E.CREDIT = E.CREDIT + B.AMOUNT;