Update data based on previous row combination values - mysql

I have a MySQL table with the following structure:
ID
CatLevel1 CatLevel2 CatLevel3 ... CatLevel6 AcctLevel1 AcctLevel2 ... AcctLevel6
(6 columns for CatLevel, from 1 to 6) and 6 columns for AcctLevel, from 1 to 6).
Beginning with AcctlLevel1, I need to update it depending on the values found in the Catelevel fields in the following manner:
Begin iteration on CatLevel1. Initial value for AcctLevel1 -> 01.
If CatLevel1 Row(n) <> CatLevel1 Row(n-1) then AcctLevel1 -> 02.
meaning that each time a new value (not matching the previous row) is found in CatLevel1, increase the AcctLevel1 by 1 also adding a leading zero for values less than 10.
When the last row in CatLevel1 has been iterated, then begin with CatLevel2 and iterate through it in the same manner.
I was wondering which way to go, to break it down in smaller pieces and code it with PHP or to do it all in MySQL with some sort or recursiveness?
Many of you will think I'm asking for the solution, but I'm really asking for some ideas to get me started because I'm a bit confused on how to go.

Based on your requirement I've come with with the following.
The first Update does a necessary reset.
The second causes AcctLevel1 to be 1 whenever there is a change with the previous row.
The third Update sums up these 1 to create the final result.
Data:
create table data
(
id int,
CatLevel1 varchar(5),
AcctLevel1 varchar(5)
);
insert into data values (0,'1','0');
insert into data values (1,'2','0');
insert into data values (2,'1','1');
insert into data values (3,'2','1');
insert into data values (4,'2','1');
SQL Commands:
UPDATE `data` t1 SET AcctLevel1 = 0;
update `data` t1
left outer JOIN `data` t2
on t1.id-1 = t2.id
set t1.AcctLevel1 =
case when t1.CatLevel1 = t2.CatLevel1 then t1.AcctLevel1
else t2.AcctLevel1+1 end;
update `data` t1
set t1.AcctLevel1 =
( select SUM(TEMP.AcctLevel1) from (SELECT *FROM `data`) AS TEMP where TEMP.ID <= t1.ID );
SQL Fiddle: http://sqlfiddle.com/#!2/8fb647/2
2ND SQL Fiddle:http://sqlfiddle.com/#!2/c047bc/1
Update: Final Toy Query
UPDATE `data` t4
SET AcctLevel1 =
(
SELECT CASE WHEN TEMP.SCHANGES IS NULL THEN 0 ELSE TEMP.SCHANGES END from
(SELECT T3.ID,
(SELECT SUM(CASE WHEN t1.CatLevel1 = t2.CatLevel1 THEN 0 ELSE 1 END) AS SUM_CHANGES
FROM `data` t1,
`data` t2
WHERE t1.id-1 = t2.id
AND t1.ID <= t3.ID) AS SCHANGES
FROM `DATA` t3 ) as TEMP where TEMP.ID = T4.ID
);
Final JSFiddle: http://sqlfiddle.com/#!2/325f16/2

Related

How can I change SELECT statement to IF statement in Mysql?

In mysql, I tried to print '-1' if 3 conditions are satisfied.
SELECT '-1'
WHERE not exists(select * from acq_staff where acq_person_id = staffID)
OR not exists(select * from acq_training_course_session where training_course_id = course_id)
OR exists(select * from acq_training_enrolment where acq_staff_acq_person_id = staffID);
But how can I change this SELECT statement to IF statement so that if either those 3 conditions are satisfied, print -1 otherwise I am going to insert a data.
Sorry for not enough information
MySQL INNER JOIN, along with WHERE NOT EXISTS, can be used to determine if there's an existing course, and existing staff, and that staff is enrolled in that course, and if not, INSERT the staff and course id in the enrollment table.
-- create
CREATE TABLE acq_staff (
acq_person_id INTEGER PRIMARY KEY
);
CREATE TABLE acq_training_course_session (
training_course_id INTEGER PRIMARY KEY
);
CREATE TABLE acq_training_enrolment (
training_course_id INTEGER NOT NULL,
acq_staff_acq_person_id INTEGER NOT NULL
);
-- insert
INSERT INTO acq_staff VALUES (1), (2), (3);
INSERT INTO acq_training_course_session VALUES (1), (2), (3), (4);
INSERT INTO acq_training_enrolment VALUES (1,1), (1,2), (2,1), (3,1);
-- fetch
INSERT INTO acq_training_enrolment (training_course_id, acq_staff_acq_person_id)
SELECT 3, 1 WHERE NOT EXISTS
(SELECT *
FROM acq_training_course_session
INNER JOIN acq_training_enrolment
ON acq_training_course_session.training_course_id = acq_training_enrolment.training_course_id
INNER JOIN acq_staff ON acq_training_enrolment.acq_staff_acq_person_id = acq_staff.acq_person_id
WHERE acq_training_course_session.training_course_id = 3
AND acq_staff.acq_person_id = 1)
;
Try it here: https://onecompiler.com/mysql/3yk7xynkg
I guess you can do something like this: How can I simulate a print statement in MySQL?
`mysql>SELECT 'some text' as '';
+-----------+
| |
+-----------+
| some text |
+-----------+
1 row in set (0.00 sec)`
and just instead of some text set -1.
And one more thing i noticed in your question, that part "if those 3 conditions are satisfied" if you want all 3 conditions to be satisfied you need to change OR to AND. Because in your case, with OR, there needs to be satisfied only 1 condition, but with AND all 3 of them need to be satisfied.
maybe you can try that
select
if(
acq_staff.acq_person_id = staffID , '-1' ,
if(
acq_training_course_session.training_course_id = course_id , '-1' ,
if(acq_training_enrolment.acq_staff_acq_person_id = staffID , '-1' , 'not exist')
)
) as "check" from acq_staff , acq_training_course_session , acq_training_enrolment limit 1
The question is about how to conditionally execute an insert query. In pseudo-code, the question asks how to do the following
flag = (SELECT ... WHERE <all the conditions are met>)
IF flag == 1
INSERT INTO ....
ELSE IF flag == -1
DO NOTHING
Now think about it this way
result_set = (SELECT ... WHERE <all the conditions are met>)
# result_set here is the actual rows we want to insert
# length(result_set) > 0 if conditions are met
# length(result_set) == 0 if conditions are not met
INSERT INTO ... (result_set)
or simply
INSERT INTO ... (SELECT ... WHERE <all the conditions are met>)
When <all the conditions are met>, the insert will actually have something to insert. Otherwise, it will have an empty result set so no rows will be inserted.
So use INSERT INTO ... SELECT ... WHERE <all the conditions are met> Syntax to achieve desired results. Unfortunately, this solution does not have a way to return back -1.

