Database - Entry with length of strings - Structure? - mysql

i'm relaunching a website a found these entries in one of the database tables. I'm wondering what format it is and how i can easily recreate data of a form into this format:
CREATE TABLE IF NOT EXISTS `phpwcms_formresult` (
`formresult_id` int(11) NOT NULL AUTO_INCREMENT,
`formresult_pid` int(11) NOT NULL DEFAULT '0',
`formresult_createdate` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`formresult_ip` varchar(50) NOT NULL DEFAULT '',
`formresult_content` mediumtext NOT NULL,
PRIMARY KEY (`formresult_id`),
KEY `formresult_pid` (`formresult_pid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
One entry looks like this:
(3179, 7, '2013-10-02 09:35:48', ':11', 'a:14:{s:13:"veranstaltung";s:4:"name";s:11:"Nick Habbel";s:22:"erziehungsberechtigter";s:12:"Petra Habbel".....;}');
In front of every string there is the length of the string "s:22: ...". What kind of format is this?
Any hint is much appreciated. Thanks!

An example of this value is done by the serialization of an array in php:
$arr = array("name"=>"Nick Habbel");
echo serialize($arr);
# output:
# a:1:{s:4:"name";s:11:"Nick Habbel";}
So, the application that inserts data in your table seems to serialize an array before the insertion. In your example an array (a) with a cardinality of 14 elements (a:14:) plus key/values with lengths and type "s" for strings, "i" for integers etc (s:13:"veranstaltung")

Related

Using json blob field attributes in MySQL where clause

I am using MySQL 5.7 and have a table with following schema
CREATE TABLE `Test` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'primary key',
`created_by` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
`status` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
`metadata` blob COMMENT 'to capture the custom metadata',
`created_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'
And the sample row data for the table looks like this
1234,user1,open,"{'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}",2021-05-18 16:01:25
I want to select rows from this table based on the keys in json blob field metadata; for example, let's say where key1 = 'value1'. So I tried something like this
select * from `test` where metadata->>"$.key1" = "value1";
But I got this error Cannot create a JSON value from a string with CHARACTER SET 'binary'. So I casted it to json first by something like below
select JSON_EXTRACT(CAST(metadata as JSON), "$") as meta from test;
The problem is this returns base64 encoded string and when I try to decode the same using FROM_BASE64 like below I get null values in the column.
select FROM_BASE64(JSON_EXTRACT(CAST(metadata as JSON), "$")) as meta from test;
So I think I have two problems here: the first one being how to decode the base64 encoded data which I get after casting blob as json, and second how to filter the rows based on keys in the metadata field.
I do feel this as a design error where the most ideal data type should have been json but since this is how it is now, I need some way to workaround this.
Edit
I also tried following as suggested in one of the comments
select cast(convert(cast(metadata as char) using utf8) as json) from test;
but I get this error
Data truncation: Invalid JSON text in argument 1 to function cast_as_json: "Missing a name for object member." at position 1
Is there any way I can work around this ?

OCaml - Timestamp field anomaly with ocaml-mysql

I'm having issues executing the following MySQL statement with the ocaml-mysql (latest version) library:
let dump_to_db text =
let insert = P.create db (s "INSERT INTO Temperature VALUES (?,?,?,?)") in
ignore (P.execute insert [| "NULL"; "xxx.xxx.xxx.xxx"; text ; "CURRENT_TIMESTAMP" |])
My problem is that the timestamp field is not set correctly. Apparently, whatever I write into the last field (might it be "CURRENT_TIMESTAMP" or simply "NULL"), I'm not able to get the proper outcome.
What happens is that the query get executed and what I see inside the table is a NULL-filled Timestamp field (even tho I have no idea how it can be possible because is defined as a NOT NULL column).
My table structure follows:
CREATE TABLE `Temperature` (
`ID` bigint(20) NOT NULL AUTO_INCREMENT,
`IP` varchar(100) DEFAULT NULL,
`Value` varchar(100) DEFAULT NULL,
`Timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
Prepared.execute takes array with values not arbitrary expressions (function calls). String value "CURRENT_TIMESTAMP" gets converted into timestamp and as it is not recognized as valid number is turned into zero.
Pass NULL properly and it will be default initialized according to CREATE TABLE :
P.execute_null insert [| None; Some "xxx.xxx.xxx.xxx"; Some text ; None |]

Subquery result returning comma separated values using IN clause MySQL

Friends,
two tables one table is
CREATE TABLE `vbw_push_notifications` (
`push_notification_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Primary key ,Auto increment field',
`push_notification_customer_ids` text NOT NULL COMMENT 'comma separated customer id list which was used for messaging/related customers/broadcasting',
`push_notification_message` varchar(500) NOT NULL COMMENT 'The notification message.(A new message from Veebow/A new message from <Merchant Name>/A new public deal <Deal Name> from <Merchant Name>/A new game deal <Deal Name> from <Merchant Name>',
`push_notification_time` datetime NOT NULL,
`push_notification_is_processed` tinyint(4) NOT NULL,
PRIMARY KEY (`push_notification_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 COMMENT='The comma separated customer ids of the customers who needs ';
-- ----------------------------
-- Records of vbw_push_notifications
-- ----------------------------
INSERT INTO `vbw_push_notifications` VALUES ('1', '165836,65802,65829,65837,65838', 'test test test', '2013-11-07 12:36:42', '0');
And I have another table with the following details.
CREATE TABLE `vbw_mobile_sessions` (
`mobile_session_id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'The unique identifier for a mobile session',
`mobile_session_start_time` datetime DEFAULT NULL COMMENT 'The starting time # server of a mobile session',
`mobile_session_end_time` datetime DEFAULT NULL COMMENT 'The ending time # server of a mobile session',
`mobile_session_token` varchar(255) DEFAULT NULL COMMENT 'The mobile session token generated for this session',
`mobile_session_device_id` varchar(50) DEFAULT NULL COMMENT 'The device id of the device used for making the session',
`mobile_session_customer_id` int(10) DEFAULT NULL COMMENT 'The customer ID of the customer who made this session',
`mobile_session_device_type` tinyint(4) DEFAULT NULL COMMENT 'The type of device that customer uses for this session. 0 - iOS, 1 - Android',
PRIMARY KEY (`mobile_session_id`),
KEY `fk_mobile_session_customer_id` (`mobile_session_customer_id`)
) ENGINE=InnoDB AUTO_INCREMENT=677 DEFAULT CHARSET=latin1 COMMENT='This table holds the merchant account activation links creat';
I want to use a subquery like this.
SELECT DISTINCT(mobile_session_customer_id)
FROM vbw_mobile_sessions
WHERE mobile_session_end_time IS null
AND mobile_session_customer_id IN (SELECT push_notification_customer_ids FROM vbw_push_notifications WHERE push_notification_id=6) .
This query not returns zero rows. But i am getting result when i have used like this.
SELECT DISTINCT(mobile_session_customer_id)
FROM vbw_mobile_sessions
WHERE mobile_session_end_time IS null
AND mobile_session_customer_id IN ( SELECT DISTINCT(mobile_session_customer_id)
FROM vbw_mobile_sessions
WHERE mobile_session_end_time IS null
AND mobile_session_customer_id IN (65836,65802,65829,65837,65838)
I think its in a different format the subquery is returning the result . Can you please point out the mistake i have made. Many Thanks.
Your answer is obvious. String 'a,b,c,d' has nothing to do with set of values (a,b,c,d). This is not how it will work.
The correct solution is not to use delimiter-separated values in one field. You should normalize your DB structure and create linking table. Then place your values into it and build your query with using subquery, selecting from it.
Another, possible solution is to select your data (string data) from your field in application, split it by delimiter and substitute to another query then.
The subquery is returning you a varchar with a value '1,2,3' and you need a set of integers which is 1,2,3...
The engine is treating your result of the subquery as a varchar() not a set of integers.
You can go through this question, asking exactly what you need

MySQL, XML boolean values, and integers: Incorrect integer value:

Im working on grabbing xml data from ebay and putting the results into MySQL, Grabbing the data works fine, however inputting to database fails due to an incorrect integer value for a couple of the xml tags values.
The xml tag value is the word "true" (without the quotes), and this is the db sql:
CREATE TABLE ebay_categories (
CategoryID int(10) NOT NULL default '0',
CategoryLevel int(5) NOT NULL default '0',
CategoryName varchar(120) NOT NULL default '',
CategoryParentID int(10) NOT NULL default '0',
LeafCategory int(1) NOT NULL default '0',
AutoPayEnabled int(1) NOT NULL default '0',
Expired int(1) NOT NULL default '0',
IntlAutosFixedCat int(1) NOT NULL default '0',
Virtual int(1) NOT NULL default '0',
LSD int(1) NOT NULL default '0',
ORPA int(1) NOT NULL default '0',
PRIMARY KEY (CategoryID),
KEY catlevel (CategoryLevel),
KEY parent (CategoryParentID),
KEY ape (AutoPayEnabled),
KEY expired (Expired),
KEY IAFC (IntlAutosFixedCat),
KEY virtual (Virtual),
KEY lsd (LSD),
KEY orpa (ORPA),
KEY leaf (LeafCategory)
) TYPE=MyISAM;
i have tried int, tinyint, Boolean (resorts to tinyint) to no avail and still get this issue. Theres nothing wrong with the db connection as i ran a test using varchar as the int type for the LeafCategory and others and everything worked ok.
is theres something i can do without resorting to searching and replacing via regex before db insertion?
edit:
$query = "INSERT INTO `ebay_categories` (`CategoryID`, `LeafCategory`)VALUES ('$xmlCategoryID', '$xmlLeafCategory')";
if (mysqli_query($link, $query)) {
echo "Successfully inserted " . mysqli_affected_rows($link) . " row";
} else {
echo "Error occurred: " . mysqli_error($link);
}
The SQL statement unwrapped from client code is:
INSERT INTO `ebay_categories`
(`CategoryID`, `LeafCategory`)
VALUES
('$xmlCategoryID', '$xmlLeafCategory')";
The error you have is telling you at least one record in your XML has something other than a valid integer for either $xmlCategoryID or $xmlLeafCategory.
What to do?
A. You could have your error message display the offending data, something like this:
echo "Error occurred: " . mysqli_error($link);
echo "Bad data was either ##$xmlCategoryID## or ##$xmlLeafCategory##.";
Notice that I used ##$value## so you can detect empty strings in your error messages. You probably should do this.
B. You could try changing your column definitions for those columns to remove the NOT NULL declaration. If in fact one of those values is empty, this may fix your problem.
C. It's possible that you need bigint values for this information. That is, they could be very large numbers.
D. If you don't care enough about null or bad values to bother to detect them you could try this.
INSERT INTO `ebay_categories`
(`CategoryID`, `LeafCategory`)
VALUES
(CAST(IFNULL('$xmlCategoryID',-1) AS INT)
(CAST(IFNULL('$xmlLeafCategory',-1) AS INT)
This will turn null values into -1 and non-integer values into 0.
Edit: Oh, I understand now. Your leafCategory item isn't a number in XML, it's a true/false/empty value. Presumably false and empty mean the same thing.
Try this, using a SQL case statement to translate true/other to 1/0.
INSERT INTO `ebay_categories`
(`CategoryID`, `LeafCategory`)
VALUES (
'$xmlCategoryID',
CASE '$xmlLeafCategory' WHEN 'true' THEN 1 ELSE 0 END
)
Finally, danger! You need to use prepared statements, and you need to sanitize these values you're extracting from your XML file. If you don't somebody will be able to trick your software into destroying your database by feeding it a poisoned XML file. Please read up on SQL injection.

MySql LOAD DATA is ignoring my Primary Key id, and using autoincrement instead

I have a table that has a simple primary key, marked as auto_increment.
(Using MySQL 5.0.77) I do repeated LOAD DATA operations. I need to overwrite all of the data, with complete control over my primary key value.
LOAD DATA LOCAL INFILE "TopicInfile.dat" INTO TABLE Topic LINES TERMINATED BY "END-OF-THIS-RECORD";
The .dat file has the ID in it. It's not NULL. And yet, when I load this data, it behaves as if it was NULL, and assigns an autoincrement id, instead of using what I specified.
The only thing unusual about this .dat file is that it contains a lot of data. The .dat file has this structure:
1 2008-06-27 12:00:00 Type-Safe Enumerations Énumérations 5
...a lot of data here...
\N 2002-10-01 12:00:00 END-OF-THIS-RECORD
2 2008-06-27 12:00:00 Class for constants Classe pour constantes 1
...a lot of data here...
\N 2002-10-01 12:00:00 END-OF-THIS-RECORD
and so on
The table structure is :
CREATE TABLE `Topic` (
`Id` smallint(5) unsigned NOT NULL auto_increment,
`LastEdit` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
`TitleEnglish` varchar(75) NOT NULL default '',
`TitleFrench` varchar(75) default NULL,
`ChapterId` smallint(6) NOT NULL default '0',
`BodyEnglish` text NOT NULL,
`BodyFrench` text,
`CreationDate` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`Id`)
) ENGINE=MyISAM AUTO_INCREMENT=251 DEFAULT CHARSET=utf8 |
I have other tables for which the behavior is fine - the LOAD DATA operation always accepts my id value, except for the above Table.
Any help appreciated.
I don't know exactly why the items were treated as null.
I made some changes to the content of the input file (tab characters not quite right), and to the LOAD DATA command (EOL character not right), which is now behaving correctly:
See:
MySQL LOAD DATA with multiline data