Nested sql insert from php - mysql

I have a nested array in php and I'm trying to insert data into a mysql table only if a duplicate does not exist. The duplicate should only check match against the sensor_serial and dates field. I'm having no luck with DUPLICATE as the id is unique regardless of the other fields. this is the table layout:
CREATE TABLE IF NOT EXISTS `temps_test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`sensor_serial` varchar(64) COLLATE latin1_general_ci DEFAULT NULL,
`temp_c` float DEFAULT NULL,
`dates` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `date` (`dates`)
)
This is my non working code. I can't seem to get it quite right.
foreach ($output as $k => &$v) {
$sql = "INSERT INTO temps_test (sensor_serial,temp_c,dates) VALUES ('$v[7]','$v[3]','$v[5]') WHERE NOT EXISTS (SELECT * FROM temps_test WHERE sensor_serial='$v[7]' AND dates='$v[5]')";
$go = mysql_query($sql) or die( mysql_error() );
}
Can this be done this way or is my approach totally off?

Try using ON DUPLICATE KEY UPDATE
INSERT INTO temps_test (sensor_serial,temp_c,dates)
VALUES ('val1','val2','val3')
ON DUPLICATE KEY UPDATE sensor_serial=sensor_serial;
make sure to add constraint on field sensor_serial, example
CREATE TABLE IF NOT EXISTS `temps_test`
(
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`sensor_serial` varchar(64) COLLATE latin1_general_ci DEFAULT NULL,
`temp_c` float DEFAULT NULL,
`dates` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `date` (`dates`),
CONSTRAINT t_uq INIQUE (`sensor_serial`) -- <== this one
)

Related

Is it possible to make a batch insert/update if the uniqueness of the record is a bundle of two fields?

I have the following table structure (example)
CREATE TABLE `Test` (
`id` int(11) NOT NULL,
`order_id` int(11) NOT NULL,
`position_id` int(11) NOT NULL,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`price` decimal(10,2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE `Test` ADD PRIMARY KEY (`id`);
ALTER TABLE `Test` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
This table contains data that is constantly in need of updating. There is also new data that needs to be entered. Since there is a lot of data, it will take quite a long time to check each record to make it insert or update.
After studying the question, I realized that I need to use batch insert/update with:
INSERT on DUPLICATE KEY UPDATE
But the documentation says that the fields must have a unique index. But I don't have any unique fields, I can't use the ID field. The uniqueness of the record can only be in a combination of two fields order_id and position_id.
Is it possible to make a batch insert/update if the uniqueness of the record is a bundle of two fields?
You need a composite primary-key. You also don't need your AUTO_INCREMENT id column, so you can drop it.
Like so:
CREATE TABLE `Test` (
`order_id` int NOT NULL,
`position_id` int NOT NULL,
`name` varchar(255) NOT NULL COLLATE utf8mb4_unicode_ci,
`price` decimal(10,2) NOT NULL,
CONSTRAINT PK_Test PRIMARY KEY ( `order_id`, `position_id` )
) ENGINE=InnoDB
Then you can use INSERT ON DUPLICATE KEY UPDATE.

Get data of table with some data from other table

I have a simple table visitor and another table visitor_tokens.
SQL creation script of visitor:
CREATE TABLE `visitor` (
`id` int(7) UNSIGNED NOT NULL,
`phone` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
ALTER TABLE `visitor`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `phone_index` (`phone`);
ALTER TABLE `visitor`
MODIFY `id` int UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;
INSERT INTO `visitor` (`phone`) VALUES
('111111111');
SQL creation script of visitor_tokens:
CREATE TABLE `visitor_tokens` (
`id` int(7) UNSIGNED NOT NULL,
`visitor` int(7) UNSIGNED NOT NULL,
`token` varchar(100) COLLATE utf8mb4_general_ci NOT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
ALTER TABLE `visitor_tokens`
ADD PRIMARY KEY (`id`);
ALTER TABLE `visitor_tokens`
MODIFY `id` int UNSIGNED NOT NULL AUTO_INCREMENT;
INSERT INTO `visitor_tokens` (`visitor`, `token`) VALUES
(1, 'abc_token'),
(1, 'xyz_token');
I want to get some data of visitor by id:
I want to get the phone number (phone column) and the visitor tokens (visitor_tokens.token). All - according to given id.
My current SQL script is: SELECT visitor.phone, visitor_tokens.token FROM visitor JOIN visitor_tokens ON visitor_tokens.visitor=visitor.id WHERE id=1. This gives me only the phone and the first token: abc. But I also want to get the tokens of the visitor from the second table. To get something like [abc_token, xyz_token]. How can I do it?
So this is my solution (also recommend on reading the main comments):
SELECT visitor.phone, GROUP_CONCAT(visitor_tokens.token) AS tokens FROM visitor LEFT JOIN visitor_tokens ON visitor_tokens.visitor=visitor.id WHERE visitor.id=1 LIMIT 1;
It returns result regardless of missing visitor tokens (LEFT JOIN), and also if there are tokens - it returns the tokens separated by comma in one row.

Keeping last seen values in a summary table

I have two tables:
parameters keeps all the para_ids and their names and is always updated to have all parameters in it.
CREATE TABLE `parameters` (
`para_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`para_id`),
UNIQUE KEY `idx_parameters_name` (`name`)
) ENGINE=InnoDB;
processing is holding a chunk of data every 5 minutes.
CREATE TABLE `processing` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`t_ns` bigint(20) unsigned NOT NULL DEFAULT '0',
`para_id` int(10) unsigned NOT NULL DEFAULT '0',
`value` varchar(1024) NOT NULL DEFAULT '',
`isanchor` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `data` (`para_id`,`t_ns`)
) ENGINE=InnoDB;
I want to keep a table actual_values with the last seen values that each parameter (if it occurred in processing) had. The para_ids are updated with an INSERT IGNORE before the update. Currently I have those queries:
INSERT IGNORE INTO actual_values (para_id) (SELECT DISTINCT para_id FROM parameters);
UPDATE actual_values a
JOIN processing p ON a.para_id = p.para_id
SET a.value = (SELECT p.value FROM processing p WHERE a.para_id = p.para_id ORDER BY t_ns DESC LIMIT 1);
I feel like this is not the optimal way to go, it takes quite long. Do you guys have better suggestions?