Select into statement for null or more than one value

I am stuck in plsql , as I have making function in which I have to update a table if only values comes in select into ..
and if not come then not and if multiple comes then have to update and delete for all that values .
In below function if in first select into null value comes then should not goto exception handling should update only CUSTOMER table and only delete from table 3 ,, if one or many values comes then do all update and delete for each value
create or replace FUNCTION FUNCTION_NAME (
from_PARTICIPANT_KEY1 IN NUMBER
)
RETURN
IS
to_participant_key1 NUMBER (11);
BEGIN
SELECT to_participant_key
INTO to_participant_key1
FROM TABLE2
WHERE FROM_PARTICIPANT_KEY = from_PARTICIPANT_KEY1;
UPDATE CUSTOMERS C
SET C.CUSTOMER_STATUS_CD =
NVL (
(SELECT old_status_cd
FROM TABLE1
WHERE PARTICIPANT_UID = from_PARTICIPANT_KEY1
AND participant_cd = 'CUSTOMER'),
C.CUSTOMER_STATUS_CD
)
WHERE C.CUSTOMER_UID = from_PARTICIPANT_KEY1;
UPDATE subscribers C
SET C.STATUS_CD =
NVL (
(SELECT old_status_cd
FROM TABLE1
WHERE PARTICIPANT_UID = to_participant_key1
AND participant_cd = 'SUBSCRIBER'),
C.STATUS_CD
)
WHERE C.account_no = to_participant_key1;
DBMS_OUTPUT.PUT_LINE ('Delete TABLE1 rows');
DELETE FROM TABLE3
WHERE PARTICIPANT_UID = from_PARTICIPANT_KEY1 AND participant_cd = 'CUSTOMER';
DELETE FROM TABLE1
WHERE PARTICIPANT_UID = to_PARTICIPANT_KEY1 AND participant_cd = 'SUBSCRIBER';
COMMIT;
EXCEPTION -- exception handlers begin
WHEN NO_DATA_FOUND THEN -- handles 'division by zero' error
dbms_output.put_line('Customer not found ' || from_PARTICIPANT_KEY1);
WHEN OTHERS THEN -- handles all other errors
dbms_output.put_line('Some other kind of error occurred.');
END;
You can use BULK COLLECT INTO and iterate over collection.
First of all, you have to declare (or use some existing) collection type and create the variable of this type:
TYPE participant_keys is table of number (11);
l_participant_keys participant_keys;
Then, your query will change to:
SELECT to_participant_key
BULK COLLECT INTO to_participant_key1
FROM TABLE2
WHERE FROM_PARTICIPANT_KEY = from_PARTICIPANT_KEY1;
If the query will not return any record then you can check it with COUNT:
if l_participant_keys.COUNT = 0 then
-- update only CUSTOMER table and only delete from table 3
else
FOR I IN l_participant_keys.FIRST .. l_participant_keys.LAST LOOP
--use l_participant_keys(i) do all update and delete for each value
END LOOP;
end if;

Summing the values from the 2nd table based on ID of the 1st table and inserting values in first table

