How to insert rows in a table depending on a different table? - sql

I have two tables.
One user table containing the user_id, user_email, user_name
and other user_status table containing user_email, status.
The issue I am facing is the user_status table is newly added and it is empty. The user table is already in the production. I want to achieve a scenario where I can add the rows in the status table without cleaning the db.
If the user_name is empty, then the status in the user_status table would be offline otherwise online.
user_id user_email user_name
1 xyz#gmail.com xyz
2 abc#gmail.com
If this is my user table and my user_status table is empty, then I want to update the user_status table as:
user_email status
xyz#gmail.com active
abc#gmail.com inactive

Use insert ...select and a conditional expression:
insert into user_status(user_email, status)
select user_email, case when user_name is null then 'offline' else 'online' end
from users
This assumes that by "empty" you mean null. If you really mean empty string, then the condition in the case should be where user_name = '' instead.
Note that user is a language keyword in almost all databases, hence not a good choice for a column name. I renamed it to users in the query.

Related

trigger after update by spesific id

hy, I want to use the after update trigger, to make changes automatically in the 'active' column of the password table, when I make changes to the 'active' column of the employee table.
I created a trigger like this:
FOR EACH ROW
BEGIN
UPDATE mstUser_2 u
SET u.activeEmp=NEW.activeEmp
WHERE u.activeEmp=OLD.activeEmp
END
but the result is changing all ids..
the example table below, when I change id : 3 to 'F' in the employee table and it will automatically change id : 3 in the 'active' column the password table to 'F'
employee table
idx
name
address
Active
1
nae
dubai
T
2
nia
mekkah
F
3
sia
dubai
T
4
bae
vegas
T
password table
idx
password
Active
1
12345
T
2
12345
F
3
12345
T
4
12345
T
I think is better to use foreign key:
ALTER TABLE 'employee'
ADD CONSTRAINT 'NAME' FOREIGN KEY ('idx') REFERENCES 'password' ('idx') ON UPDATE RESTRICT
This way you can remove the column active in the password table that is redundant and you can, in one query, using SELECT * FROM employee NATURAL JOIN password WHERE idx=n extract all you need.
Optionally you can tell what to do when an empolyee is deleted with ON DELETE, here the mariadb reference page https://mariadb.com/kb/en/foreign-keys/

How to verify table update and migrate data from another table - postgresql

I have following two tables in my potgres database with each type.
user
userid | bigint (PK) NOT NULL
username | character varying(255)
businessname | character varying(255)
inbox
messageid | bigint (PK) NOT NULL
username | character varying(255)
businessname | character varying(255)
What i wanna achieve here is i want to add a new field called userRefId to inbox table and migrate data on user table's userid data into that where each username and businessname match in both tables.
These are the queries i use to do that.
ALTER TABLE inbox ADD userRefId bigint;
UPDATE inbox
SET userRefId = u.userid
from "user" u
WHERE u.username = inbox.username
AND u.businessname = inbox.businessname;
Now i want to verify the data has been migrated correctly. what are the approaches i can take to achieve this? (Note : the username on inbox can be null)
Would this be good enough to verification?
Result of select count(*) from inbox where username is not null; being equal to
select count(userRefId) from inbox;
Is the data transferred correctly? First, the update looks correct, so you don't really need to worry.
You can get all rows in consumer_inbox where the user names don't match
select ci.*. -- or count(*)
from consumer_inbox ci
where not exists (select 1
from user u
where ci.userRefId = u.userId
);
This doesn't mean that the update didn't work. Just that the values in consumer_inbox have no matches.
Under the circumstances of your code, this is equivalent to:
select ci.*
from consumer_inbox ci
where userId is null;
Although this would not pick up a userId set to a non-matching record (cosmic rays, anyone?).
You can also validate the additional fields used for matching:
select ci.*. -- or count(*)
from consumer_inbox ci
where not exists (select 1
from user u
where ci.userRefId = u.userId and
ci.username = u.username and
ci.businessname = u.businessname
);
However, all this checking seems unnecessary, unless you have trigger on the tables or known non-matched records.

Can a SQL database support "insert only" mode?

In the latest years the "Insert Only" methodology came more and more popular.
For those who use SQL DB you probably know that in high volume with a lot of update queries the DB is locking the rows and you starting to get a "bottleneck". the Insert Only mode is to use only insert (without updates) and always retrieve the latest item in the DB.
The issue I'm facing is with the SELECT queries since there is a field that can be common for multiple records in the DB and if I will want to query by it I will never know when I got all of the latest records for the field above (unless I'm using GROUP and this will not be efficient)
Scheme Example:
let say I have the following scheme:
CREATE TABLE users
(
id SERIAL NOT NULL
CONSTRAINT users_pkey
PRIMARY KEY,
first_name VARCHAR(255),
last_name VARCHAR(255),
username VARCHAR(255),
email VARCHAR(255),
password VARCHAR(255),
account_id INTEGER,
created_at TIMESTAMP NOT NULL
);
Now let say I have the following users that's related to account number 1 (using account_id):
1. John Doe
2. Jain Doe
If I will want to edit John Doe last name in the Insert Only mode I will insert a new record and when I will want to retrieve it I will run the following query:
SELECT * from users WHERE email='jhon.doe#test.com' ORDER BY created_at Desc limit 1;
The issue is what I need to to if I want to retrieve all account 1 users ? how can I prevent from executing poor query with group by
The following query will return 3 records although I have only 2 users
SELECT * from users WHERE account_id=1;
The answer to your question is distinct on (in Postgres). However, it is unclear how you define a user. I would expect a user_id, but perhaps email is supposed to serve this purpose.
The query looks like:
select distinct on (email) u.*
from users u
where account_id = 1
order by email, created_at desc;
For performance, you want an index on users(account_id, email, created_at desc).

