Update MySQL table with another table's data - mysql

I read this and this, but I need to make a GROUP BY query to set another table.
logintable is like this:
id | name | login_date
------------------------
1 | michael | 2013-01-04
2 | michael | 2013-01-08
3 | mary | 2013-01-11
4 | john | 2013-01-15
5 | michael | 2013-01-19
6 | mary | 2013-01-22
7 | john | 2013-01-26
I make a query like this:
SELECT * FROM logintable GROUP BY name ORDER BY id ASC
This gives me first login date of the users:
1 | michael | 2013-01-04
3 | mary | 2013-01-11
4 | john | 2013-01-15
I have another table called userstable like this:
id | name | last_seen_date | first_login_date
------------------------------------------------
1 | michael | 2013-02-02 |
2 | john | 2013-02-04 |
3 | mary | 2013-02-16 |
I need to update userstable's first_login_date column, with the first result. How can I do this ?
(I have 75k records in logintable and 10k records in userstable)

UPDATE userstable a
INNER JOIN
(
SELECT name, min(login_date) min_date
FROM logintable
GROUP BY name
) b ON a.name = b.Name
SET a.first_login_table = b.min_date
for faster performance, you need to add an INDEX on column Name for both tables. This will prevent from performing full table scan which is very slow in large databases.
Adding INDEX on table userstable:
ALTER TABLE usersTable ADD INDEX (Name);
for referential integrity, make table logintable dependent on table userstable by defining FOREIGN KEY constraint:
ALTER TABLE loginTable ADD CONSTRAINT tb_fk
FOREIGN KEY (Name) REFRENCES usersTable (Name)

UPDATE userstable AS u
INNER JOIN
(
SELECT MIN(login_date) AS MinLoginDate, Name
FROM logintable
GROUP BY name
) AS l ON u.name = l.name
SET u.first_login_date = l.MinLoginDate

I don't know MySql...but in SQL Server you would write something like this:
UPDATE userstable set first_login_date = (SELECT MIN(login_date) FROM logintable where name = userstable.name)

UPDATE userstable a
INNER JOIN
(
SELECT name, min(login_date) min_date
FROM logintable
GROUP BY name
) b ON a.name = b.Name
SET a.first_login_table = b.min_date
This will definitely show your output.

Related

Joining two SQL queries to filter duplicate records joining another table

I am a bit new to write complex SQL queries. There are two tables and we call them employee and status.
I need to filter duplicate records based on the key and status.
Key : |emplyee_dep_id|employee_reg_date|employee_rep_manager|
It is a composite key.
And there is a column in the Employee table called emp_status_id. In the Status table, there are two columns status_code and status_id.
Finally, I need to filter duplicate records based on the composite key with status "promoted" joining two tables.
I have written two queries but need to develop a single query. Could you help me to combine these two queries, please?
Sample data
|emplyee_dep_id|employee_reg_date|employee_rep_manager|status_id|email|
| 1 | 20-01-01 | Anne | 3 |a#a.com|
| 1 | 20-01-01 | Anne | 3 |u#a.com|
| 1 | 20-01-01 | Anne | 3 |y#a.com|
| 1 | 20-01-01 | Anne | 3 |h#a.com|
| 1 | 20-01-01 | Anne | 1 |b#a.com|
|Status_id|status_code|
| 3 | Promoted |
| 1 | Probation |
Query:
SELECT
emp.emplyee_dep_id, emp.employee_reg_date,
emp.employee_rep_manager, employee_status
FROM
employee emp
INNER JOIN
(SELECT
emplyee_dep_id, employee_reg_date, employee_rep_manager,
COUNT(*) AS CountOf
FROM
employee
GROUP BY
emplyee_dep_id, employee_reg_date, employee_rep_manager
HAVING
COUNT(*) > 1) emp1 ON emp.emplyee_dep_id = emp1.emplyee_dep_id
AND emp.employee_reg_date = emp1.employee_reg_date
AND emp.employee_rep_manager = emp1.employee_rep_manager
SELECT
employee_status
FROM
Employee
INNER JOIN
Status ON Employee.status_id = Status.status_id
WHERE
Status.status_code = 'promoted'
Instead of the Employee in the 2nd query, put the 1st query and join with status
SELECT e.*, s.status_code
from
(
SELECT emp.emplyee_dep_id,emp.employee_reg_date,emp.employee_rep_manager,employee_status as status_id
FROM employee emp
INNER JOIN (SELECT
emplyee_dep_id,employee_reg_date,employee_rep_manager, COUNT(*) AS CountOf
FROM employee
GROUP BY emplyee_dep_id,employee_reg_date,employee_rep_manager
HAVING COUNT(*)>1
) emp1
ON emp.emplyee_dep_id=emp1.emplyee_dep_id
AND emp.employee_reg_date=emp1.employee_reg_date
AND emp.employee_rep_manager = emp1.employee_rep_manager
) E
INNER JOIN Staus s
ON E.status_id = s.status_id
where s.status_code = 'promoted'
Group by emplyee_dep_id,employee_reg_date,employee_rep_manager;
And here is the fiddle