How to in first table where it says UkupnaCena insert sum value of column Cena where RacunID in first table is equal to RacunID in other table. For example if RacunID is equal to 1 in first table, I want its UkupnaCena to be equal to sum of all values in column Cena where RacunID is 1.
Tables:
My procedure so far:
Create procedure sp_RacunUpdate(
#pRacunID int,
#pStatusRacuna nvarchar(50),
#pDatum nvarchar(20),
#pOpis nvarchar(200),
#pMesto nvarchar(50),
#pKupacID int
)
as begin
Declare #pUkupnaCena decimal(20,2)
select #pUkupnaCena=sum(Cena) from Stavka
inner join Racun
on Racun.RacunID=Stavka.RacunID
Where Racun.RacunID=Stavka.RacunID
group by Stavka.RacunID
begin transaction
UPDATE Racun
SET StatusRacuna=#pStatusRacuna, Datum=#pDatum, Opis=#pOpis,Mesto=#pMesto,UkupnaCena=#pUkupnaCena,KupacID=#pKupacID
WHERE RacunID=#pRacunID
IF ##ERROR <> 0
BEGIN
ROLLBACK
END
ELSE
BEGIN
COMMIT
END
END
GO
You can modify the update query to something like this
UPDATE Racun from Racun
SET UkupnaCena=(select sum(Cena) from Stavka s where s.RacunID= Racun.RacunID), Datum=#pDatum, Opis=#pOpis,Mesto=#pMesto,KupacID=#pKupacID
WHERE RacunID=#pRacunID
I believe you want a correlated subquery. In MySQL, this would look like:
UPDATE Racun r
SET StatusRacuna = #pStatusRacuna,
Datum = #pDatum,
Opis = #pOpis,
Mesto = #pMesto,
KupacID = #pKupacID,
UkupnaCena = (SELECT SUM(s.Cena) FROM Stavka s WHERE s.RacunID = r.RacunId)
WHERE RacunID = #pRacunID;
However, your code does not look like MySQL; it looks more like SQL Server. In either database, you can do:
UPDATE Racun
SET StatusRacuna = #pStatusRacuna,
Datum = #pDatum,
Opis = #pOpis,
Mesto = #pMesto,
KupacID = #pKupacID,
UkupnaCena = (SELECT SUM(s.Cena) FROM Stavka s WHERE s.RacunID = Racun.RacunId)
WHERE RacunID = #pRacunID;
The only difference here is removing the table alias in the outer query.

trigger for a compostite key and update another column

I have two tables: threads and threadreply.
threads has a composite primary key, (thread_id,reply_id).
When I insert a new row into threadreply, I need to:
update my column threads.reply_count by adding +1 to the previous value; and
insert data into threadreply by adding +1 to the MAX(reply_id) with same thread_id.
Using the following trigger, I was able to add+1 to my reply_id, but couldn't get to update my reply_count:
CREATE TRIGGER addone BEFORE INSERT ON threadreply
FOR EACH ROW BEGIN
SET NEW.reply_id = (
SELECT IFNULL(
(
SELECT MAX(reply_id) + 1
FROM threadreply
WHERE thread_id = NEW.thread_id
),
1
)
);
END
How can I solve this?
I assume that there is a typo in the question and the composite key (thread_id,reply_id) exists in the threadreply table, not in the threads table.
The trigger might look like:
CREATE TRIGGER addone BEFORE INSERT ON threadreply
FOR EACH ROW BEGIN
SET NEW.reply_id = (
SELECT IFNULL(
(
SELECT MAX(reply_id) + 1
FROM threadreply
WHERE thread_id = NEW.thread_id
), 1
)
);
UPDATE threads SET reply_count = reply_count + 1
WHERE thread_id = NEW.thread_id;
END
/
Take a look at this demo: --> http://www.sqlfiddle.com/#!2/1e7bb/2
The trigger and insert statements are on the left side in the schema window, below are shown results of the demo.

How can i create a trigger that will only update a record if the new record is different from the old record?

Question is create a trigger that will only update a record if the old record is different from the new. Can i get some help please i don't even know how to start the syntax apart from
CREATE TRIGGER update_marketingliste
ON marketing_list FOR UPDATE
AS
BEGIN
SELECT * FROM INSERTED
END
I am not sure what the schema is but the sample code below should help you to understand how this can be done.
SET NOCOUNT ON
GO
CREATE TABLE test(col1 int primary key , col2 int )
go
CREATE TRIGGER trg_test_upd on test
INSTEAD OF UPDATE
AS
BEGIN
IF EXISTS (
SELECT *
FROM Deleted del -- old value
INNER JOIN Inserted ins -- new value
on del.col1 = ins.col1
and del.col2 = ins.col2)
BEGIN
PRINT 'No Update'
RETURN --if old value is same as new value dont update
END
ELSE
BEGIN
UPDATE t1
set col2 = i.col2
from dbo.test t1
inner join inserted i
on t1.col1 = i.col1
END
END
go
Insert into test (col1, col2)
select 10, 10
go
update test
set col2 = 200
where col1 = 10
SELECT *
FROM TEST
--This would not do the update
update test
set col2 = 200
GO
Drop table test
go