How to preserve value of one column based on other column values? - mysql

I have a requirement wherein I will be getting records which I need to insert into a database (MariaDB 10.3) table wherein for each record I have 2 base values viz. name and amount and one processed value viz. action (imagine this action is something acted upon by user from UI).
+---------+--------+----------------+----------------+
| name | amount | action | created_at |
+---------+--------+----------------+----------------+
| Akshay | 1000 | processed | 2019-08-01 |
+---------+--------+----------------+----------------+
Now, what I want to achieve is when next time I receive a record with name and amount which already exist in the table, then populate action by automatic reference to the previous entry from this same table whose name and amount match.
And if name and amount combination does not exist in the table, then do not populate action.
Desired end result is depicted in structure below:
+---------+--------+----------------+----------------+
| name | amount | action | created_at |
+---------+--------+----------------+----------------+
| Akshay | 1000 | processed | 2019-08-04 |
| Akshay | 1001 | | 2019-08-03 |
| Saanvi | 1000 | | 2019-08-02 |
| Akshay | 1000 | processed | 2019-08-01 |
+---------+--------+----------------+----------------+
Any clues how can I achieve this functionality?

DROP PROCEDURE IF EXISTS db.SP_CREATE_VALUE;
CREATE PROCEDURE db.`SP_CREATE_VALUE`(IN `in_name` VARCHAR(50), IN `in_amount` INT)
BEGIN
DECLARE numAlreadyExists INT(11) DEFAULT 0;
DECLARE strExistingAction VARCHAR(20) DEFAULT "";
SET numAlreadyExists=(SELECT COUNT(*) FROM table_name WHERE name=in_name AND in_amount=in_amount);
IF (numAlreadyExists >0) THEN
SET strExistingAction=(SELECT action FROM table_name WHERE name=in_name AND in_amount=in_amount ORDER BY table_id DESC LIMIT 1);
END IF;
INSERT INTO table_name
name=in_name,amount=in_amount,action=strExistingAction;
END;
And then when you want to create a new record, simply...
CALL SP_CREATE_VALUE('Akshay',1000);

You can use window functions. For instance:
select name, amount,
max(action) over (partition by name, amount order by date) as action,
date
from t;

Related

Create Trigger : update table column by inserting data into another table rows

Please Help me to create triggers,
I have 2 tables of
data
+---------+------------+-------+-------+
| id | info_id | rate | qty | total |
+----+---------+------------+----------+
| 80 | 10 | 150 | 5 | 750 |
+----+---------+-------+-------+-------+
| 81 | 10 | 50 | 5 | 250 |
+--------------+-------+-------+-------+
info
+---------+---------------+------------+
| id | name | gtotal | dated |
+-----+--------+----------+------------+
| 10 | Hari | NULL | 2021-05-15 |
+---------+------------+---------------+
I want to create a trigger through phpmyadmin, as soon as data will be inserted, then info.gtotal will be updated by adding data.total from matched info_id from table name- data.
what will be the trigger if update on data happens too. I just want to create both triggers.
I am new with such, please help me. Any help is accepted.
You need to create two triggers one for insert and another for update.
CREATE TRIGGER `insert_trigger`
AFTER INSERT ON `data`
FOR EACH ROW
UPDATE info
SET gtotal = gtotal + new.total
WHERE id = new.info_id;
Here new.info_id will have the info_id value of newly insert record
CREATE TRIGGER `update_trigger`
AFTER UPDATE ON `data`
FOR EACH ROW
UPDATE info
SET gtotal = (gtotal - old.total) + new.total
WHERE id = new.info_id;
Here old.total will have the total value of record before updating. new.total is the total value after updation.
Since you haven't conveyed what to do after update I have added the logic of subtracting the total from old total and added the new total value. Change it as per your requirement.
You can also create these triggers using GUI in phpmyadmin. You have to select the triggers in the menu bar and add the trigger definition.

mysql copy many records with one change

