Update with subquery in MySql - mysql

I've two tables:
work (work_id (AI, PK), sent_date, received_date, visit_date)
history_work(id_history_work (AI, PK), work_id (FK), sent_date, reseived_date, visit_date)
Relationship shoud be 1->n.
I want to update work table so sent_date, received_date and visit_date shoud have the values of last inserted record in history_work table (last id_history value) with same work_id value.

You can do this by using join. Join once to the history table. Join a second time to get the maximum id (which is presumably the most recent insertion).
update work w join
history h
on w.work_id = h.work_id join
(select work_id, max(id_history_work) as maxihw
from history
group by work_id
) hw
on hw.maxihw = h.id_work_history
set w.sent_date = h.sent_date,
w.received_date = h.received_date,
w.visit_date = h.visit_date;

Related

MySQL delete all but one record matching two column values [duplicate]

I am doing some data clean up and I would like to remove duplicate rows by finding records that have the same "picture id" and "date" values:
Example:
picture_id - 2 date - "13-Jul-18"
picture_id - 2 date - "13-Jul-18"
picture_id - 2 date - "13-Jul-18"
picture_id - 2 date - "13-Jul-18"
DELETE FROM `pictures` WHERE `picture_id` = '2' AND `date` = '13-Jul-18'
Table columns (in order): ID (primary key), picture_id, date, followers
I would like to only delete all but one of the duplicate records. It does not matter which one. How can I accomplish this?
In MySQL, you can keep the smallest (or biggest) id using JOIN:
DELETE p
FROM pictures p JOIN
(SELECT p.picture_id, p.date, MIN(id) as min_id
FROM pictures p
WHERE p.picture_id = 2 AND p.date = '2018-07-13'
GROUP BY p.picture_id
) pp
ON p.picture_id = pp.picture_id AND p.date = pp.date AND p.id > p.min_id;
Assuming you don't care which ID you keep you can select one record all delete all those records which are not the one selected
DELETE
FROM pictures
WHERE ID NOT IN (
SELECT
ID
FROM pictures
WHERE picture_id = 2 AND
Date = '2018-07-13'
LIMIT 1
) AND
picture_id = 2 AND
Date = '2018-07-13'
The fact these are unwanted duplicates makes me think either your current Primary Key is insufficient for your purposes or you need to look at a unique constraints
you can try something like
DROP TABLE IF EXISTS pictures;
CREATE TABLE pictures(picture_id INT(11), `dt` DATE, followers INT(11));
INSERT INTO pictures VALUES
(2,'2018-07-13',4553),
(2,'2018-07-13',4552),
(2,'2018-07-13',4557),
(2,'2018-07-13',4577),
(3,'2018-07-13',4355),
(3,'2018-07-13',4351),
(3,'2018-07-13',4353),
(3,'2018-07-13',4374);
Delete query
DELETE P FROM pictures p
LEFT JOIN (
SELECT picture_id, dt, MAX(followers) AS fol
FROM pictures WHERE dt ='2018-07-13' GROUP BY picture_id
) AS main
ON main.dt = p.dt
WHERE main.picture_id = p.picture_id
AND main.fol <> p.followers;
I hope this will solve you problem.
simply use common table
With CTE_Duplicates as
(select picture_id ,date , row_number() over(partition by picture_id,date order by picture_id ,date ) rownumber
from `pictures` )
delete from CTE_Duplicates where rownumber!=1
it work for me.please check

MySQL Delete duplicate rows that have same column value

