trigger after update by spesific id - sql

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/

Related

For each existing row in table A, insert N rows in table B

I am trying to write a migration script using SQL.
I got the DDL part pretty easily covered, but now i have to migrate the existing data as shown below:
Before Migration:
Table BOX
uuid
active_service_number
other BOX columns...
2869c64f-8ecb-4296-8c3b-1c72b308d59f
2
...
After Migration:
Table BOX
uuid
other BOX columns...
2869c64f-8ecb-4296-8c3b-1c72b308d59f
...
Table BOX_SERVICE
uuid
number
state
box_uuid
6a33d57f-e02b-4d0a-b258-3cef0bb3dff7
0
INACTIVE
2869c64f-8ecb-4296-8c3b-1c72b308d59f
...
1
INACTIVE
2869c64f-8ecb-4296-8c3b-1c72b308d59f
...
2
ACTIVE
2869c64f-8ecb-4296-8c3b-1c72b308d59f
...
...
...
...
...
N
INACTIVE
2869c64f-8ecb-4296-8c3b-1c72b308d59f
To sum it up
For each BOX row, I want to create exactly N BOX_SERVICE rows, numbered from 0 to N. (N is a fixed number predetermined)
Only one BOX_SERVICE should have it's state set to ACTIVE, the one corresponding to active_service_number (2 in the example above) of the corresponding BOX.
I got the pseudo-code figured out, but can't seem to translate it into SQL. I tried to do it with a single request, with multiple requests, cursors.
Here is what my DDL is looking like:
CREATE TABLE BOX_SERVICE (uuid varchar(255) NOT NULL,
number int,
state varchar(255) DEFAULT 'INACTIVE',
box_uuid varchar(255),
PRIMARY KEY(uuid),
CONSTRAINT FK_BOX_BOX_SERVICE FOREIGN KEY (box_uuid)
REFERENCES BOX(uuid)
);
-- Migrate existing data
ALTER TABLE BOX DROP active_service_number
You can generate the rows using generate_series() and cross join:
select <uuid function>,
gs.n as number,
(case when gs.n = b.active_service_number then 'ACTIVE' else 'INACTIVE' end),
b.uuid as box_uuid
from box b cross join
generate_series(0, n, 1) as gs(n);
Your version of Postgres only offers UUIDs via an extension. Use whatever method you use for the first column of generating UUIDs.
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
select uuid_generate_v1(),sequence number,
(case when active_service_number=SEQUENCE THEN 'ACTIVE' ELSE 'INACTIVE' END)STATE,
UUID BOX_UUID from box CROSS JOIN (select generate_series(0,5) as sequence)t
Output:
UUID |Number|Status |Box_UUID
4b247576-8e42-11eb-80ae-1831bf6eced8|0 |INACTIVE|2869c64f-8ecb-4296-8c3b-1c72b308d59f
4b247577-8e42-11eb-80af-1831bf6eced8|1 |INACTIVE|2869c64f-8ecb-4296-8c3b-1c72b308d59f
4b247578-8e42-11eb-80b0-1831bf6eced8|2 |ACTIVE |2869c64f-8ecb-4296-8c3b-1c72b308d59f
4b247579-8e42-11eb-80b1-1831bf6eced8|3 |INACTIVE|2869c64f-8ecb-4296-8c3b-1c72b308d59f
4b24757a-8e42-11eb-80b2-1831bf6eced8|4 |INACTIVE|2869c64f-8ecb-4296-8c3b-1c72b308d59f
4b24757b-8e42-11eb-80b3-1831bf6eced8|5 |INACTIVE|2869c64f-8ecb-4296-8c3b-1c72b308d59f

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

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.

union table, change serial primary key, postgresql