Here is a table Evact:
+--------------+-----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-----------------------+------+-----+---------+-------+
| EvActMas | char(10) | NO | PRI | | |
| EvActSub | char(10) | NO | PRI | | |
| EvActCode | char(10) | NO | PRI | | |
| EvActIncOutg | enum('I','O','B','N') | YES | | NULL | |
| EvActBudAct | enum('B','A','O') | YES | | NULL | |
...other columns ...
and here are some records:
EvActMas EvActSub EvActCode EvActIncOutg EvActBudAct ..other..
Bank-2017 Incoming mth01 I A
Bank-2017 Incoming mth02 I A
Bank-2017 Incoming mth03 I A
Bank-2017 Incoming mth04 I A
Bank-2017 Incoming mth05 I A
Bank-2017 Incoming mth06 I A
I want to add six new records to the table where 'Incoming' is changed to 'Outgoing' and 'I' is changed to 'O'.
I did it the hard way by creating a new table from the old one; updating the new table and then inserting back into Evact:
Create table btemp like Evact;
update btemp set Evact = 'Outgoing', EvActIncOutg = 'O';
insert into Evact select * from btemp;
That worked, but I want to get better at SQL. What I wish for is a way to do this in one step by joining Evact to itself in some way. Does anyone have a suggestion?
If you want to insert a bunch of rows that are part copies of existing rows:
INSERT INTO evact
SELECT evactmas, 'Outgoing', evactcode, 'O', evactbudact, ...other..
FROM evact
You make a Select statement that is the data you want to insert, some columns in the select are the values as-is, other columns are the new values
If you aren't specifying all the columns in the select you'll have to put a list of column names in brackets after the INTO so MySQL knows which columns are to get what data. You can only omit the columns list if your select query selects the same number of columns in the table (in which case the columns selected must be in the same order as the table columns to be inserted into)
If your table has a calculated primary key (auto increment for example) specify the value to insert as 0 or NULL to have MySQL calculate a new value for it, or name all the columns except that one after the INTO and omit it from the select list

How to create an update trigger where an insert operation is performed?

Consider below is my table,
register_device
id | user_id | device_id | status |
1 | 12 | 1234 | 1 |
2 | 1 | 5678 | 1 |
3 | 11 | 1456 | 1 |
Logic for trigger:
Before inserting value in register_device table, i want to check whether the new device_id value already exist in register_device table. If in case the value is already present its status need to be changed to 0, before inserting a new value, like below.
id | user_id | device_id | status |
1 | 12 | 1234 | 0 |
2 | 1 | 5678 | 1 |
3 | 11 | 1456 | 1 |
4 | 14 | 1234 | 1 |
So when i run insert operation through coding, trigger need to perform the above logic by its own in database.
Your current approach is going to make it very difficult to implement your insert logic for several reasons:
You can't use a trigger because a trigger cannot modify the table which caused it to fire
Using ON DUPLICATE KEY UPDATE also won't fly because you actually want to insert the record even if an update also happens
I propose a slightly different table design:
id | user_id | device_id | status_timestamp
The only change here is that status has become status_timestamp, which is a timestamp column. You can insert records and use NOW() for the current timestamp value.
Logically speaking, any record which does not have the max value of status_timestamp for a given device_id would correspond to a zero status in your original table. And records having the max status_timestamp value for a given device_id would correspond to a status of 1.
For example, to get the status=1 record for device_id 1234 you could use the following query:
SELECT *
FROM register_device
WHERE device_id = 1234
ORDER BY status_timestamp DESC
LIMIT 1
And to get all the status=0 records for device_id 1234 you could use:
SELECT *
FROM register_device
WHERE device_id = 1234 AND
status_timestamp < (SELECT MAX(status_timestamp) FROM register_device
WHERE device_id = 1234)

MySQL Advanced SUM function