Cannot add foreign key constraint when value is NULL?

I using CodeIgniter for develop my application, I have insert a constraint for this table:
Appointments
CREATE TABLE IF NOT EXISTS `appointments` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`GroupID` int(11) NOT NULL,
`book_datetime` datetime DEFAULT NULL,
`start_datetime` datetime DEFAULT NULL,
`end_datetime` datetime DEFAULT NULL,
`notes` text,
`hash` text,
`is_unavailable` tinyint(4) DEFAULT '0',
`guid_users_provider` char(36) DEFAULT NULL,
`guid_users_customer` char(36) DEFAULT NULL,
`guid_services` char(36) DEFAULT NULL,
`id_google_calendar` text,
`resources_guid` char(36) DEFAULT NULL,
`data` int(11) NOT NULL,
`lastUpdated` varchar(36),
PRIMARY KEY (`id`),
KEY `guid_users_customer` (`guid_users_customer`),
KEY `guid_services` (`guid_services`),
KEY `guid_users_provider` (`guid_users_provider`),
KEY `resources_guid` (`resources_guid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
Resources
CREATE TABLE IF NOT EXISTS `resources` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`GUID` char(36) NOT NULL UNIQUE,
`descrizione` varchar(255) NOT NULL,
`sigla` varchar(255) NOT NULL,
`planning` varchar(255) NOT NULL,
`hex_color` varchar(255) NOT NULL,
`data` int(11) NOT NULL,
`lastUpdated` varchar(36),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
This is the constraint:
ALTER TABLE `appointments`
ADD CONSTRAINT `appointments_ibfk_5` FOREIGN KEY (`resources_guid`) REFERENCES `resources` (`GUID`) ON DELETE CASCADE ON UPDATE CASCADE;
The schema is builded correctly, but the problem is when I try to insert a record through my application, in particular the field resource_guid sometimes is NULL. Now, if I insert a record in PhpMyAdmin for test, in the appointments table and set the resource_guid as empty the record is added succesfully, but when I insert the record from my application on CodeIgniter I get this error:
Cannot add or update a child row: a foreign key constraint fails (scheduler.appointments, CONSTRAINT appointments_ibfk_5 FOREIGN KEY (resources_guid) REFERENCES resources (GUID) ON DELETE CASCADE ON UPDATE CASCADE)\",\"previous\":null,\
Now this is the content array of the query:
array(12) {
["guid_users_provider"]=>
string(36) "EE36D621-5E29-4674-81CB-B98622153E0C"
["start_datetime"]=>
string(19) "2015-12-30 23:19:00"
["end_datetime"]=>
string(19) "2015-12-31 00:45:00"
["notes"]=>
string(0) ""
["resources_guid"]=>
string(4) "null"
["is_unavailable"]=>
bool(false)
["guid_users_customer"]=>
string(36) "CDB8C010-7E51-4478-A341-F077E0460C88"
["guid_services"]=>
string(36) "31C40686-D72C-4361-B211-DCB2223552A9"
["book_datetime"]=>
string(19) "2015-12-31 01:12:39"
["hash"]=>
string(32) "5a9882faec12ab5bacb3445382176463"
["lastUpdated"]=>
string(27) "31-12-2015 10:12:39.5659760"
["GroupID"]=>
int(1)
}
How you can see the field resource_guid is NULL. Now the thing that I don't understand is (If I insert this in PhpMyAdmin as resource_guid set to NUll, so empty field, no error will be displayed, also from my application the error above appear).
This array is passed to the insert method of CodeIgniter like this:
if(!$this->db->insert('appointments', $appointment))
{
throw new Exception("Can't add record=> " . $this->db->_error_message());
}
How I can insert the resource also when is NULL? I mean, in my db table structure there is no renstriction for null value, infact in the appointments table is set with DEFAULT NULL. Someone could help me?
In your Appointments Table, you have given default value as NULL
Instead, give empty value as DEFAULT.
resources_guid` char(36) NOT NULL DEFAULT ''
To make an Existing Column as NOT NULL use MODIFY
ALTER TABLE Appointments MODIFY resources_guid char(36) NOT NULL DEFAULT ''
Look at your input resources_guid
["resources_guid"]=> string(4) "null"
It's a string with value "null", not a boolean NULL.
Pls check how you created that input. Make sure that is returning an actual NULL value. If you don't have control on that, you may need to change it manually by this way: (assuming the array as $appointment)
if($appointment["resources_guid"] == "null") {
$appointment["resources_guid"] = NULL;
}
Regarding the FOREIGN KEY, it should work as you have set it. There should be no problem for NULL values in the child field (unless the field is set as NOT NULL).

MySQL On Duplicate Key Update

It is only allowing me to update resulting in a total of 2
Heres my Table
CREATE TABLE `cart` (
`id` int(7) NOT NULL AUTO_INCREMENT,
`User` int(7) DEFAULT NULL,
`Product` varchar(100) DEFAULT NULL,
`Quantity` int(7) DEFAULT NULL,
UNIQUE KEY `id` (`id`),
UNIQUE KEY `Quantity` (`Quantity`)
)
Then, my code to insert the data is:
$a = '1'
query2 = " INSERT INTO CART(User, Product,Quantity)
VALUES
('$id','$model_number','$a')
ON DUPLICATE KEY UPDATE Quantity=Quantity+1";
It will work when I Add the data to the database but, upon my second attemp I get this error:
Duplicate entry '2' for key 'Quantity'
You probably don't want this line:
UNIQUE KEY `Quantity` (`Quantity`)
That creates a unique constraint on the quantity field, which is why your second insert is failing. I can't think of any reason why you would want that.
P.S. If you remove that line, make sure to remove the comma (,) from the previous line.