MySQL join two tables without NOT IN

Two tables users, relationships in my db.
CREATE TABLE users(
id int primary key auto_increment,
nickname varchar(20),
is_active TINYINT
)
CREATE TABLE relationships(
id int primary key auto_increment,
user_id int,
target_user_id int,
FOREIGN KEY(user_id) REFERENCES users(id),
FOREIGN KEY(target_user_id) REFERENCES users(id)
)
mysql> select * from users;
+----+----------+-----------+
| id | nickname | is_active |
+----+----------+-----------+
| 1 | hide | 1 |
| 2 | john | 1 |
| 3 | ben | 0 |
| 4 | test | 1 |
| 5 | gogo | 1 |
+----+----------+-----------+
mysql> select * from relationships;
+----+---------+----------------+
| id | user_id | target_user_id |
+----+---------+----------------+
| 1 | 1 | 2 |
| 2 | 1 | 4 |
+----+---------+----------------+
I have to extract users.id with certain condition.
I will explain in case of users.id = 1
users.is_active=1
user who does not have relationships via relationships table. you know that in current relationships table, user_id = 1 has 2 rows that target_user_id = 2 and 4. So query result does not contain user_id = 2 and 4.
Using NOT IN, it is pretty simple.
SELECT id FROM users WHERE is_active=1 AND id NOT IN(SELECT target_user_id FROM relationships WHERE user_id=1)
RESULT : 1, 5
Note that there is huge rows in users and relationships.
If I using NOT IN with subquery, it will occur performance issue.
So I think I have to join with foreign key but I don't know how to make query exactly.
Any suggestion, appreciate.
Thanks.
TRY THIS: I am sure LEFT JOIN with IS NULL approach will definitely work for you
SELECT u.id
FROM users u
LEFT JOIN relationships r ON r.target_user_id = u.id
AND r.user_id = 1
WHERE u.is_active=1 AND r.target_user_id IS NULL
Nothing wrong with your query. MySQL should be able to use your index.
However, you can also use left join:
SELECT
users.id
FROM
users
LEFT JOIN relationships ON (
users.id = relationships.target_user_id
/*
-- un-comment if filtering by user is needed
AND relationships.user_id = 1
*/
)
WHERE
users.is_active=1
AND relationships.target_user_id IS NULL
-- addition filtering can be here
UPDATE:
If you filtering by user, you can try to add composite index (user_id, target_user_id) to relationships table (columns should be in this order)

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

Multi join one to many