Good day!
I am sorry If this question was already asked, but I am kind of in hurry, so I am not sure.
I have 2 tables:
Table.Cars and Table.Price
In table Cars:
ID Auto_Increment Primary key NOT NULL
Name VARCHAR(30)
In table Price:
CarsID Primary key NOT NULL
Units Int
Price_per_unit decimal(10,2)
Total decimal(10,2)
So, what I need to do is, Create column (TOTAL* (Name does not need to be necessary this one)), in table Price, Set it to do Mathematical function.
Basicly, I want Column.Total to show Units * price_per_unit which would be:
ALTER TABLE Price
ADD TOTAL Decimal(10,2)
UPDATE Price SET Total = SUM(Units * Price_per_unit);
Which will look like this:
---------------------------------------------------
| ID | Units | Price_per_unit | Total | TOTAL |
---------------------------------------------------
| 1 | 12 | 30000,00 | 360000,00 | NULL |
| 2 | 5 | 12000,00 | 60000,00 | NULL |
And here comes my problem. I want to make TOTAL, to look like this:
---------------------------------------------------------
| ID | Units | Price_per_unit | Total | TOTAL |
---------------------------------------------------------
| 1 | 12 | 30000,00 | 360000,00 | 420000 |
| 2 | 5 | 12000,00 | 60000,00 | |
|_______________________________________________________|
So, next time, I put new record in table Price, I need TOTAL, to auto SUM my table by taking data from Units * Price_pre_unit.
So my question is, how do I make this query?
If you want Mysql database to do it automatically, it seems you are looking for a trigger. You should tun this code one time and the trigger will handle it for ever:
CREATE TRIGGER trigger_name
AFTER INSERT
ON price FOR EACH ROW
BEGIN
UPDATE Price SET Total = SUM(Units * Price_per_unit) where id=(select id from price order by id limit 1);
END;

MySQL second auto increment field based on foreign key

I've come across this problem numerous times but haven't found a "MySQL way" to solve the issue as such - I have a database that contains users and reports. Each report has an id which I display as a report number to my users.
The main complaint is that users are confused as to why reports have gone missing from their system. This is not actually the case. It is actually that they are recognizing a gap between their IDs and assume that these are missing reports, when in actual fact, it is simply becasue another user has filled in this auto-incrementing gap.
I need to know if there is a way to do this in MySQL:
Is it possible that I can have a second auto-increment field called report_number which is based on a user_id field which has a different set of auto-increments per user?
e.g.
|------|---------|---------------|
| id | user_id | report_number |
|------|---------|---------------|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
| 5 | 1 | 4 |
| 6 | 1 | 5 |
| 7 | 2 | 2 |
| 8 | 3 | 1 |
| 9 | 3 | 2 |
|------|---------|---------------|
I am using InnoDB for this as it is quite heavily weighted with foreign-keys. It appears to complain when I add a second auto increment field, but I wasn't sure if there was a different way to do this?
MyISAM supports the second column with auto increment, but InnoDB doesn't.
For InnoDB you might create a trigger BEFORE INSERT to get the max value of the reportid and add one to the value.
DELIMITER $$
CREATE TRIGGER report_trigger
BEFORE INSERT ON reports
FOR EACH ROW BEGIN
SET NEW.`report_id` = (SELECT MAX(report_id) + 1 FROM reports WHERE user_id = NEW.user_id);
END $$
DELIMITER ;
If you can use MyISAM instead, in the documentation of MySQL page there is an example:
http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
CREATE TABLE animals (
grp ENUM('fish','mammal','bird') NOT NULL,
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (grp,id)
) ENGINE=MyISAM;
INSERT INTO animals (grp,name) VALUES
('mammal','dog'),('mammal','cat'),
('bird','penguin'),('fish','lax'),('mammal','whale'),
('bird','ostrich');
SELECT * FROM animals ORDER BY grp,id;
Which returns:
+--------+----+---------+
| grp | id | name |
+--------+----+---------+
| fish | 1 | lax |
| mammal | 1 | dog |
| mammal | 2 | cat |
| mammal | 3 | whale |
| bird | 1 | penguin |
| bird | 2 | ostrich |
+--------+----+---------+
Right one with IFNULL:
DELIMITER $$
CREATE TRIGGER salons_trigger
BEFORE INSERT ON salon
FOR EACH ROW BEGIN
SET NEW.salon_id = IFNULL((SELECT MAX(salon_id) + 1 FROM salon WHERE owner = NEW.owner), 1);
END $$
DELIMITER ;
I think mysql doesnt support two auto_increment columns. you can create report number using information schema.
select NULL from information_schema.columns
MySQl does not support two auto incremented fields, if you need then create another table, set the other field which you want to be as auto incremented and you must set up a relationship with these two tables.