I create a table in MySQL 8.0 as follows:
CREATE TABLE `airline_table` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`info` json DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
It contains JSON type data, and I insert some data as:
INSERT INTO airline_table VALUES ('1','{"data": [{"city": "Houston", "state": "TX"},
{"city": "Los Angles", "state": "CA"}], "airline": ["UA", "AA"]}');
And I use php to visit the database, I wish to get value of "airline" as an Array.
<?php
$mysqli = new mysqli("localhost", "root", "aproot2019", "test");
$sql = "SELECT id, info -> '$.airline' AS airline FROM airline_table";
$result = $mysqli->query($sql);
$row = $result->fetch_array();
//print_r($row);
$airline = $row['airline'];
echo $airline . "<br>"; // ["UA", "AA"] , this is a string but not an array, how can I have an Array?
echo is_array($airline) ? 'Array' : 'not an Array' . "<br>"; // not an Array
echo is_string($airline) ? 'String' : 'not a String' . "<br>" ; // String
$mysqli->close();
?>
But it comes out a String, NOT an Array!
This really annoys me, and JSON in MySQL is hard to understand.
Have you considered decoding JSON?
$json = json_decode('{"data": [{"city": "Houston", "state": "TX"}, {"city": "Los Angles", "state": "CA"}], "airline": ["UA", "AA"]}');
// for your case it will be :
// $json = json_decode($row['airline']);
echo var_dump($json->airline);
/**
* array(2) {
[0]=>
string(2) "UA"
[1]=>
string(2) "AA"
}
Querying a JSON from MySQL is not hard, but.... For this kind of tables I would not do it in JSON. 😉
SELECT
j.city,
j.state
FROM airline_table
CROSS JOIN JSON_TABLE(info, '$.data[*]' COLUMNS(
city VARCHAR(20) PATH '$.city',
state VARCHAR(20) PATH '$.state')) as j
output:
city
state
Houston
TX
Los Angles
CA
Related
I am trying to insert data to 2 different tables in my database.
First table is named business which I have done it to insert data to from the json file to the database.
But when I am trying to insert data into table named business_phone it does not do anything.
Here is my code for inserting the data:
$query = '';
$query_phones='';
$table_data = '';
$filename = "businesses.json";
$businesses = file_get_contents($filename);
$business = json_decode($businesses, true);
foreach($business as $row)
{
$query .= "INSERT INTO business(title, address, website, page) VALUES ('".$row["title"]."', '".$row["address"]."', '".$row["website"]."', '".$row["page"]."'); ";
//data that i will show on page
$table_data .= '
<tr>
<td>'.$row["title"].'</td>
<td>'.$row["address"].'</td>
<td>'.$row["website"].'</td>
<td>'.$row["page"].'</td>
</tr>
';
}
foreach($business as $row)
{
$query_phones .="INSERT INTO business_phones(business_title, phone_number, phone_name) VALUES ('".$row["title"]."', '".$row["number"]."', '".$row["name"]."');";
}
Here is some code from the json file
[
{
"title": "CONSERVE IT LTD",
"address": "12 Truman Ave (10) ",
"phones": [
{
"name": "telephone_1",
"number": "876-754-0220"
},
{
"name": "telephone_2",
"number": "876-754-0221"
}
],
"website": "www.conserveitja.com",
"page": 1
},
{
"title": "Consie Walters Cancer Hospital",
"address": "22 Deanery Rd (3) ",
"phones": [
{
"name": "telephone_1",
"number": "876-930-5016"
}
],
"page": 1
},
...
]
I don't know how you to handle within php but you can create an auxiliary table to be populated from the file, and then use JSON_TABLE function for the key values to be inserted into that table, provided you're using MySQL DB ver. 8+ :
INSERT INTO business(title, address, website, page)
SELECT t.*
FROM tab
CROSS JOIN
JSON_TABLE(jsdata, '$[*]' COLUMNS (
title VARCHAR(100) PATH '$.title',
address VARCHAR(100) PATH '$.address',
website VARCHAR(100) PATH '$.website',
page VARCHAR(100) PATH '$.page')
) t
and
INSERT INTO business_phones(business_title, phone_number, phone_name)
SELECT t.*
FROM tab
CROSS JOIN
JSON_TABLE(jsdata, '$[*]' COLUMNS (
business_title VARCHAR(100) PATH '$.title',
NESTED PATH '$.phones[*]' COLUMNS (
phone_number VARCHAR(100) PATH '$.number',
phone_name VARCHAR(100) PATH '$.name')
)
) t
a side Note concatenations for sql statements are vulnerable to Injection for most of the programming languages as #Magnuss Eriksson mentioned.
Demo
$row["number"] is not valid. It will be $row["phones"][0] or $row["phones"][1]. Because according to your data "number" and "name" inside of "phones" which is array.
You can nested loop through "phones"
foreach($row["phones"] as $contact){
$query .="INSERT INTO business_phones(business_title, phone_number,
phone_name) VALUES ('".$row["title"]."', '".contact."',
'".$row["name"]."');"
}
I have 2 MySQL tables, the first one is the parent table and second one the child table. These two table share a 1:M relationship. The T_1 contains the list of unique users with some informations. And the T_2 contains all the line data list with coordinates at a specific timestamp for each user. The child table T_2 has a FK that references the PK in the T_1 parent table. I share below the CREATE STATEMENT:
CREATE TABLE `T_1` (
`id` varchar(45) DEFAULT NULL,
`value_1` tinyint(4) NOT NULL,
`personId` varchar(45) NOT NULL,
`value_2` varchar(45) NOT NULL,
`value_3` varchar(45) NOT NULL,
`Value_4` int(11) NOT NULL,
PRIMARY KEY (`personId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `T_2` (
`personId` varchar(45) NOT NULL,
`timestamp` varchar(45) NOT NULL,
`x` int(11) NOT NULL,
`y` int(11) NOT NULL,
KEY `user_fk_idx` (`personId`),
CONSTRAINT `user_fk` FOREIGN KEY (`personId`) REFERENCES `T_1` (`personId`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
I would like to get as final json result something like that:
[
{
"id": "",
"value_1": true,
"personId": "1",
"value_2": "test",
"value_3": "test",
"value_4": 10,
"lineData": [
{
"timestamp": "some_date",
"x": 100,
"y": 250
},
{
"timestamp": "some_date",
"x": 100,
"y": 350
}
]
},
{
"id": "",
"value_1": true,
"personId": "2",
"value_2": "test",
"value_3": "test",
"value_4": 10,
"lineData": [
{
"timestamp": "some_date",
"x": 50,
"y": 450
},
{
"timestamp": "some_date",
"x": 80,
"y": 550
}
]
}
]
This is the first query selection that I have made in order to get the aggregation of all the T_2 records for each T_1.personId:
SELECT T_1.personId,GROUP_CONCAT(CONCAT(T_2.timestamp, T_2.x, T_2.y) SEPARATOR ' ')
FROM T_1
JOIN T_2
ON T_1.personId=T_2.personId
GROUP BY personId;
Except that I need to add also id, value_1, value_2, value_3, value_4, the query aggregation seems correct by I'm still far away from the expected result:
By using the PDO::FETCH_ASSOCquery fetch within PHP I get actually the similar expected array result.
But the main problem is that the linedata aggregation is just in a single string format grouped and concatenated all together, not in an object structure form. (screen below)
I attach the example data below from the query selection:
array(7) {
["id"]=>
NULL
["value_1"]=>
string(1) "0"
["personId"]=>
string(2) "1"
["value_2"]=>
string(9) "test"
["value_3"]=>
string(4) "test"
["value_4"]=>
string(2) "10"
["linedata"]=>
string(359) "2018/09/15 10:00:05 AM1100950 2018/09/15 10:00:07 AM1100850 2018/09/15 10:00:09 AM1180800 2018/09/15 10:00:10 AM1280800 2018/09/15 10:00:15 AM1380800 2018/09/15 10:00:17 AM1480800 2018/09/15 10:00:20 AM1900800 2018/09/15 10:00:25 AM1930750 2018/09/15 10:00:40 AM1910440 2018/09/15 10:00:45 AM1250460 2018/09/15 10:01:25 AM1100455 2018/09/15 10:01:29 AM1100655"
}
}
Maybe is it needed to concatenate the square and curly brackets within the selection query?
Can someone suggest me how to get the correct separated structure for linea data? I supposed that we need to use also some post-process PHP stuff in order to get the exact desired output structure.
Update
Following the #Salman A's suggestion, I have tweak the query as below:
GROUP_CONCAT(CONCAT_WS(', ',timestamp,x, y) SEPARATOR '; ') as linedata_0
And I have stored the result of the query within $query_result.
Then I have made a nested foreach in order to explode each row with ; and each value of each row with , in $query_result['linedata_0']. And I have put the exploded result in a new key called linedata_1. As showed below:
foreach ($query_result as $q_r){
$first_split = explode(";", $q_r["linedata_0"]);
foreach ($first_split as $f_s){
$second_split = explode(",", $f_s);
$query_result["linedata_1"][]= $second_split;
}
}
I have removed the $query_result[0]["linedata_0"] element. And after that I have assigned the key values to each $query_result['linedata_1'] sub-arrays and store in a new element called $query_result['linedata']. After that I have remove the old $query_result['linedata_1'] element with unset command and in the last foreach I have cast the x and y values from string to integer:
unset($query_result[0]["linedata_0"]);
foreach(($query_result["linedata_1"]) as $q_r) {
$keys = array('timestamp', 'x', 'y');
$query_result["linedata"][] = array_combine($keys, $q_r);
}
unset($query_result["linedata_1"]);
$index = 0;
foreach($query_result["linedata"] as $index=>$val) {
$query_result["linedata"][$index]["x"] = (int) $val["x"];
$query_result["linedata"][$index]["y"] = (int) $val["y"];
$index++;
}
With these PHP post-process operations I got exactly the expected result.Probably this post-process steps within php are not well optimized, but they do the trick for me. If someone of us has a more optimized workaround solution please share it. Thanks.
I have a MySQL database containing tables with Arabic data (Varchar type exactly), I try to print a select query string thought php but it prints the values as zeros, Here's my query :
SELECT *,(
CASE WHEN `name_singular`= "قَائِدان" THEN "name_singular"
WHEN `name_twoA`= "قَائِدان" THEN "name_twoA"
WHEN `name_pluralA`= "قَائِدان" THEN "name_pluralA"
WHEN `name_twoO`= "قَائِدان" THEN "name_twoO"
WHEN `name_pluralO`= "قَائِدان" THEN
"name_pluralO" else NULL END) AS `field`
FROM `name` WHERE `name_singular`= "قَائِدان" OR
`name_twoA`= "قَائِدان" OR
`name_pluralA`= "قَائِدان" OR
`name_twoO`= "قَائِدان" OR
`name_pluralO`= "قَائِدان" LIMIT 0, 10 ;
and that's what i got as a result of printing the query string.
it works fine when executing it thought mysql directly, but when using php it returns null
SELECT *,
( CASE
WHEN `name_singular` = "0" THEN "name_singular"
WHEN `name_twoa` = "0" THEN "name_twoa"
WHEN `name_plurala` = "0" THEN "name_plurala"
WHEN `name_twoo` = "0" THEN "name_twoo"
WHEN `name_pluralo` = "0" THEN "name_pluralo"
ELSE NULL
end ) AS `field`
FROM `name`
WHERE `name_singular` = "0"
OR `name_twoa` = "0"
OR `name_plurala` = "0"
OR `name_twoo` = "0"
OR `name_pluralo` = "0"
LIMIT 0, 10
And that's the php code :
<?php $query = 'the query string above ';
echo $query; $array=mysql_fetch_object(mysql_query($query));
var_dump($array);
?>
Here's my (simplified) code to insert values into tables:
function myInsert($pdo, $sql, $values) {
$pdo->prepare($sql);
foreach ($values as $key=>$value) {
$stmt->bindValue($key, $value);
}
}
myInsert(
$pdo,
'INSERT INTO mytable (a,b,c) VALUES (:a,:b,:c)',
array(
':a' => 'valuea',
':b' => 'valueb',
':c' => 'valuec',
)
);
What could be the correct 'valuea' that could represent a MySQL geo point?
You're supposed to follow this format:
POINT( a.latitude, a.longitude )
BUT for some reason I had trouble doing that, so I simply reused the :lat & :lng that I had no trouble putting into my database. I was getting an HY000 (couldn't connect to database) error for some reason when my $newPosition = "POINT(" . $newlat . ", " . $newlng . ")"; line preceded the connection, but with bit of PDO/SQL I no longer had to bother with a $newPosition at all:
SET lat = :lat, lng = :lng, position = POINT( :lat, :lng)
Use
GeomFromText('POINT(1 1)')
$valuea = "$lat $lng";
GeomFromText('POINT($valuea)')", //Example: GeomFromText('POINT(31.95635 35.945843)')
and be aware of the table column type it should be type of point.
Example:
CREATE TABLE mytable(
id int(11) NOT NULL AUTO_INCREMENT,
geo_point point DEFAULT NULL,
PRIMARY KEY (id),
)
I have a simple question but I don't know which term I should use to find the answer (english is not my first language).
I have a classical database design of products like and categories.
CREATE TABLE IF NOT EXISTS `a` (
`id_a` int(11) NOT NULL auto_increment,
`type` varchar(255) NOT NULL,
PRIMARY KEY (`id_a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=12 ;
CREATE TABLE IF NOT EXISTS `b` (
`id_b` int(11) NOT NULL,
`id_a` int(11) NOT NULL,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id_b`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Where b.id_a is a foreign key to a.id_a
I want to get a hierarchy of all thoses like
A VALUE 1
b_value_1
b_value_2
A VALUE 2
b_value_11
b_value_12
A VALUE 3
b_value_21
b_value_22
b_value_23
The request doesn't matters but I get this kind of anwser:
VALUEOF-TABLE-A | VALUEOF-TABLE-B
A VALUE 1 | b_value_1
A VALUE 1 | b_value_2
and so on.
My current code is something like:
$categ = '';
while ($row = mysql_fetch_row ($ressource))
{
if ($row['VALUEOF-TABLE-A']!=$categ)
{
$categ = $row['VALUEOF-TABLE-A'];
echo '<h3>', $categ, '</h3>';
}
echo '<h4>', $row['VALUEOF-TABLE-B'], '</h4>';
}
But I don't like much the idea of the categ variable, be it a string or an id.
Is there an other way to get the data and display them?
Ideally, I'de like a tree object, having only one node for identical children.
Hope you understood what I want.
When working with foreign keys in Mysql, you should use the InnoDB engine instead of MyISAM.
There seems to be a problem in the conception of the b table, id_b should be the primary key, not id_a.
To solve your problem, maybe you should first retrieve the list of id_a, then make one selection request by id_a to select the corresponding id_b using a JOIN.
EDIT : the script should look like this with a little more presentation :
$category_array = mysql_query("SELECT id_a, type FROM a");
while ($category = mysql_fetch_array($category_array))
{
echo $category['type'];
$product_array = mysql_query("SELECT * FROM b WHERE id_a = $id_a");
while ($product = mysql_fetch_array($product_array))
{
echo $product['name'];
}
}
The example Chico gives is on the right track, but has a problem: when there are many categories, the script will also execute many queries, which is inefficient. The following example is much more efficient:
$categories = array();
$category_array = mysql_query("SELECT id_a, type FROM a");
while ($category = mysql_fetch_array($category_array))
{
$category['products'] = array();
$categories[$category['id_a']][] = $category;
}
$product_array = mysql_query("SELECT * FROM b");
while ($product = mysql_fetch_array($product_array))
{
$categories[$product['id_a']]['products'][] = $product
}
foreach($categories as $category) {
echo $category['type'];
foreach ($category['products'] as $product) {
echo $product['name'];
}
}
As an added bonus, this also separates the retrieval of the data more cleanly from the output.