SQL Statement INSERT, on duplicate columns UPDATE - php

I have an SQL Table that contains a list of items that users can have linked to their profile. The SQL table looks something like this:
Item_Activity_ID Item_ID User_ID Status Date-Added
1 1 1 1 2015-06-08
2 2 2 1 2015-06-08
3 1 1 0 2015-06-09
The entry shows that someone with the user with id of 1 added item id 1 twice, and the only thing that was changed was the date and status. I want to make it so that when given an INSERT statement such as:
INSERT INTO items (Item_ID, User_ID, Status, Date_Added) VALUES ('$x', '$y', 1, CURDATE()) IF EXISTS SOME Item_ID = $x AND User_ID = $y UPDATE items SET Status = 1, Date_Added = CURDATE() WHERE Item_ID = $x AND User_ID = $y
Item_Activity_ID is an auto_incremented primary key index. How can I accomplish this in one query? Two users can have the same item, but where should never be repeat entries of the same user id and item id.

First, create a unique index for Item_ID, UserID combination,
Then, use the INSERT ... ON DUPLICATE KEY UPDATE statement:
INSERT INTO items (Item_ID, User_ID, Status, Date_Added)
VALUES ('$x', '$y', 1, CURDATE())
ON DUPLICATE KEY UPDATE Status = VALUES(Status), Date_Added = VALUES(Date_Added))
P.S. make sure to sanitize $x and $y to prevent SQL injections!

I would start by adding a unique key index:
ALTER TABLE items
ADD CONSTRAINT uc_UserItem UNIQUE (Item_ID,User_ID);
Then, you can just modify your insert query:
INSERT INTO items (Item_ID, User_ID, Status, Date_Added) VALUES ('$x', '$y', 1, CURDATE()) ON DUPLICATE KEY UPDATE Status=VALUES(1), Date_Added=VALUES(CURDATE());

Try to perform the update first supposing that the user and item already exist. Then check if this update affects any rows (using ##rowcount, in SQL Server).
If not then perform an insert.
Don't forget to put the above two statements in a transaction... ;)

Normal way would be to set a composite constraint at the db level. If you are using mysql and phpmyadmin you do this in the table structure view.
Check both fields (I guess 'user_id' and 'item_id') and click the 'unique' button.
After that is set you can just append
ON DUPLICATE KEY UPDATE status =1, date_added=CURDATE().
It will update the row that violated the constraint you created

Related

Insert rows on one table based on the values of a field of another table in PHP-MySQL

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)")

how to insert a new record in a table that has foreign key attributes in mysql

What is wrong in this statement since customers table has only one record
INSERT INTO CART (Cartid,custid,Pid)
VALUES ('2',SELECT(custid from CUSTOMERS), SELECT (Pid from Products where Pname ='shirts'))
Make sure that the cart table id is primary key and auto_increment. Get the customer id and store in a variable. You can try something similar like this
INSERT INTO CART (Cartid,custid,Pid) VALUES ('', SELECT custid from CUSTOMERS WHERE custid = '$customer_id'),(SELECT Pid FROM Products WHERE Pname = 'shirts' LIMIT 1));
The correct syntax is:
INSERT INTO CART (Cartid, custid, Pid)
VALUES (2,
(SELECT custid FROM CUSTOMERS LIMIT 1),
(SELECT Pid FROM Products WHERE Pname = 'shirts' LIMIT 1)
);
Your parentheses are in the wrong place.
Notes:
I added the LIMIT just to enforce that one row is returned.
I removed the single quotes around '2', because ids are usually number.
You probably should not be inserting the id; it should be an auto-increment column.

copy all rows with matching field value

I would like to copy all mysql rows with a matching field value into a new row and change one field.
So I have a mysql table with the following fields
`lessonplan`, `group`, `category`, `sort_id`, `item`
So I want to copy all rows that have lessonplan=10 and set change the value of lessonplan to 11 for all new rows. Lesson plan is not an auto increment field.
What is best practice for a scenario like this one?
INSERT INTO tableName( lessonplan, `group`, category, sort_id, item )
SELECT 11, `group`, category, sort_id, item
FROM tableName
WHERE lessonplan = 10

SQL Query for fetching the data of users not submitting their time for a particular week?

I have two tables one containing user information and the other having their time entered for the weeks as below!
Table1
------
UserID (PK)
Username
Email
Phone
Table2
------
Timesheetid (PK)
UserID (FK)
Weekenddate(date)
Totaltimeworked
From the above tables I want to retrieving the user ID,username and email from TABLE 1 for the user who have not entered information in the table 2 based on the weekend date(weekend date is selected in the search field and not hardcoded).
Please help me with the SQL query to create this table .
Try this working code on SQL Fiddle. As you haven't posted any data and columns definition I assume weekenddate to be a varchar.
On the condition Weekenddate = 'sunday' OR Weekenddate = 'saturday' substitute the values sunday and saturday by your parameter value. In fact, you will only need to use on of the clauses of the condition as you have only one parameter with the weekend value. Then just wrap the code into an
`INSERT INTO your_new_table (UserID, Username)`
Considering your Totaltimeworked column is up to date:
CREATE TABLE newTable(
UserID int not null,
Weekenddate date not null,
FOREIGN KEY(UserID) REFERENCES Table1(UserID)
ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO newTable (UserID, Weekenddate)
(SELECT (UserID, Weekenddate) FROM Table2 WHERE Totaltimeworked > 0);
Or if you meant just for 1 specific week don't add the Weekenddate to newTable and modify query as
INSERT INTO newTable (UserID)
(SELECT (UserID) FROM Table2 WHERE Totaltimeworked > 0
AND Weekenddate = 'year-month-day');

INSERT on update. Compound Key

I have a question on This MySQL statement.
I got this from this post
However, I am not sure how to structure the query when I have the table like this.
TableA
--------
id ==> Auto Increment field
question_id
form_id
member_id
event_id
admin_id
desc
is_cand_field
c_field_id
In this, question_id, form_id, memmber_id, event_id, admin_id can be same. desc, is_cand_field, c_field_id can change. When inserting, I want to check if this combination exists. If exists, I want to update the last 3 fields. If not, I want to insert a record.
Is this possible with the above referred query. Its not clear from the page.
Add unique key on combination of these fields:
ALTER TABLE `tablea` ADD UNIQUE INDEX `compound_key` (`question_id`, `form_id`, `member_id`, `event_id`, `admin_id`);
Insert values and add update section:
INSERT INTO tablea (`question_id`, `form_id`, `member_id`, `event_id`, `admin_id`, `desc`, `is_cand_field`, `c_field_id`)
VALUES (1, 2, 3, 4, 5, 1, 0, 1)
ON DUPLICATE KEY UPDATE `desc` = VALUES(`desc`), is_cand_field = VALUES(`is_cand_field`), c_field_id = VALUES(`c_field_id`)
You can add multiple rows in the ON DUPLICATE KEY UPDATE section.
INSERT INTO TableA (form_id, member_id, event_id, admin_id, desc, is_cand_field, c_field_id)
VALUES (2, 3, 4, 5, 'b', 0, 1)
ON DUPLICATE KEY UPDATE desc='a', is_cand_field=1, c_field_id=2

Categories