Trades
id |Trade_name |
1 | trade1 |
2 | trade2 |
3 | trade3 |
4 | trade4 |
Users
Name | Primary_id(FK to trade.id) | secondary_id (FK to trade.id) |
John | 1 | 2 |
Alex | 3 | 4 |
This is my current SQL which joins trades.t1 to primary & secondary.id:
select
`users`.`name` ,
`t1`.`trade_name` AS `Primary_trade`,
`t2`.`trade_name` AS `Secondary_trade`,
FROM `users`
right JOIN `trades` `t1` On (`t1`.`trade_id` = `users`.`primary_trade_id`)
right JOIN `trades` `t2` on (`t2`.`trade_id` = `users`.`secondary_trade_id`)
My question is, how do I identify which trades are not used for users both as primary or secondary. I want to see record where a trade does not exist in both primary or secondary column so I can perform housekeeping.
Thanking you all in advance for your help.
If you need only the trades rows
SELECT t.*
FROM trades t
WHERE NOT EXISTS ( SELECT 'u'
FROM Users u
WHERE u.Primary_id = t.id
OR u.Secondary_id = t.id
)
I think this should work for you:
SELECT * FROM trades WHERE id NOT IN (SELECT Primary_id FROM Users) AND id NOT IN (SELECT Secondary_id FROM Users)
It selects the rows which are not in either primary_id nor secondary_id

Select the fields are duplicated in mysql

Assuming that I have the below customer_offer table.
My question is:
How to select all the rows where the key(s) are duplicated in that table?
+---------+-------------+------------+----------+--------+---------------------+
| link_id | customer_id | partner_id | offer_id | key | date_updated |
+---------+-------------+------------+----------+--------+---------------------+
| 1 | 99 | 11 | 14 | mmmmmq | 2011-09-21 12:40:46 |
| 2 | 100 | 11 | 14 | qmmmmq | 2011-09-21 12:40:46 |
| 3 | 101 | 11 | 14 | 8mmmmq | 2011-09-21 12:40:46 |
| 4 | 99 | 11 | 14 | Dmmmmq | 2011-09-21 12:59:28 |
| 5 | 100 | 11 | 14 | Nmmmmq | 2011-09-21 12:59:28 |
+---------+-------------+------------+----------+--------+---------------------+
UPDATE:
Thanks so much for all your answer. There are many answers are good. Now I got the solution to do.
select *
from customer_offer
where key in
(select key from customer_offer group by key having count(*) > 1)
Update:
As mentioned from #Scorpi0, if with a big table, it is better to use join. And from mysql6.0 the new optimizer will convert this kind of subqueries into joins.
Self join
SELECT * FROM customer_offer c1 inner join customer_offer c2
on c1.key = c2.key
or group by the field then take when count > 1
SELECT COUNT(key),link_id FROM customer_offer c1
group by key, link_id
having COUNT(Key) > 1
SELECT DISTINCT c1.*
FROM customer_offer c1
INNER JOIN customer_offer c2
ON c1.key = c2.key
AND c1.link_id != c2.link_id
Assuming link_id is a primary key.
Use a sub-query to do the count check, and the main query to select the rows. The count check query is simply:
SELECT `link_id` FROM `customer_offer` GROUP BY `key` HAVING COUNT(`key`) > 1
Then the outer query will use this by joining into it:
SELECT customer_offer.* FROM customer_offer
INNER JOIN (SELECT `link_id` FROM `customer_offer` GROUP BY `key` HAVING COUNT(`key`) > 1) AS count_check
ON customer_offer.link_id = count_check.link_id
There are many threads on the mysql website which explains how to do this. This link will explain how to do this using mysql: http://forums.mysql.com/read.php?10,180556,180567#msg-180567
As a brief example the code below is from the link with a slight modification which better suits your example.
SELECT *
FROM tbl
GROUP BY key
HAVING COUNT(key)>1;
You can also use a joing which is my prefered method, as this removes the slower count method:
SELECT *
FROM this_table t
inner join this_table t1 on t.key = t1.key
SELECT link_id, key, count(key) as Occurrences
FROM table
GROUP BY key
HAVING COUNT(key)>1;