I am doing some data clean up and I would like to remove duplicate rows by finding records that have the same "picture id" and "date" values:
Example:
picture_id - 2 date - "13-Jul-18"
picture_id - 2 date - "13-Jul-18"
picture_id - 2 date - "13-Jul-18"
picture_id - 2 date - "13-Jul-18"
DELETE FROM `pictures` WHERE `picture_id` = '2' AND `date` = '13-Jul-18'
Table columns (in order): ID (primary key), picture_id, date, followers
I would like to only delete all but one of the duplicate records. It does not matter which one. How can I accomplish this?
In MySQL, you can keep the smallest (or biggest) id using JOIN:
DELETE p
FROM pictures p JOIN
(SELECT p.picture_id, p.date, MIN(id) as min_id
FROM pictures p
WHERE p.picture_id = 2 AND p.date = '2018-07-13'
GROUP BY p.picture_id
) pp
ON p.picture_id = pp.picture_id AND p.date = pp.date AND p.id > p.min_id;
Assuming you don't care which ID you keep you can select one record all delete all those records which are not the one selected
DELETE
FROM pictures
WHERE ID NOT IN (
SELECT
ID
FROM pictures
WHERE picture_id = 2 AND
Date = '2018-07-13'
LIMIT 1
) AND
picture_id = 2 AND
Date = '2018-07-13'
The fact these are unwanted duplicates makes me think either your current Primary Key is insufficient for your purposes or you need to look at a unique constraints
you can try something like
DROP TABLE IF EXISTS pictures;
CREATE TABLE pictures(picture_id INT(11), `dt` DATE, followers INT(11));
INSERT INTO pictures VALUES
(2,'2018-07-13',4553),
(2,'2018-07-13',4552),
(2,'2018-07-13',4557),
(2,'2018-07-13',4577),
(3,'2018-07-13',4355),
(3,'2018-07-13',4351),
(3,'2018-07-13',4353),
(3,'2018-07-13',4374);
Delete query
DELETE P FROM pictures p
LEFT JOIN (
SELECT picture_id, dt, MAX(followers) AS fol
FROM pictures WHERE dt ='2018-07-13' GROUP BY picture_id
) AS main
ON main.dt = p.dt
WHERE main.picture_id = p.picture_id
AND main.fol <> p.followers;
I hope this will solve you problem.
simply use common table
With CTE_Duplicates as
(select picture_id ,date , row_number() over(partition by picture_id,date order by picture_id ,date ) rownumber
from `pictures` )
delete from CTE_Duplicates where rownumber!=1
it work for me.please check

SQL Statement Inner Join + Others...So join within a join?

I have the following SQL statement where I am adding game inventory and ordered inventory and then selecting the games that have that total inventory below the reorder point. The only problem is that I also want to select the game inventory below the reorder point that does not have any ordered inventory. I tried messing with the Having line where ItemIDs don't match, but no luck. Here is the current working code.
What I have:
SELECT tblGames.ItemID, tblGames.Title, ABS(tblGames.Inventory + Sum(tblSupplyOrders.Inventory)) AS UpdatedInventory
FROM tblGames
INNER JOIN tblSupplyOrders
ON tblGames.ItemID=tblSupplyOrders.ItemID
Group By tblGames.ItemID, tblGames.Title, tblGames.Inventory, tblGames.ReorderPoint
Having ABS(tblGames.Inventory + Sum(tblSupplyOrders.Inventory)) < tblGames.ReorderPoint
What I also want to display with it:
SELECT tblGames.ItemID, tblGames.Title, tblGames.Inventory
FROM tblGames
INNER JOIN tblSupplyOrders
ON tblGames.ItemID=tblSupplyOrders.ItemID
Group By tblGames.ItemID, tblGames.Title, tblGames.Inventory, tblGames.ReorderPoint
Having tblGames.Inventory < tblGames.ReorderPoint
...where there is no tblSupplyOrders.ItemID
Thanks in advance!
Update Requested
tblGames includes:
ItemID int, auto PK
Title varchar(100)
Inventory int,
ReorderPoint int
tblSupplyOrders includes:
SupplyOrder int, auto PK
ItemID int, FK to tblGames
Inventory int
So if:
tblGames/tblSupplyOrders.ItemID = The Same #
tblGames.Inventory = 2
tblSupplyOrders.Inventory = 3
tblGames.ReorderPoint = 6
Output will include this game.
The problem: It won't detect this game if there is no matching ItemID in tblSupplyOrders.
I think you are overcomplicating things:
SELECT tg.ItemID, tg.Title, tg.Inventory
FROM tblGames tg
LEFT JOIN (
select ItemID, sum(inventory) as Inventory
from tblSupplyOrders
group by ItemID) tso
ON tg.ItemID=tso.ItemID
where tg.Inventory+coalesce(tso.Inventory,0) < tg.ReorderPoint
This will left-join tblGames to a subquery of tblSupplyOrders that aggregates all orders for a particular item. This will return all rows from tblGames and matching rows of order aggregate from tblSupplyOrders, with nulls where there is no matching tso row.
The expression tg.Inventory+coalesce(tso.Inventory,0) calculates current inventory + pending orders; the coalesce is needed to deal with cases where there is no tso row, substituting zero instead of null for pending orders.