SQL Select statement separate values into two columns

I have string value in the column Username.
Sample usernames:
USERNAME
--------
foobar123
john
smith23
steve
peter
king213
The user names with numbers at the end means that these users are no longer active. I want to separate these usernames into two columns Active and Not_Active in one Select Statement since i'll be using these for reports purposes.
Result should be:
Active Not_Active
john foobar123
steve smith23
peter king213
Query:
SELECT
Username,
(
CASE Username
WHEN '%[0-9]%' THEN 'Not'
ELSE 'Active'
END
)
FROM
Users;
I tried Case but I don't know how to get the username value.
Expanding on my comment reply to your original posting, you don't want the data in the same output result-set; instead you will want two result sets (i.e. two tables), each with the different criteria.
Note that you cannot use LIKE string matching (%) with the WHEN statement in SQL. You have to use it in a CASE WHEN statement (one without a "switch" expression)
-- Result set one: Active users
SELECT
UserName
FROM
Users
WHERE
UserName NOT LIKE '%[0-9]';
-- Result set two: Inactive users
SELECT
UserName
FROM
Users
WHERE
UserName LIKE '%[0-9]';
If you really want, you can combine these two queries into a single result-set with the data in different columns. This would be done by adding a ROW_NUMBER() column to each intermediate table, then doing a FULL OUTER JOIN on ROW_NUMBER(), however the output result would be meaningless and painful to iterate over in any consuming client code.
Another option might be a single result-set, with a computed IsActive column:
SELECT
UserName,
( CASE WHEN UserName NOT LIKE '%[0-9]' THEN 1 ELSE 0 END ) AS IsActive
FROM
Users
...which would be considerably easier to process in any consuming code.
this format of saving data is quite useful in this one column holds username and other holds status of the user
select username,
case username
when '%[0-9]% then inactive
else active
end as user_status
from table_1
username user_status
john active
john123 inactive

Selectively retrieve data from tables when one record in first table is linked to multiple records in second table

I have 2 tables:
1. Tbl_Master: columns:
a. SEQ_id
b. M_Email_id
c. M_location_id
d. Del_flag
2. Tbl_User: columns
a. U_email_id
b. Last_logged_date
c. User_id
First table Is master table it has unique rows i.e. single record of all users in the system.
Each User can be uniquely identified by the email_id in each table.
One user can have multiple profile, which means for one us_email_id field in the tblUser table, there can be many user_id in tbl_User,
i.e there can be multiple entries in second table for each user.
Now I have to select only those users who have logged in for last time before, lets say '2012', i.e before 1-Jan-2012.
But if one user has 2 or more user_id and one user_id has last_logged_date less than 2012
But other user_id has greater than 2012 then such user should be ignored.
In the last all all the result user will be marked for deletion by setting DEL_flag in master table to ‘Yes’
For eg:
Record in Tbl_Master:
A123 ram#abc.com D234 No
A123 john#abc.com D256 No
Record in tbl_User can be Like:
ram#abc.com '11-Dec-2011' Ram1
ram#abc.com '05-Apr-2014' Ram2
john#abc.com '15-Dec-2010' John1
In such case only John's Record should be selected not of Ram whose one profile has last_logged_date>1-Jan-2012
Another possibility was
SELECT
m.M_Email_id,
MAX(u.Last_logged_date) AS last_login
FROM
Tbl_Master m
INNER JOIN
Tbl_User u on u.U_email_id = m.M_Email_id
GROUP BY m.M_Email_id
HAVING
-- Year(MAX(u.Last_logged_date)) < 2012 -- use the appropriate function of your DBMS
EXTRACT(YEAR FROM(MAX(u.Last_logged_date))) < 2012 -- should be the version for oracle
-- see http://docs.oracle.com/cd/B14117_01/server.101/b10759/functions045.htm#i1017161
Your UPDATE operation can use this select in the WHERE clause.
Try this, this ans is in sql server, I haven't worked on Oracle.
select * from Tbl_Master
outer apply
(
select U_email_id,max(Last_logged_date)as LLogged,count(U_email_id) as RecCount
from Tbl_User
where Tbl_User.U_email_id = Tbl_Master.M_Email_id
group by U_email_id
)as a
where RecCount >2
and Year(LLogged) < '2012'
Try this DEMO
Hope it helps you.