MySQL Update current record in table - mysql

I've been trying to come up with an elegant way to do the following, let's say I have the following table:
+-----+---------+------------+--------------+------------+------------+--------+
| ID | EmpNum | Name | Title | StartDate | UpdateDate | IsCurr |
+-----+---------+------------+--------------+------------+------------+--------+
| 1 | 0000001 | John Smith | Engineer | 01/01/2017 | 01/02/2017 | N |
| 2 | 0000001 | John Smith | Sr. Engineer | 01/01/2017 | NULL | Y |
+-----+---------+------------+--------------+------------+------------+--------+
When the Title of the employee changes, I want to update the UpdateDate of the current employee record and change IsCurr to N, then insert the new record which will be the current one. For example if employee John Smith got promoted to Team Lead on 01/03/2017, then the resulting table would like this.
+-----+---------+------------+--------------+------------+------------+----
----+
| ID | EmpNum | Name | Title | StartDate | UpdateDate | IsCurr |
+-----+---------+------------+--------------+------------+------------+--------+
| 1 | 0000001 | John Smith | Engineer | 01/01/2017 | 01/02/2017 | N |
| 2 | 0000001 | John Smith | Sr. Engineer | 01/01/2017 | 01/03/2017 | N |
| 3 | 0000001 | John Smith | Team Lead | 01/01/2017 | NULL | Y |
+-----+---------+------------+--------------+------------+------------+--------+
From what I can tell MySQL does not have a MERGE function so I would need to this in 2 separate commands. As in UPDATE the most recent record and then insert the new row.
Is there a better way to do this in MySQL?
Thanks in advance.

You could try to arrange your desired query with INSERT INTO ... ON DUPLICATE KEY. But you need ID to be an index.
It is available since MySQL version 5.5.
INSERT INTO table (ID, EmpNum, Name, Title, StartDate, UpdateDate, IsCurr)
VALUES
(3, '0000001', 'John Smith', 'Team Lead', '01/01/2017', NULL, 'Y'),
(2, '0000001', 'John Smith', 'Sr. Engineer', '01/01/2017', '01/03/2017', 'N')
ON DUPLICATE KEY UPDATE isCurr='N', UpdateDate='01/03/2017';

Related

Retaining earliest instances of duplicate entries from a table [duplicate]