Mysql insert records from table A to table B. if table B.column is less than

**Employee**
PK empId
firstName
lastName
isRegularEmp
**Employee_Training**
PK FK empId
PK FK trainingId
logId
**Training**
PK TrainingId
date
specialEmployeesNeeded
regularEmployeesNeeded
FK roomId
I am trying to insert all the employees into the employee_training table by a specific date. It works except that I have a required amount not to surpass which is the SpecialEmployees/ Regular Employees field value.
For instance I have 200 Regular Employees and 100 Regular Employees in the Employee Table but I only need 35 Special Employees and 5 Reegular Employees to be inserted as specified in the training table.
I tried HAVING but it keeps throwing an error unknown column. Please help, I tried inserting one type of employee , but it still doesn't work
INSERT INTO EMPLOYEE_TRAINING(empId, trainingId)
SELECT E.empId , T.TrainingId
FROM EMPLOYEE E, TRAINING T
WHERE T.`date` = "2013-4-20"
AND E.isRegularEmp = false
HAVING COUNT(E.empId) <= regularEmployeesNeeded
I can't post my erd because I don't have enough points.
regularEmployees is not a column in any of your tables nor is it defined anywhere in your query. Try
INSERT INTO EMPLOYEE_TRAINING(empId, trainingId)
SELECT E.empId , T.TrainingId
FROM EMPLOYEE E, TRAINING T
WHERE T.`date` = "2013-4-20"
AND E.isRegularEmp = false
HAVING COUNT(E.empId) <= (select count(*) from EMPLOYEE where isRegularEmp=true )
The placement of your isRegularEmp condition is incorrect. It should be placed in the WHERE clause.
INSERT INTO EMPLOYEE_TRAINING(empId, trainingId)
SELECT E.empId , T.TrainingId
FROM EMPLOYEE E, TRAINING T
WHERE T.`date` = "2013-4-20"
AND E.isRegularEmp = false
HAVING COUNT(E.empId) <= regularEmployees
EDIT: As pointed out in Michael Benjamin's answer, regularEmployees is not a field is not defined. You need to SELECT the COUNT of regular employees.
INSERT INTO EMPLOYEE_TRAINING(empId, trainingId)
SELECT E.empId , T.TrainingId
FROM EMPLOYEE E, TRAINING T
WHERE T.`date` = "2013-4-20"
AND E.isRegularEmp = false
HAVING COUNT(E.empId) <= (SELECT COUNT(*) FROM EMPLOYEE WHERE isRegularEmp = true)

MySQL Querying database for time periods not already assigned

