I'm not quite figuring out how to do what I'm after.So what I'm making is an online game.When a user buy's a new car I do an INSERT:
$c->query("INSERT INTO user_cars (carid, userid, acc, speed) VALUES ('$buyid','$id','$acc','$speed')");
Now I have another table that I need to insert info to right after the query above FROM the query above.What I need is the carid .The user can have more than 2 cars.What should I do now?
You have multiple options:
You can build a trigger to insert a new row in table2, when row is inserted in the cars table (Read more here http://dev.mysql.com/doc/refman/5.5/en/trigger-syntax.html)
There is this function mysql_insert_id() which returns the last inserted id ( Read more here http://php.net/manual/en/function.mysql-insert-id.php )
If you use PDO , there is a smillar command for it
etc.
This is a basic demonstration of the trigger you would want to create. For illustrative purposes I've also included the ddl and an example insert into your user_cars table to show that another table, which I've called "your_other_table" receives the insert (just the carid value) of an insert going into the user_cars table.
Fiddle:
http://sqlfiddle.com/#!9/f76a7/1/0
(notice how "your_other_tabe" has one row with the carid of the insert into "user_cars", despite having no direct inserts into itself)
delimiter //
create table user_cars
(
carid int,
userid int,
acc int,
speed int,
constraint id_pk primary key (carid, userid)
)//
create table your_other_table
(
carid int
)//
create trigger your_trigger_name before insert on user_cars
for each row begin
insert into your_other_table (carid)
values (new.carid);
end
//
insert into user_cars values
(1, 2, 3, 99)//
delimiter ;
select *
from your_other_table;
Output:
| CARID |
|-------|
| 1 |
This is the only portion of the above sql that creates the trigger:
delimiter //
create trigger your_trigger_name before insert on user_cars
for each row begin
insert into your_other_table (carid)
values (new.carid);
end
//
delimiter ;
Related
I would like to ask for a solution on how to insert n rows based on the values of a field in another table.
Consider the following tables:
CREATE TABLE Input (
ID INT AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(128),
Ticket_Piece INT
);
CREATE TABLE Output (
Ticket_ID INT AUTO_INCREMENT PRIMARY KEY,
Transaction_ID INT,
Ticket_Number VARCHAR(23) UNIQUE,
FOREIGN KEY (Transaction_ID)
REFERENCES Input (ID)
ON UPDATE CASCADE
ON DELETE CASCADE
);
If a row from the Input table has n in the Ticket_Number column, then n rows should be inserted into the Output table, with Ticket_Number having values "ID-1" through "ID-n" (e.g. (4, "D", 5) in Input should result in rows with ticket numbers "4-1" through "4-5" being added to Output). How can rows for Output be generated in a range of numbers based on the Ticket_Piece column using PHP and MySQL?
For example, with the input:
INSERT INTO Input (ID, Name, Ticket_Piece)
VALUES
(1, 'A', 2),
(2, 'B', 1),
(3, 'C', 3)
;
the result should be:
Ticket_ID
Transaction_ID
Ticket_Number
1
1
1-1
2
1
1-2
3
2
2-1
4
3
3-1
5
3
3-2
6
3
3-3
For each row you fetch from the input table, use a for loop to insert multiple rows into the output table.
$res = $pdo->query("SELECT id, ticket_piece FROM Input_Table");
$insert_stmt = $pdo->prepare("INSERT INTO Output_Table (transaction_id, ticket_number) VALUES (:id, :ticket)");
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
$pieces = $row['ticket_piece'];
$id = $row['transaction_id'];
for ($i = 1; $i <= $pieces; $i++) {
$insert_stmt->execute([':id' => $id, ':ticket' => "$id-$i"]);
}
}
A solution in PHP or SQL will likely need to use a loop.
If this comes from the data model rather than business rules (and depending on other factors), a trigger might be a fairly simple option. The trigger body could have a WHILE or other loop to iterate over the ticket piece numbers, and CONCAT to combine the ID and piece number into a ticket number, inserting each in turn.
DELIMITER ;;
CREATE TRIGGER create_ticket_pieces
AFTER INSERT ON Input
FOR EACH ROW
BEGIN
DECLARE piece INT DEFAULT 1;
WHILE piece <= NEW.Ticket_Piece DO
INSERT INTO Output (Transaction_ID, Ticket_Number) Values (NEW.ID, Concat(NEW.ID, '-', piece));
SET piece := piece + 1;
END WHILE;
END;;
DELIMITER ;
An alternative some use is to pregenerate a table of numbers, then join with this table to generate rows:
INSERT INTO Output (Transaction_ID, Ticket_Number)
SELECT Input.ID, Concat(Input.ID, '-', Numbers.Number)
FROM Input
JOIN Numbers ON Numbers.Number <= Input.Ticket_Piece
WHERE ... -- select Input rows
It should be noted that by duplicating information (the transaction ID) in two different columns, the Output table isn't normalized. In particular, it violates 3rd normal form, due to a functional dependency of Transaction_ID on Ticket_Number. The way to resolve this is to leave the transaction ID out of the ticket number field (i.e. Output.Ticket_Number holds only the generated integer ≤ Input.Ticket_Piece). (See: "Third Normal Form: Composite PRIMARY KEY vs System-Generated Surrogate (IDENTITY)")
I have a table that contains many rows, ordered by the field 'seq'.
I have selected rows 6-9 and I want to copy and paste them on row 3 for example.
For that I'd like to create an SQL query that does the following:
INSERT INTO my_table ( seq, field1, field2.... )
SELECT seq, field1,field2..
FROM my_table
WHERE id IN ( 234, 233,232 )
(id field is the auto increment field that identifies my selected rows).
Now - I managed to duplicate the rows into the table.
What is missing is to correctly update the 'seq' field in the following manner :
In the pasted location (3) my rows should contain the values 3,4,5.
All the original rows in that location should be incremented by 3 so that the original row (seq=3) should now become (seq=6) and all rows move 3 rows down the table.
Can this be achieved with an SQL query ?
You can create a trigger which check for seq, if a sequence exists, it will update sequence numbers above it and will.
create table s_sequence
(seq number(3),
name varchar2(2000)
);
create or replace trigger s_seq_order
before insert on s_sequence
for each row
declare
seq_exists varchar2(20);
begin
begin
select 1 into seq_exists from s_sequence where seq = :new.seq;
exception
when NO_DATA_FOUND then
null;
end;
if seq_exists = '1' then
update s_sequence set seq = seq + 1 where seq >= :new.seq;
end if;
end;
inserting (seq, name) with (1, 'A') , (2, 'B') .. (5, 'E')
now insert (2, 'F')
But, I am not sure if this is an appropriate way to deal with order.
but why put any data in table in order ?
PS : This code tested in oracle.
I have a database with two tables. When a user posts an article, it will be inserted into both tables, (2 queries in one file)
I use post_id as foreign key, both tables post_id auto increment. Will foreign keys be messed up? For example if users A and B query the database at the same time.
Table 1
post_id user...
1 A
2 B
Table 2
post_id content...
1 A
2 B
First off you can't have auto increment on both tables.
Usually, what you do is insert in table 1, get the ID of the just inserted row.
Then you use this ID, to insert in table 2 which references table 1.
See: mysqli::$insert_id at
http://www.php.net/manual/en/mysqli.insert-id.php
Example:
$query = "INSERT INTO table1(user,whatever) VALUES ('A','something')";
$mysqli->query($query);
printf ("New Record has id %d.\n", $mysqli->insert_id);
$query = "INSERT INTO table2(post_id,content) VALUES ($mysqli->insert_id,'This is content')";
$mysqli->query($query);
You could also do this using a stored procedure based on: stackoverflow.com/a/1723325/1688441
DELIMITER //
CREATE PROCEDURE new_post_with_content(
user_id CHAR(5), content_text CHAR(100)
BEGIN
START TRANSACTION;
INSERT INTO table1 (user)
VALUES(user_id);
INSERT INTO table2 (post_id, content)
VALUES(LAST_INSERT_ID(), content_text);
COMMIT;
END//
DELIMITER ;
And you call it like so:
CALL new_engineer_with_task('A','This is the content');
Why not use table1 as user table and second with posts?
users
user_id(autoinc) username
1 A
2 B
3 C
posts
post_id(autoinc) user_id posts_text
1 2 text
2 1 other text
I have a MySQL table with an autoincremented primary key, and a column for a person's name, and some data.
Is there a MySQL query where I can insert a new row if the name of the person is unique, but if it's a duplicate name, then I would update that row?
I.e.
ID, Name, Data
1 , Michael, x
2 , Stephen, y
3 , Christopher, z
If I were to add a "Michael" to the database with "qq" data, I would want the database to look like this:
ID, Name, Data
1 , Michael, qq
2 , Stephen, y
3 , Christopher, z
If I were to add "John" with "zz" data, the database would look like this:
ID, Name, Data
1 , Michael, x
2 , Stephen, y
3 , Christopher, z
4 , John, zz
I know of the command, ON DUPLICATE KEY UPDATE, but I only want to update if the name is the same, not if the primary key is the same.
Create a UNIQUE index on Name. ON DUPLICATE KEY UPDATE will then work correctly.
Create a stored procedure and simply call it in your query code
PROCEDURE:
DROP PROCEDURE IF EXISTS InsUpdTable $$
CREATE PROCEDURE InsUpdTable
(
IN _name VARCHAR(45),
IN _data VARCHAR(45)
)
BEGIN
if exists (select ID from mytable where name = _name)
Then
update mytable set data = _data where name=_name;
else
insert into mytable(name, data) values(_name, _data);
END IF;
END $$
DELIMITER ;
Query:
call InsUpdTable('John','zzz')
I have two tables A and B. If I remove a entry in the table A, I want to update the status of the entry in the table B using the user id. I'm using this code:
CREATE TRIGGER blockuserundo BEFORE DELETE ON user_blocked
FOR EACH ROW BEGIN
UPDATE members SET ty_status = '1' WHERE user_id = OLD.block_user_id ;
END;
It shows an error like:
no new row in the trigger delete
Please guide me to write the query for the above scenario.
You need to set the delimiter to something other then ;
DELIMITER |
CREATE TRIGGER blockuserundo BEFORE DELETE ON user_blocked
FOR EACH ROW BEGIN
UPDATE members SET ty_status = '1' WHERE user_id = OLD.block_user_id ;
END;
|
DELIMITER ;
Code below works as expected:
DROP TABLE IF EXISTS user_blocked;
CREATE TABLE user_blocked
(
block_user_id INT
);
DROP TABLE IF EXISTS members;
CREATE TABLE members
(
user_id INT,
ty_status CHAR(1)
);
INSERT user_blocked
VALUES (1),(2),(3),(4),(5);
INSERT members
VALUES (1, '0'),(2, '0'),(3, '0'),(8, '0'),(9, '1');
DELIMITER |
CREATE TRIGGER blockuserundo BEFORE DELETE ON user_blocked
FOR EACH ROW BEGIN
UPDATE members SET ty_status = '1' WHERE user_id = OLD.block_user_id ;
END;
|
DELIMITER ;
SELECT * FROM members;
DELETE FROM user_blocked WHERE block_user_id IN(1,2);
SELECT * FROM members;