Mysql trigger with joins - mysql

I have three MYSQL tables that all relate to each other as you can see below.
I'm currently storing the dateofjob twice because i do not know how to create table joins in a trigger. Currently i'm using this trigger on the specimen details table
CREATE TRIGGER `NewAge_update` BEFORE UPDATE ON `Speciemn_Details`
FOR EACH ROW BEGIN
SET NEW.Due_Date = DATE_ADD(NEW.CastDate,INTERVAL NEW.Age DAY);
END
And this is working perfectly, but i want to be able to remove the column dateofjob from the specimen details table and calculate the duedate from the Job_Details table to save myself from having double data.
I will have to join the job_details.ID with the Test_Details.PARENTID and the Test_Details.TESTID with the specimen_details.TESTID, I just don't know how to do this inside a trigger. any help would be appreciated greatly
I've attempted to be as detailed as possible BUT If anymore information is required please ask me
Job_Details
+----+-----------+
| ID | dateofjob |
+----+-----------+
| 1 | 1/01/2015 |
| 2 | 1/01/2016 |
| 3 | 1/01/2017 |
+----+-----------+
Test_Details
+----------+--------+--------------+
| ParentID | TestID | TestLocation |
+----------+--------+--------------+
| 2 | 2154 | Barn |
| 2 | 2155 | Barn |
| 1 | 8055 | Yard |
+----------+--------+--------------+
Specimen_Details
+--------+----------+---------+-----------+-----------+
| TestID | Specimen | TestAge | dateofjob | Duedate |
+--------+----------+---------+-----------+-----------+
| 2154 | A | 3 | 1/01/2016 | 4/01/2016 |
| 2154 | B | 8 | 1/01/2016 | 9/01/2016 |
| 8055 | A | 2 | 1/01/2015 | 3/01/2015 |
+--------+----------+---------+-----------+-----------+

Joins inside trigger code really aren't any different from joins in any other procedural code, except that you can't query the triggering table and you instead have the OLD and NEW pseudorecords. If I've understood your description, you want to do something like
CREATE TRIGGER `NewAge_update` BEFORE UPDATE ON `Specimen_Details`
FOR EACH ROW
BEGIN
DECLARE jobdate DATE;
SELECT dateofjob
INTO jobdate
FROM job_details j, test_details t
WHERE j.ID = t.ParentID
AND t.TestID = NEW.TestID;
SET NEW.Duedate = DATE_ADD(jobdate, INTERVAL NEW.TestAge DAY);
END;
(Don't forget that trigger bodies are procedural, so you don't have to do everything in a single statement.)

Related

When inserting new record in existing table tt goes up instead of down

I have already created table I want to add extra row when adding extra row the created extra row goes up. I want that row at the bottom.
MariaDB [armydetails]> insert into armydetails values('r05','Shishir','Bhujel','Jhapa','9845678954','male','1978-6-7','1994-1-3','ran5','Na11088905433');
Query OK, 1 row affected (0.17 sec)
MariaDB [armydetails]> select * from armydetails;
+-------+---------+---------+-----------+------------+--------+------------+------------+--------+----------------+
| regNo | fName | lName | address | number | gender | DOB | DOJ | rankID | accountNo |
+-------+---------+---------+-----------+------------+--------+------------+------------+--------+----------------+
| r05 | Shishir | Bhujel | Jhapa | 9845678954 | male | 1978-06-07 | 1994-01-03 | ran5 | Na11088905433 |
| ro1 | Milan | Katwal | Dharan | 9811095122 | Male | 1970-01-03 | 1990-01-01 | ran1 | Na11984567823 |
| ro2 | Hari | Yadav | Kathmandu | 9810756436 | male | 1980-06-07 | 2000-05-06 | ran2 | Na119876678543 |
| ro3 | Khrisna | Neupane | Itahari | 9864578934 | male | 1980-02-02 | 2001-01-07 | ran3 | Na11954437890 |
| ro4 | Lalit | Rai | Damak | 9842376547 | male | 1989-05-09 | 2005-01-02 | ran4 | Na11064553221 |
+-------+---------+---------+-----------+------------+--------+------------+------------+--------+----------------+
5 rows in set (0.00 sec)
MariaDB [armydetails]>
The SQL 2011 publication from ISO/IEC 9075 says:
In general, rows in a table are unordered; however, rows in a table are ordered if the table is the result of a that immediately contains an « order by clause ».
In a SQL database, there is no underlying, default ordering for records. A relational database basically stores a table as a bunch of unordered records.
When records are SELECTed without an ORDER BY clause, they come out in an undefined order, that in no way is guaranteed to be consistent over subsequent queries (including the very same query being executed several times). This is true for MySQL and for other RDBMS.
The only way to properly order records is to use an ORDER BY clause, like:
select * from armydetails order by regNo
Suggested lecture: Tom Kyte Blog : Order in the Court!.
You can simply add an ORDER BY clause to your statment as follows:
SELECT * FROM armydetails ORDER BY regNO DESC;