This question already has answers here:
SQL select only rows with max value on a column [duplicate]
(27 answers)
Closed 2 years ago.
We have a situation where duplicate entries have crept into our table with more than 60 million entries (duplicate here implies that all fields, except the AUTO_INCREMENT index field have the same value). We suspect that there are about 2 million duplicate entries in the table. We would like to delete these duplicate entries such that the earliest instances of the duplicate entries are retained.
Let me explain with an illustrative table:
CREATE TABLE people
(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(40) NOT NULL DEFAULT '',
age INT NOT NULL DEFAULT 0,
phrase VARCHAR(40) NOT NULL DEFAULT '',
PRIMARY KEY (id)
);
INSERT INTO people(name, age, phrase) VALUES ('John Doe', 25, 'qwert'), ('William Smith', 19, 'yuiop'),
('Peter Jones', 19, 'yuiop'), ('Ronnie Arbuckle', 32, 'asdfg'), ('Ronnie Arbuckle', 32, 'asdfg'),
('Mary Evans', 18, 'hjklp'), ('Mary Evans', 18, 'hjklpd'), ('John Doe', 25, 'qwert');
SELECT * FROM people;
+----+-----------------+-----+--------+
| id | name | age | phrase |
+----+-----------------+-----+--------+
| 1 | John Doe | 25 | qwert |
| 2 | William Smith | 19 | yuiop |
| 3 | Peter Jones | 19 | yuiop |
| 4 | Ronnie Arbuckle | 32 | asdfg |
| 5 | Ronnie Arbuckle | 32 | asdfg |
| 6 | Mary Evans | 18 | hjklp |
| 7 | Mary Evans | 18 | hjklpd |
| 8 | John Doe | 25 | qwert |
+----+-----------------+-----+--------+
We would like to remove duplicate entries so that we get the following output:
SELECT * FROM people;
+----+-----------------+-----+--------+
| id | name | age | phrase |
+----+-----------------+-----+--------+
| 1 | John Doe | 25 | qwert |
| 2 | William Smith | 19 | yuiop |
| 3 | Peter Jones | 19 | yuiop |
| 4 | Ronnie Arbuckle | 32 | asdfg |
| 6 | Mary Evans | 18 | hjklp |
| 7 | Mary Evans | 18 | hjklpd |
+----+-----------------+-----+--------+
On smaller sized tables the following approach would work:
CREATE TABLE people_uniq LIKE people;
INSERT INTO people_uniq SELECT * FROM people GROUP BY name, age, phrase;
DROP TABLE people;
RENAME TABLE people_uniq TO people;
SELECT * FROM people;
+----+-----------------+-----+--------+
| id | name | age | phrase |
+----+-----------------+-----+--------+
| 1 | John Doe | 25 | qwert |
| 2 | William Smith | 19 | yuiop |
| 3 | Peter Jones | 19 | yuiop |
| 4 | Ronnie Arbuckle | 32 | asdfg |
| 6 | Mary Evans | 18 | hjklp |
| 7 | Mary Evans | 18 | hjklpd |
+----+-----------------+-----+--------+
Kindly suggest a solution that would scale to a table with tens of millions of entries and many more columns. We are using MySQL version 5.6.49.
why not deleting duplicates?
DELETE FROM people
where id in (
SELECT MAX(id)
FROM people
GROUP BY name, age, phrase
HAVING count(*) > 1
)
if it still takes too much time , you can do it in batch

Mysql - joining labels and values table and including not referenced labels as null

The following problem has been bugging me for some time now. I have two tables in my database.
First I have a table holding labels, referenced values.
| option_id | option_name |
|-----------|-------------|
| 1 | Blue |
| 2 | Red |
| 3 | Black |
Then I have the second table with the actual values
| record_id | option_id | first_name | profession |
|-----------|-----------|------------|------------|
| 1 | 2 | James | Clerk |
| 2 | 2 | Ethan | Clerk |
| 3 | 1 | Marian | Nurse |
| 4 | 3 | Bob | Nurse |
| 5 | 3 | Paul | Nurse |
How can I join these two tables in MySQL so I get all the options listed for each of the professions even when there is no reference value so it will show up as NULL?
So the table would look something like:
| profession | option_name | first_name |
|------------|-------------|------------|
| Clerk | Blue | NULL |
| Clerk | Red | James |
| Clerk | Red | Ethan |
| Clerk | Black | NULL |
| Nurse | Blue | Marian |
| Nurse | Red | NULL |
| Nurse | Black | Bob |
| Nurse | Black | Paul |
Any help would be appreciated. Here is the sample database
CREATE TABLE options (
option_id INT,
option_name TEXT
);
INSERT INTO options VALUES (1, 'Blue');
INSERT INTO options VALUES (2, 'Red');
INSERT INTO options VALUES (3, 'Black');
CREATE TABLE records (
record_id INT,
option_id INT,
first_name TEXT,
profession TEXT
);
INSERT INTO records VALUES (1, 2, 'James','Clerk');
INSERT INTO records VALUES (2, 2, 'Ethen','Clerk');
INSERT INTO records VALUES (3, 1, 'Marian','Nurse');
INSERT INTO records VALUES (4, 3, 'Bob', 'Nurse');
INSERT INTO records VALUES (5, 3, 'Paul', 'Nurse');
You can enumerate the professions from the records table, cross join table options to generate all possible combinations, then bring the records table with a left join:
select p.profession, o.option_name, r.first_name
from (select distinct profession from records) p
cross join options o
left join records r
on r.option_id = o.option_id
and r.profession = p.profession
order by p.profession, o.option_name