Postgresql:
I have two tables 'abc' and 'xyz' in postgresql. Both tables have same 'id' columns which type is 'serial primary key;'.
abc table id column values are 1,2,3 and also xyz id column containing same values 1,2,3,4
I want to union both tables with 'union all' constraint. But I want to change 'xyz' id column values to next value of 'abc' id column last value as 1,2,3,4,5,6,7
select id from abc
union all
select id from xyz
|id|
1
2
3
1
2
3
4
my wanted resuls as
|id|
1
2
3
4
5
6
7
BETTER - Thanks to #CaiusJard
This should do it for you
select id FROM abc
UNION ALL select x.id + a.maxid FROM xyz x,
(SELECT MAX(id) as maxid from abc) a
ORDER BY id
For anyone who's doing something like this:
I had a similar problem to this, I had table A and table B which had two different serials. My solution was to create a new table C which was identical to table B except it had an "oldid" column, and the id column was set to use the same sequence as table A. I then inserted all the data from table B into table C (putting the id in the oldid field). Once I fixed the refernces to point to from the oldid to the (new)id I was able to drop the oldid column.
In my case I needed to fix the old relations, and needed it to remain unique in the future (but I don't care that the ids from table A HAVE to all be before those from table C). Depending on what your trying to accomplish, this approach may be useful.
If anyone is going to use this approach, strictly speaking, there should be a trigger to prevent someone from manually setting an id in one table to match another. You should also alter the sequence to be owned by NONE so it's not dropped with table A, if table A is ever dropped.

Update a table foreign keys by substituting by a lookup from the result of another table

Suppose I have two tables :
Table 1:
SELECT * FROM ORIGINAL_DEALER;
ID ENAME
----- --------------------------
1 JOHN
2 00000JOHN
3 JACK
4 00000JACK
5 MARIA
6 00000MARIA
Table 2:
SELECT * FROM NAMES;
ID_NUM
------
1
2
3
4
5
6
I'll have to update NAMES.
Table ORIGINAL_DEALER has duplicate / invalid names such as
00000JOHN
The invalid names have exactly five zeros prefixed before the valid names. i.e valid name: JOHN
invalid name: 00000JOHN
Now I'll have to select the ID's of invalid names from
ORIGINAL_DEALER table and update the ID_NUM in NAMES table
WITH VALID ID. i.e when the invalid ename= '00000JOHN' has an ID
= 2 which is also invalid. but original_dealer is parent table, i'll have to replace all the invalid id's in NAMES table with valid
ones.
i.e the output after updating NAMES should be:
SELECT * FROM NAMES;
ID_NUM
------
1
1
3
3
5
5
How can I do it without manually setting it everytime as there will huge data?
I'm using Oracle DB
You can use a update statement with a lookup like below, by using an inner lookup subquery which in turn uses the TRIM function to strip out the leading zeroes during matching. We also restrict the update to just those Names linked to OriginalDealer records starting with 00000 to mimimize the risk of unnecessary updates.
UPDATE Names SET ID_NUM =
(SELECT od1.ID
FROM OriginalDealer od1
INNER JOIN OriginalDealer od2
ON od1.EName = TRIM(LEADING '0' FROM od2.EName)
WHERE od2.ID = Names.ID_NUM)
WHERE EXISTS
(
SELECT 1
FROM OriginalDealer od
WHERE od.ENAME LIKE '00000%'
AND Names.ID_NUM = od.ID
);
SqlFiddle here
Note that the model of marking duplicates with a prefix like '00000' is rather fragile:
It assumes there is exactly 1 match between the 00000NAME and NAME rows in ORIGINAL_DEALER
If the above isn't true, it will attempt to set Names.ID_NUM to NULL or Fail if there is more than one match (which is probably a good thing, we don't want to corrupt data)

How to change values of foreign keys in postgresql?

Let's say I have two tables: Customer and City. There are many Customers that live in the same City. The cities have an uid that is primary key. The customers have a foreign key reference to their respective city via Customer.city_uid.
I have to swap two City.uids with one another for external reasons. But the customers should stay attached to their cities. Therefore it is necessary to swap the Customer.city_uids as well. So I thought I first swap the City.uids and then change the Customer.city_uids accordingliy via an UPDATE-statement. Unfortunately, I can not do that since these uids are referenced from the Customer-table and PostgreSQL prevents me from doing that.
Is there an easy way of swapping the two City.uids with one another as well as the Customer.city_uids?
One solution could be:
BEGIN;
1. Drop foreign key
2. Make update
3. Create foreign key
COMMIT;
Or:
BEGIN;
1. Insert "new" correct information
2. Remove outdated information
COMMIT;
My instinct is to recommend not trying to change the city table's id field. But there is lot of information missing here. So it really is a feeling rather than a definitive point of view.
Instead, I would swap the values in the other fields of the city table. For example, change the name of city1 to city2's name, and vice-versa.
For example:
OLD TABLE NEW TABLE
id | name | population id | name | population
------------------------- -------------------------
1 | ABerg | 123456 1 | BBerg | 654321
2 | BBerg | 654321 2 | ABerg | 123456
3 | CBerg | 333333 3 | CBerg | 333333
(The ID was not touched, but the other values were swapped. Functionally the same as swapping the IDs, but with 'softer touch' queries that don't need to make any changes to table constraints, etc.)
Then, in your associated tables, you can do...
UPDATE
Customer
SET
city_uid = CASE WHEN city_uid = 1 THEN 2 ELSE 1 END
WHERE
city_uid IN (1,2)
But then, do you have other tables that reference city_uid? And if so, is it feasible for you to repeat that update on all those tables?
You could create two temporary cities.
You would have:
City 1
City 2
City Temp 1
City Temp 2
Then, you could do the follow:
Update all Customer UIDs from City 1 to City Temp 1.
Update all Customer UIDs from City 2 to City Temp 2.
Swap City 1 and 2 UIDs
Move all Customers back from City Temp 1 to City 1.
Move all Customers back from City Temp 2 to City 2.
Delete the temporally cities.
You can also add an ON UPDATE CASCADE clause to the parent table's CREATE TABLE statement, as described here:
How to do a cascading update?