MySQL query to fetch rows from different table with multiple rows into respective column

We have two tables as below:
Table-1 Name: apprecord
---------------------------------------
appid | desc | status
ALT01 | this is first | Open
ALT02 | this is second | Open
ALT03 | this is third | Closed
---------------------------------------
Table-2 Name: question
-----------------------------------------------
appid | questionseq | ques | ans
ALT01 | 1 | how are you | good
ALT01 | 2 | are you fine | yes
ALT02 | 1 | how was your day | great
ALT02 | 2 | are you coming today | yes
ALT03 | 1 | where are you | at home
ALT03 | 2 | are you fine | yes
--------------------------------------------------
How can I write a MySQL query so that I can get the result as below:
----------------------------------------------------------------------------------------
appid | desc | status| QUES1 | ANS1 | QUES2 | ANS2
ALT01 | this is first | Open | how are you | good | are you fine | yes
ALT02 | this is second| Open | how was your day| great | are you coming today | no
ALT03 | this is third | Closed| where are you | at home| are you fine | yes
---------------------------------------------------------------------------------------
Here QUES1, ANS1, QUES2, ANS2 are hardcoded/fixed column headers.
Try this:
Sample data:
create table apprecord(appid varchar(10),desc varchar(100),status varchar(10));
insert into apprecord values
('ALT01','this is first','Open'),
('ALT02','this is second','Open'),
('ALT03','this is third','Closed');
create table question(appid varchar(10),questionseq int,ques varchar(100),ans varchar(10));
insert into question values
('ALT01',1,'how are you','good'),
('ALT01',2,'are you fine','yes'),
('ALT02',1,'how was your day','great'),
('ALT02',2,'are you coming today','yes'),
('ALT03',1,'where are you','at home'),
('ALT03',2,'are you fine','yes');
T-SQL:
select ar.appid,
`desc`,
`status`,
q1.ques ques1,
q1.ans ans1,
q2.ques ques2,
q2.ans ans2
from apprecord ar
left join (select appid, ques, ans from question where questionseq = 1) q1
on ar.appid = q1.appid
left join (select appid, ques, ans from question where questionseq = 2) q2
on ar.appid = q2.appid
This is standard pivoting, although it can be dane as above, using two joins :)

Select value from table sorted by a certain order from another table

I want to select value from table sorted by a certain order.
I have a table called test that looks like this:
| date | code | value |
+----------+-----------+----------+
| 20050104 | 000005.SZ | -6359.19 |
| 20050104 | 600601.SH | -7876.34 |
| 20050104 | 600602.SH | -25693.3 |
| 20050104 | 600651.SH | NULL |
| 20050104 | 600652.SH | -15309.9 |
...
| 20050105 | 000005.SZ | -4276.28 |
| 20050105 | 600601.SH | -3214.56 |
...
| 20170405 | 000005.SZ | 23978.13 |
| 20170405 | 600601.SH | 32212.54 |
Right now I want to select only one date, say date = 20050104, and then sort the data by a certain order (the order that each stock was listed in the stock market).
I have another table called stock_code which stores the correct order:
+---------+-----------+
| code_id | code |
+---------+-----------+
| 1 | 000002.SZ |
| 2 | 000004.SZ |
| 3 | 600656.SH |
| 4 | 600651.SH |
| 5 | 600652.SH |
| 6 | 600653.SH |
| 7 | 600654.SH |
| 8 | 600602.SH |
| 9 | 600601.SH |
| 10 | 000005.SZ |
...
I want to sorted the selected data by stock_code(code_id), but I don't want to use join because it takes too much time. Any thoughts?
I tried to use field but it gives me an error, please tell me how to correct it or give me an even better idea.
select * from test
where date = 20050104 and code in (select code from stock_code order by code)
order by field(code, (select code from stock_code order by code));
Error Code: 1242. Subquery returns more than 1 row
You told us that you don't want to join because it takes too much time, but the following join query is probably the best option here:
SELECT t.*
FROM test t
INNER JOIN stock_code sc
ON t.code = sc.code
WHERE t.date = '20050104'
ORDER BY sc.code_id
If this really runs slowly, then you should check to make sure you have indices setup on the appropriate columns. In this case, indices on the code columns from both tables as well as an index on test.date should be very helpful.
ALTER TABLE test ADD INDEX code_idx (code)
ALTER TABLE test ADD INDEX date_idx (date)
ALTER TABLE code ADD INDEX code_idx (code)

SQL join several tables based on latest entry in transaction table per join record

