I have two table named "user" and "logs".
user table has column named "userID" which is also pk.
logs table has two columns named "log_detail" and "userID".
What I want to query is "get all user.userID values one by one from user table and check them if log_detail value contains this value, If it countains then update logs.userID with this userID value".
I tried some queries but I really don't know how to do it.
By the way I am using Mysql.
UPDATE logs
SET logs.userID = user.userID
SELECT userID
FROM logs
WHERE logs.userID LIKE concat("%",user.userID,"%");
SQL Fiddle
Schema details
create table user
(userid varchar(30));
create table logs
(log_detail varchar(100),
userid varchar(30));
insert into user values('user1');
insert into user values('user2');
insert into user values('user3');
insert into logs values('update by user1','user3');
insert into logs values('inserted by user2','user2');
insert into logs values('inserted by user3',null);
Table data before update
| log_detail | userid |
|-------------------|--------|
| update by user1 | user3 |
| inserted by user2 | user2 |
| inserted by user3 | (null) |
Update Query
update logs join user
set logs.userid=user.userid
where logs.log_detail LIKE concat("%",user.userID,"%");
Table data after update
| log_detail | userid |
|-------------------|--------|
| update by user1 | user1 |
| inserted by user2 | user2 |
| inserted by user3 | user3 |
update logs
inner join 'user' on
logs.userID = user.userID
set logs.userID = user.userID
WHERE logs.log_detail LIKE concat("%",user.userID,"%");
Also take into account that user is a reserved keyword in mysql
I am not very much familiar with MYSQL but in oracle we can satisfy your requirements like this
CREATE TABLE USERS
( USERID VARCHAR2(100 CHAR) PRIMARY KEY
);
INSERT INTO USERS
(SELECT 'AVROY'||LEVEL FROM DUAL CONNECT BY LEVEL < 10
);
COMMIT;
CREATE TABLE logs_UID
(
log_dtl VARCHAR2(200 CHAR),
UserID VARCHAR2(100 CHAR)
);
INSERT INTO logs_UID
SELECT 'test avroy'||level,NULL FROM dual CONNECT BY level < 10 ;
COMMIT;
MERGE INTO LOGS_UID lu USING USERS u
ON (UPPER(u.userid) = UPPER(SUBSTR(LU.LOG_DTL,INSTR(UPPER(lu.LOG_DTL),UPPER(u.userid),1),LENGTH(lu.log_dtl)-INSTR(UPPER(lu.LOG_DTL),UPPER(u.userid),1)+1)))
WHEN MATCHED THEN
UPDATE SET lu.USERID = u.USERID;
COMMIT;
Try with the following query.I think you will get what you need.
update logs l
join users u
on l.log_detail = u.userid
set l.userid = u.userid
I think we no need to write where condition again,because we are using inner join in the query.
Thank you.
Related
I want to update records in table Users that are not present in table UserActions (see sqlfiddle demo or sql and data at gist.github)
My tables
Table Users
ID | UserName | isActive
1 | Ben Busy | 1
2 | Lui Lazy | 1 <-- never logged in
3 | Emmy Eager | 1
4 | Lana Later | 1 <-- never logged in
Table UserActions
ID | User_ID | Type | ActionDate
1 | 1 | Login | 2021-01-01 <-- Joe
2 | 3 | Login | 2021-01-02 <-- Eda
3 | 1 | Login | 2021-01-02 <-- Joe
4 | 1 | Login | 2021-01-03 <-- Joe
I want to set isActive = 0 for all Users that never logged in.
This query returns the userIDs that never logged in:
SELECT ID FROM Users u LEFT JOIN UserActions ua
ON u.ID = ua.User_ID
AND (ua.Type = "Login" OR ua.Type = NULL)
WHERE ua.ActionDate IS NULL
I was not able to use this question or this question so i thought that using a varible SET #userIDs := (....) should work as well
SET #userIDs := (
SELECT GROUP_CONCAT(ID SEPARATOR ', ') FROM Users u LEFT JOIN UserActions ua
ON u.ID = ua.User_ID
AND (ua.Type = "Login" OR ua.Type = NULL)
WHERE ua.ActionDate IS NULL);
The varible #userIDs contains all the relevant user-ids that never logged in (2,4).
But this statement
SELECT * FROM Users where ID in (#userIDs);
only returns the first result.
Questions
Why does where ID in #myVar not work?
Is there a way besides using a temporary table?
Code and Data
sql and data at gist
sqlfiddle demo
Perhaps you can just use NOT EXISTS:
UPDATE Users u
SET u.IsActive=0
WHERE NOT EXISTS
(SELECT user_id FROM UserActions ua
WHERE (ua.Type = "Login" OR ua.Type = NULL) AND u.ID=ua.user_id);
Demo fiddle
Update 3rd party edit
If you want to use a variable you can do it with find_in_set
SET #userIDs := (
SELECT GROUP_CONCAT(u.ID SEPARATOR ',') FROM Users u
LEFT JOIN UserActions ua
ON u.ID = ua.User_ID
AND (ua.Type = "Login" OR ua.Type = NULL)
WHERE ua.ActionDate IS NULL);
And then
SELECT * FROM Users WHERE FIND_IN_SET(Users.ID, #userIDs);
See this dbfiddle
I have a database with two tables one table (shops) has an admin user column and the other a user with less privileges. I plan to LEFT JOIN the table of the user with less privileges. When I retrieve the data, the records for the admin user must be on a separate row and must have NULL values for the left joined table followed by records of users with less privileges (records of the left joined table) if any. I am using MySQL.
I have looked into the UNION commands but I don't think it can help. Please see the results bellow of what I need.
Thank you.
SELECT *
FROM shops LEFT JOIN users USING(shop_id)
WHERE shop_id = 1 AND (admin_id = 1 OR user_id = 1);
+---------+----------+---------+
| shop_id | admin_id | user_id |
+---------+----------+---------+
| 1 | 1 | NULL | <-- Need this one extra record
| 1 | 1 | 1 |
| 1 | 1 | 2 |
| 1 | 1 | 3 |
+---------+----------+---------+
Here is an example structure of the databases and some sample data:
CREATE SCHEMA test DEFAULT CHARACTER SET utf8 ;
USE test;
CREATE TABLE admin(
admin_id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(admin_id)
);
CREATE TABLE shops(
shop_id INT NOT NULL AUTO_INCREMENT,
admin_id INT NOT NULL,
PRIMARY KEY(shop_id),
CONSTRAINT fk_shop_admin FOREIGN KEY(admin_id) REFERENCES admin (admin_id)
);
CREATE TABLE users(
user_id INT NOT NULL AUTO_INCREMENT,
shop_id INT NOT NULL,
CONSTRAINT fk_user_shop FOREIGN KEY(shop_id) REFERENCES admin (shop_id)
);
-- Sample data
INSERT INTO admin() VALUES ();
INSERT INTO shops(admin_id) VALUES (1);
INSERT INTO users(shop_id) VALUES (1),(1),(1);
I think you need union all:
select s.shop_id, s.admin_id, null as user_id
from shops s
where s.shop_id = 1
union all
select s.shop_id, s.admin_id, u.user_id
from shops s join
users u
on s.shop_id = u.shop_id
where shop_id = 1;
Put your where condition in On clause
SELECT *
FROM shops LEFT JOIN users on shops.shop_id=users.shop_id and (admin_id = 1 OR user_id = 1)
WHERE shops.shop_id = 1
I have table users AND orders. After every UPDATE row in orders. I want update DATA in users table namely concat(OLD.DATA + ID which was updated).
Table 'users'.
ID NAME DATA
1 John 1|2
2 Michael 3|4
3 Someone 5
Table 'orders'.
ID USER CONTENT
1 1 ---
2 1 ---
3 2 ---
4 2 ---
5 3 ---
For example:
SELECT `data` from `users` where `id` = 2; // Result: 3|4
UPDATE `orders` SET '...' WHERE `id` > 0;
**NEXT LOOP**
UPDATE `users` SET `data` = concat(OLD.data, ID.rowUpdated) WHERE `user` = 1;
UPDATE `users` SET `data` = concat(OLD.data, ID.rowUpdated) WHERE `user` = 1;
UPDATE `users` SET `data` = concat(OLD.data, ID.rowUpdated) WHERE `user` = 2;
UPDATE `users` SET `data` = concat(OLD.data, ID.rowUpdated) WHERE `user` = 2;
UPDATE `users` SET `data` = concat(OLD.data, ID.rowUpdated) WHERE `user` = 3;
Result:
SELECT data from users where id = 1; // Result: 1|2|1|2
SELECT data from users where id = 2; // Result: 3|4|3|4
SELECT data from users where id = 3; // Result: 5|5
How can I do it?
I think you are making the same mistake I made not too long ago, ie storing an array/object in a column.
I would recommend using the following tables in your scenario:
users
+-----------+-----------+
| id | user_name |
+-----------+-----------+
| 1 | John |
+-----------+-----------+
| 2 | Michael |
+-----------+-----------+
orders
+-----------+-----------+------------+
| id | user_id |date_ordered|
+-----------+-----------+------------+
| 1 | 1 | 2019-03-05 |
+-----------+-----------+------------+
| 2 | 2 | 2019-03-05 |
+-----------+-----------+------------+
Where user_id is the foreign key to users
sales
+-----------+-----------+------------+------------+------------+
| id | order_id | item_sku | qty | price |
+-----------+-----------+------------+------------+------------+
| 1 | 1 | 1001 | 1 | 2.50 |
+-----------+-----------+------------+------------+------------+
| 2 | 1 | 1002 | 2 | 3.00 |
+-----------+-----------+------------+------------+------------+
| 3 | 2 | 1001 | 2 | 2.00 |
+-----------+-----------+------------+------------+------------+
where order_id is the foreign key to orders
Now for the confusing part. You will need to use a series of JOINs to access the relevant data for each user.
SELECT
t3.id AS user_id,
t3.user_name,
t1.id AS order_id,
t1.date_ordered,
SUM((t2.price * t2.qty)) AS order_total
FROM orders t1
JOIN sales t2 ON (t2.order_id = t1.id)
LEFT JOIN users t3 ON (t1.user_id = t3.id)
WHERE user_id=1
GROUP BY order_id;
This will return:
+-----------+--------------+------------+------------+--------------+
| user_id | user_name | order_id |date_ordered| order_total |
+-----------+--------------+------------+------------+--------------+
| 1 | John | 1 | 2019-03-05 | 8.50 |
+-----------+--------------+------------+------------+--------------+
These type of JOIN statements should come up in basically any project using a relational database (that is, if you are designing your DB correctly). Typically I create a view for each of these complicated queries, which can then be accessed with a simple SELECT * FROM orders_view
For example:
CREATE
ALGORITHM = UNDEFINED
DEFINER = `root`#`localhost`
SQL SECURITY DEFINER
VIEW orders_view AS (
SELECT
t3.id AS user_id,
t3.user_name,
t1.id AS order_id,
t1.date_ordered,
SUM((t2.price * t2.qty)) AS order_total
FROM orders t1
JOIN sales t2 ON (t2.order_id = t1.id)
LEFT JOIN users t3 ON (t1.user_id = t3.id)
GROUP BY order_id
)
This can then be accessed by:
SELECT * FROM orders_view WHERE user_id=1;
Which would return the same results as the query above.
Depending on your needs, you will probably need to add a few more tables (addresses, products etc.) and several more rows to each of these tables. Very often you will find that you need to JOIN 5+ tables into a view, and sometimes you might need to JOIN the same table twice.
I hope this helps despite it not exactly answering your question!
It is probably a bad idea to update the USERS table after inserting into (or updating) the ORDERS table. Avoid storing data twice. In your case: you can always get all "order ids" for a user by querying the ORDERS table. Thus, you don't need to store them in the USERS table (again). Example (tested with MySQL 8.0, see dbfiddle):
Tables and data
create table users( id integer primary key, name varchar(30) ) ;
insert into users( id, name ) values
(1, 'John'),(2, 'Michael'),(3, 'Someone') ;
create table orders(
id integer primary key
, userid integer
, content varchar(3) references users (id)
);
insert into orders ( id, userid, content ) values
(101, 1, '---'),(102, 1, '---')
,(103, 2, '---'),(104, 2, '---'),(105, 3, '---') ;
Maybe a VIEW - similar to the one below - will do the trick. (Advantage: you don't need additional columns or tables.)
-- View
-- Inner SELECT: group order ids per user (table ORDERS).
-- Outer SELECT: fetch the user name (table USERS)
create or replace view userorders (
userid, username, userdata
)
as
select
U.id, U.name, O.orders_
from (
select
userid
, group_concat( id order by id separator '|' ) as orders_
from orders
group by userid
) O join users U on O.userid = U.id ;
Once the view is in place, you can just SELECT from it, and you will always get the current "userdata" eg
select * from userorders ;
-- result
userid username userdata
1 John 101|102
2 Michael 103|104
3 Someone 105
-- add some more orders
insert into orders ( id, userid, content ) values
(1000, 1, '***'),(4000, 1, '***'),(7000, 1, '***')
,(2000, 2, ':::'),(5000, 2, ':::'),(8000, 2, ':::')
,(3000, 3, '###'),(6000, 3, '###'),(9000, 3, '###') ;
select * from userorders ;
-- result
userid username userdata
1 John 101|102|1000|4000|7000
2 Michael 103|104|2000|5000|8000
3 Someone 105|3000|6000|9000
I have two tables as below:
logs
id | user | log_id
---------------------
1 | user1 | abc
2 | user2 | def
3 | user1 | xyz
...
users
id | user | code
---------------
1 | user1 | 1234
2 | user2 | 9876
3 | user1 | 5678
...
I want to add log_id to users and update it with log_id's from Table1, to make Table2 as below:
id | user | code | log_id
---------------------------
1 | user1 | 1234 | abc
2 | user2 | 9876 | def
3 | user1 | 5678 | xyz
...
The only way to match rows in logs and users is using the user field, and the chronological order they appear in the tables. id, as you may have guessed, is the primary key in both tables.
Much appreciated if someone could help me with the query for this. Thanks.
If the id fields are always matched then the reply by Ronak Shah would be my choice.
If the ids do not match then possibly something like this:-
Firstly:-
ALTER TABLE table1 ADD COLUMN code VARCHAR(25);
Then an update like this:-
UPDATE table2
INNER JOIN
(
SELECT id, user, code, #rank2:=IF(#prev_user2 = user, #rank2+1, 1) AS rank, #prev_user2 := user
FROM table2
CROSS JOIN (SELECT #rank2:=0, #prev_user2:='') sub2
ORDER BY user, id
) tab_2
ON table2.id = tab_2.id
INNER JOIN
(
SELECT id, user, log_id, #rank1:=IF(#prev_user1 = user, #rank1+1, 1) AS rank, #prev_user1 = user
FROM table1
CROSS JOIN (SELECT #rank1:=0, #prev_user1:='') sub1
ORDER BY user, id
) tab_1
ON tab_1.user = tab_2.user
AND tab_1.rank = tab_2.rank
SET table2.log_id = tab_1.log_id;
What this is doing is a pair of sub queries which adds a rank to each tables records (I have added the rank within the user, which should make it cope a bit better if one user on one table has an extra record). The results of these sub queries are joined together, and then joined to table2 to do the actual update (the sub query for table2 to get the rank can be joined to table2 based on id).
This seems to work when done in SQL fiddle:-
http://www.sqlfiddle.com/#!2/ad8a6b/1
Try this:
UPDATE dbo.Table2 A
SET A.log_id = B.log_id
INNER JOIN dbo.Table1 B
ON A.user = B.user
But first you have to add log_id column to table2 with alter query.
try this:
alter table table1 add column code varchar(100);
update table1,table2 set table1.code = table2.code where table1.id=table2.id and table1.user=table2.user;
I figured out the solution. I added 2 columns rank and prev_user in both tables, and incremented the value for rank from 1 for the first record for user_x to n for the nth record for user_x, as below:
ALTER TABLE users ADD COLUMN rank tinyInt(1);
ALTER TABLE users ADD COLUMN prevuser varchar(50);
SET #prevuser = '';
SET #rank = 0;
UPDATE users
SET rank = (#rank:=IF(#prevuser != user,1,#rank+1)),
prevuser = (#prevuser := user)
ORDER BY user,id;
ALTER TABLE users DROP COLUMN prevuser;
and,
ALTER TABLE logs ADD COLUMN rank tinyInt(1);
ALTER TABLE logs ADD COLUMN prevuser varchar(50);
SET #prevuser = '';
SET #rank = 0;
UPDATE logs
SET rank = (#rank:=IF(#prevuser != user,1,#rank+1)),
prevuser = (#prevuser := user)
ORDER BY user,id;
ALTER TABLE logs DROP COLUMN prevuser;
Now records can be matched between the tables using user & rank. I added the field log_id to users and updated it as below:
UPDATE users, logs SET users.log_id=logs.log_id WHERE users.user=logs.user AND users.rank = logs.rank;
And voila!
I have a table [users] that I wish to count the number of each occurrence of Movie_ID and update the record in a different table called [total]. So for Movie_ID=81212 it would send the value 2 to my [total] table.
like below:
------------------------------------
| [users] | [total]
+---------+---------+ +---------+-------------+
|Movie_ID |Player_ID| |Movie_ID | Player_Count|
+---------+---------+ +---------+-------------+
|81212 |P3912 | | 81212 | 2 |
+---------+---------+ +---------+-------------+
|12821 |P4851 | | 12821 | 1 |
+---------+---------+ +---------+-------------+
|81212 |P5121 |
+---------+---------+
(movie_ID + player_ID form composite key
so Movie_ID does not need to be unique)
So i'm trying to accomplish this with a stored procedure, this is what I have so far: I'm not sure how to code the part where it loops through every entry in the [users] table in order to find each occurrence of movie_id and sums it up.
DELIMITER //
CREATE PROCEDURE `movie_total` (OUT movie_count int(5))
LANGUAGE SQL
MODIFIES SQL DATA
BEGIN
DECLARE movie_count int(5);
SELECT count(movie_id) AS movie_count FROM users
foreach unique row in Users ;
IF (SELECT COUNT(*) FROM users WHERE movie_id) > 0
THEN
INSERT INTO total (:movie_id, :Player_Count) VALUES (movie_id, movie_count);
END //
To update this field you can use a query like this -
UPDATE
total t
JOIN (SELECT Movie_ID, COUNT(*) cnt FROM users GROUP BY Movie_ID) m
ON t.Movie_ID = m.Movie_ID
SET
t.Player_Count = cnt
BUT: Do you really need a total table? You always can get this information using SELECT query; and the information in the total table may be out of date.
I think you can do this without a loop:
update total set total.Player_Count = (select COUNT(Movie_ID) from users where total.Movie_ID=users.Movie_ID group by (Movie_ID));