I have a rather complex-seeming query that will form the basis for an online classroom scheduling tool. My challenge is to develop a method to identify which classes a user is signed up for in the st_schedule table, then deduce from the overall table of classes, st_classes, which other classes are available that don't conflict with the user's current classes.
For example, if a user has an entry in st_schedule assigning them to a class from 8:00am to 9:00am, they would be ineligible for any class whose time fell between 8:00am and 9:00am. A class that ran 7:15am - 8:15am would make the user ineligible. I store the start times and end times of classes in the database separately for comparison purposes. It's important that this be as flexible as possible, so the concept of "blocking" times and assigning times to blocks is not a possibility.
Here are excerpts from the tables:
table st_classes (holds class information)
id
start_time
end_time
table st_schedule (holds schedule information)
id
user_id
class_id
I certainly could do this in a series of loops server-side, but I have to think that there's a MySQL method that can do this type of operation in one fell swoop.
You want to join the two tables together to represent the user's classes, and then find unregistered classes where the start time and end time do not fall between the start and end time of the user's classes.
Something like this. Completely off the cuff and untested:
SELECT
*
FROM
st_schedule s
INNER JOIN st_classes c ON c.id = s.class_id
INNER JOIN st_classes all_classes
ON all_classes.start_time NOT BETWEEN c.start_time AND c.end_time
AND all_classes.end_time NOT BETWEEN c.start_time AND c.end_time
WHERE
s.user_id = 1
Edit: Try #2
I only have a moment to look at this. I think I reversed the second join clauses. The all_classes alias represents the full list of classes, where the "c" alias represents the classes that the student is signed up for.
SELECT DISTINCT
all_classes.*
FROM
st_schedule s
INNER JOIN st_classes c ON c.id = s.class_id
INNER JOIN st_classes all_classes
ON c.start_time NOT BETWEEN all_classes.start_time AND all_classes.end_time
AND c.end_time NOT BETWEEN all_classes.start_time AND all_classes.end_time
WHERE
s.user_id = 1
This is using table variables in mssql but the sql selects should translate over to mysql
First the sample data
DECLARE #st_classes TABLE
(
ID INT NOT NULL,
Title VARCHAR(40) NOT NULL,
StartTime DATETIME NOT NULL,
EndTime DATETIME NOT NULL
)
DECLARE #st_schedule TABLE
(
ID INT NOT NULL,
UserID INT NOT NULL,
ClassID INT NOT NULL
)
INSERT INTO #st_classes (ID, Title, StartTime, EndTime)
SELECT 1,'Class1','08:00:00','09:30:00' UNION
SELECT 2,'Class2','09:30:00','11:30:00' UNION
SELECT 3,'Class3','11:30:00','16:00:00' UNION
SELECT 4,'Class4','16:00:00','17:30:00' UNION
SELECT 5,'Class5','09:00:00','11:45:00' UNION
SELECT 6,'Class6','07:00:00','18:00:00'
INSERT INTO #st_schedule(ID, UserID, ClassID)
SELECT 1,1,1 UNION
SELECT 2,1,2 UNION
SELECT 3,2,6
Next a bit of sql to confirm the tables join OK (selecting scheduled courses for user with an ID of 1) - Returns class 1 and 2
SELECT *
FROM #st_schedule AS S INNER JOIN
#st_classes AS C ON S.ClassID = C.ID
WHERE S.UserID = 1
Now we need to select all the ID of the courses where they overlap time wise with the users scheduled ones (including the scheduled ones) - Returns 1,2,5,6
SELECT AC.ID
FROM #st_classes AS AC
INNER JOIN ( SELECT C.StartTime,
C.EndTime
FROM #st_schedule AS S
INNER JOIN #st_classes AS C ON S.ClassID = C.ID
WHERE S.UserID = 1
) AS UC ON ( AC.StartTime < DATEADD(ss, -1, UC.EndTime)
AND DATEADD(ss, -1, UC.EndTime) > UC.StartTime
)
GROUP BY AC.ID
Now we need to select all courses where the Course ID is not in our list of overlapping course IDs. - Returns course 3 and 4
SELECT *
FROM #st_classes
WHERE ID NOT IN (
SELECT AC.ID
FROM #st_classes AS AC
INNER JOIN ( SELECT C.StartTime,
C.EndTime
FROM #st_schedule AS S
INNER JOIN #st_classes AS C ON S.ClassID = C.ID
WHERE S.UserID = 1
) AS UC ON ( AC.StartTime < DATEADD(ss, -1, UC.EndTime)
AND DATEADD(ss, -1, UC.EndTime) > UC.StartTime
)
GROUP BY AC.ID )
Change the user ID filter to 2 and you should not get any returned as the course assigned to that user overlaps all courses.