I have a transaction table with timestamps
a transaction has one event and one user.
All transactions have an event,
All events have at least one trasaction,
Each transaction has a user that must exist,
A User will not necessarily have a transaction.
The output will be a sort of the evt list
Output line count should equal db.evt record count.
The first column of each table is the Autoinc unique index.
In transaction, these are fks to the other tables.
The problem is that I need the transaction with the latest timestamp for the evt in the transaction table.
I am still relatively new to SQL (Using MySQL) and while I muddle through joins. I have no idea how to get the latest record by evID by timestamp.
I have looked at other questions on the topic but not found one that addresses mine. (Granted there are 14K on Joins alone, so I may have missed one)
Sample Table Data below:
Table structure is hopefully obvious by I will edit it in if requested.
Edit:
I've changed the names of tables and columns for clarity (and to avoid matching keywords)
I tried Stuart's answer below and got an error:
Answer:
SELECT
eventTable.EvtName AS EvtD,
transTable.TranAct AS LastTrans,
userTable.UserName AS UsrNm
FROM
transTables,
INNER JOIN (
SELECT evtID, MAX(TransID) TransID FROM transTable GROUP BY evtID
) last ON last.evtID = transTable.evtID AND last.TransID = transTable.TransID
INNER JOIN eventTable ON eventTable.evtID = transTable.evtID
INNER JOIN userTable ON userTable.usId = transTable.usId
Response:
#1064 - You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax to use near
'INNER JOIN (
SELECT evtID, MAX(TransID) TransID FROM transTable GROUP BY evt'
at line 7
Tables:
db.transTable
| TransID | EvtID | TranAct | timestamp | UserID
----------------------------------------------------------------
| 1 | 1 | add | 2014-05-08 08:10:00.000 | 3
| 2 | 2 | add | 2014-05-08 09:10:00.000 | 2
| 3 | 3 | add | 2014-05-08 10:10:00.000 | 3
| 4 | 2 | validate | 2014-05-08 11:10:00.000 | 5
| 5 | 3 | validate | 2014-05-08 12:10:00.000 | 3
| 6 | 2 | reverse | 2014-05-08 13:10:00.000 | 1
| 7 | 1 | edit | 2014-05-08 14:10:00.000 | 4
| 8 | 4 | add | 2014-05-08 15:10:00.000 | 3
| 9 | 5 | add | 2014-05-08 16:10:00.000 | 2
db.eventTable
| EvtID | EvtName
-----------------
| 1 | Evt1
| 2 | Evt2
| 3 | Evt3
| 4 | Evt4
| 5 | Evt5
db.userTable
| UserID | UserName
--------------------
| 1 | Usr1
| 2 | Usr2
| 3 | Usr3
| 4 | Usr4
| 5 | Usr5
Desired output:
eventTable.EvtName AS EvtD
transTable.TranAct AS LastTrans
userTable.UserName AS UsrNm
| EvtD | LastTrans | UsrNm
--------------------------
| Evt1 | edit | Usr4
| Evt2 | reverse | Usr1
| Evt3 | validate | Usr3
| Evt4 | add | Usr3
| Evt5 | add | Usr2
Much thanks for any assistance.
Something like this shuold work where a derived table is used to eliminate all transactions except the latest per evId.
SELECT
eventTable.EvtName AS EvtD,
transTable.TranAct AS LastTrans,
userTable.UserName AS UsrNm,
FROM
transTable
INNER JOIN (
SELECT evId, MAX(UID) uid FROM transTable GROUP BY evId
) last ON last.evId = transTable.evId AND last.uid = transTable.uid
INNER JOIN eventTable ON eventTable.evId = transTable.evId
INNER JOIN userTable ON userTable.usId = transTable.usId

mySQL cross table field linking

Basically I have two tables A and B. These are linked by unique ID's where the entries in B point to one entry in A. The entries in A and B also have a 'status' field denoting if the entry is active or not...
My questions is therefore; is it possible to link the status field of the entries in B and have them update, every time the 'status' field in A (pointed to by the unique ID) is updated? I could do this fairly easy with an SQL command however I'm wondering if there is a more automatic solution. Example:
table A
|------ID------|----status----|
| 1 | on |
| 2 | on |
|---------------|----------------|
table B
|-----eID------|------ID------|----status----|
| 1 | 1 | on |
| 2 | 1 | on |
| 3 | 2 | on |
|---------------|---------------|----------------|
I then run:
UPDATE `A` SET `status` = 'off' WHERE `ID` = 1;
And the result would be:
table A
|------ID------|----status----|
| 1 | off |
| 2 | on |
|---------------|---------------|
table B
|-----eID------|------ID------|----status----|
| 1 | 1 | off |
| 2 | 1 | off |
| 3 | 2 | on |
|---------------|---------------|----------------|
Is that possible?
Many Regards,
Andreas
i hope this trigger code can help u.
CREATE TRIGGER `abc` AFTER UPDATE ON `tablea` FOR EACH ROW BEGIN UPDATE tableb SET STATUS = new.status WHERE id = new.id;
END