How do I sort a master table based on metadata in a separate table in MySQL 5.5.x?

I'm hoping to get some advise on an SQL problem...
We have a master table (MySQL 5.5.x) that contains very little information. We we also have a metadata table that stores variable/value pairs and references the master table. The issue I'm having is that we need to retrieve the information using a JOIN to combine both tables, but we need to sort the output based on a particular meta-datum. The following trivial example will illustrate.
Here's a super-distilled version of the schema:
CREATE TABLE fundraise (
id INTEGER NOT NULL,
charity TEXT NOT NULL,
PRIMARY KEY(id)
);
CREATE TABLE meta (
master_id INTEGER REFERENCES fundraise(id),
variable TEXT NOT NULL,
value TEXT NOT NULL
);
We then enter some information for all three charities:
INSERT INTO fundraise(id, charity) VALUES
(1, 'save the dolphins'),
(2, 'feed the kids'),
(3, 'cloth the homeless');
We also insert some metadata:
INSERT INTO meta(master_id, variable, value) VALUES
(1, 'name', 'Mike'), (1, 'priority', 'high'), (1, 'start','2016'),
(2, 'name', 'Barb'), (2, 'priority', 'veryhigh'), (2, 'start','2012'),
(3, 'name', 'Sam'), (3, 'priority', 'veryhigh'), (3, 'start','2013');
Note that the metadata variable 'start' is intended to be used as the sort order of the required report. Here's the SQL statement I'm using to generate the report (unsorted):
SELECT f.charity, m.variable, m.value
FROM fundraise f
LEFT OUTER JOIN meta m ON (f.id = m.master_id);
The output I'm getting seems correct, for the most part, except that we haven't sorted yet:
+--------------------+----------+----------+
| charity | variable | value |
+--------------------+----------+----------+
| save the dolphins | name | Mike |
| save the dolphins | priority | high |
| save the dolphins | start | 2016 |
| feed the kids | name | Barb |
| feed the kids | priority | veryhigh |
| feed the kids | start | 2012 |
| cloth the homeless | name | Sam |
| cloth the homeless | priority | veryhigh |
| cloth the homeless | start | 2013 |
+--------------------+----------+----------+
But what I really need is for it to display sorted on the "start" year, while keeping all the details about a particular charity together. In other words, I need to see the report order by year, like this:
+--------------------+----------+----------+
| charity | variable | value |
+--------------------+----------+----------+
| feed the kids | name | Barb |
| feed the kids | priority | veryhigh |
| feed the kids | start | 2012 |
| cloth the homeless | name | Sam |
| cloth the homeless | priority | veryhigh |
| cloth the homeless | start | 2013 |
| save the dolphins | name | Mike |
| save the dolphins | priority | high |
| save the dolphins | start | 2016 |
+--------------------+----------+----------+
But I'm at a loss as to how to do this... Anyone has any suggestions on how to do this using SQL, exclusively?!?!
May thanks in advance!
p.s., I'd like to point out that the actual system I'm using is much much more complex, and the above is a rather contrived demo to simplify the asking of the question.
Try this.
SELECT * FROM (SELECT f.id AS id,f.charity, m.variable, m.value FROM fundraise f RIGHT OUTER JOIN meta m ON (f.id = m.master_id) GROUP BY value HAVING (variable = 'start') ORDER BY value) as sorted_table LEFT JOIN meta m2 ON sorted_table.id = m2.master_id ORDER BY sorted_table.value
This is my result using that query.
MariaDB [fbb]> SELECT * FROM (SELECT f.id AS id,f.charity, m.variable, m.value FROM fundraise f RIGHT OUTER JOIN meta m ON (f.id = m.master_id) GROUP BY value HAVING (variable = 'start') ORDER BY value) as sorted_table LEFT JOIN meta m2 ON sorted_table.id = m2.master_id ORDER BY sorted_table.value
-> ;
+------+--------------------+----------+-------+-----------+----------+----------+
| id | charity | variable | value | master_id | variable | value |
+------+--------------------+----------+-------+-----------+----------+----------+
| 2 | feed the kids | start | 2012 | 2 | name | Barb |
| 2 | feed the kids | start | 2012 | 2 | priority | veryhigh |
| 2 | feed the kids | start | 2012 | 2 | start | 2012 |
| 3 | cloth the homeless | start | 2013 | 3 | name | Sam |
| 3 | cloth the homeless | start | 2013 | 3 | priority | veryhigh |
| 3 | cloth the homeless | start | 2013 | 3 | start | 2013 |
| 1 | save the dolphins | start | 2016 | 1 | name | Mike |
| 1 | save the dolphins | start | 2016 | 1 | priority | high |
| 1 | save the dolphins | start | 2016 | 1 | start | 2016 |
+------+--------------------+----------+-------+-----------+----------+----------+
9 rows in set (0.01 sec)
MariaDB [fbb]>

How to sort the records based on month(June to May) in mysql?

I want to display the records starting june month to may using mysql.
My table is
id | subjects | from | to |
______|____________|________________|__________________|
1 | php | 2013-01-01 | 2013-01-21 |
2 | C | 2013-12-01 | 2013-12-21 |
3 | C++ | 2013-04-01 | 2013-04-21 |
4 | C# | 2013-06-01 | 2013-06-21 |
5 | Mysql | 2013-09-01 | 2013-09-21 |
Result like
id | subjects | from | to |
______|____________|________________|__________________|
1 | C# | 2013-06-01 | 2013-06-21 |
2 | Mysql | 2013-09-01 | 2013-09-21 |
3 | C | 2013-12-01 | 2013-12-21 |
4 | php | 2013-01-01 | 2013-01-21 |
5 | C++ | 2013-04-01 | 2013-04-21 |
I am giving code in SQL Server you can do same in MySQL.
CREATE TABLE Author (
BookID INT IDENTITY,
AuthID INT,
DAT DATETIME
)
GO
INSERT INTO Author VALUES(2, GETDATE())
INSERT INTO Author VALUES(2, GETDATE()-60)
INSERT INTO Author VALUES(2, GETDATE()-180)
INSERT INTO Author VALUES(2, GETDATE()-30)
INSERT INTO Author VALUES(2, GETDATE()-70)
INSERT INTO Author VALUES(2, GETDATE()-270)
INSERT INTO Author VALUES(2, GETDATE()-360)
SELECT datename(month, DAT) AS MonthName,
Month(DAT) AS MonthNum,
CASE WHEN Month(DAT)-6 >0
THEN Month(DAT)-6
ELSE Month(DAT)+6
END AS ReqOrder,
*
FROM Author
ORDER BY 3
DROP TABLE Author
Let me know your comments/results.

MySQL: Selecting data based on values from multiple rows

I am trying to write a SQL statement that selects data out of a table where an individual has multiple values in the same column. For example, based on the table below: I need a query to select all of the rows for all of the individuals who have both a bat and a baseball in the “Toy” column.
------------------------
| ID | Name | Toy |
------------------------
| 1 | Jack | Bat |
| 2 | Jim | Baseball |
| 3 | Jack | Baseball |
| 4 | John | Bat |
| 5 | Jim | Football |
| 6 | Jack | Glove |
------------------------
I would like the results to be something like:
-------------------
| Name | Toy |
-------------------
| Jack | Bat |
| Jack | Baseball |
-------------------
I hope this makes sense. Thanks.
select distinct t.name, t.toy
from your_table t
where name in
(
select name
from your_table
where toy in ('bat','baseball')
group by name
having count(distinct toy) = 2
)
and toy in ('bat','baseball')
If you just need the name you can do
select name
from your_table
where toy in ('bat','baseball')
group by name
having count(distinct toy) = 2
SQLFiddle demo