mariadb json decode - json

I got a text column with JSON arrays.
+-------------------------------------------------------------------------+
| code |
+-------------------------------------------------------------------------+
| [] |
| ["5020","6420"] |
| ["4645","4775"] |
| ["6820"] |
| ["2442","2511"] |
| ["4675"] |
| ["1814","6201","6203","6209","6312","6399","7022","7311","7312","7320"] |
| ["6910","6920"] |
| ["4321","4329","4652","7112"] |
| ["4332","7739"] |
+-------------------------------------------------------------------------+
I need to get these codes to another table as single integer values. As soon as there are millions of records I would not like to fetch these records to php/ruby/etc for this task. I'd like to make it inside MariaDB with SQL.
The question is what could be a nice approach for such query?

In addition to the first posted answer about reading table in chunks, some other possible solutions:
1) If it needs to be done once or rarely, I would go with the low-tech approach:
select code into an outfile;
run a simple sed (remove square brackets and replace commas with new lines, thus getting one number per row, quote marks don't matter);
load the file into a table.
2) If you really want to stick with SQL only, there should be a procedure:
use cursor to go through each row;
use substring replacements to convert the array-like string ["1","2"] into the values-like string (1),(2) -- it's simple, although a bit ugly;
append the resulting string to INSERT INTO <table name> VALUES;
run it as a prepared statement;
3) If you want to go fancy and experiment (assuming it's not production), try JSON functions in MariaDB 10.2, also through a procedure:
use cursor to go through each row;
use JSON_LENGTH to get a number of elements in the array;
use a loop (e.g. WHILE) to JSON_EXTRACT each value in turn and either insert it immediately, or again build a prepared statement.

No. The SQL code would be so messy as to be worse overall.
I would read the table in chunks of 100-1000 rows, go through the arrays to get the numbers, de-dup (in php/etc) then do INSERT or INSERT IGNORE into the target table.
Tips on chunking (aimed at DELETE, but adaptable for SELECT): http://mysql.rjweb.org/doc.php/deletebig#deleting_in_chunks

For PHP. u can use it
$re = '/\d+/m';
$str = '+-------------------------------------------------------------------------+
| code |
+-------------------------------------------------------------------------+
| [] |
| ["5020","6420"] |
| ["4645","4775"] |
| ["6820"] |
| ["2442","2511"] |
| ["4675"] |
| ["1814","6201","6203","6209","6312","6399","7022","7311","7312","7320"] |
| ["6910","6920"] |
| ["4321","4329","4652","7112"] |
| ["4332","7739"] |
+-------------------------------------------------------------------------+';
preg_match_all($re, $str, $matches);
// Print the entire match result
print_r($matches);
Result:
Array
(
[0] => Array
(
[0] => 5020
[1] => 6420
[2] => 4645
[3] => 4775
[4] => 6820
[5] => 2442
[6] => 2511
[7] => 4675
[8] => 1814
[9] => 6201
[10] => 6203
[11] => 6209
[12] => 6312
[13] => 6399
[14] => 7022
[15] => 7311
[16] => 7312
[17] => 7320
[18] => 6910
[19] => 6920
[20] => 4321
[21] => 4329
[22] => 4652
[23] => 7112
[24] => 4332
[25] => 7739
)
)
u should do
$str = Result (MYSQL JSON)
Enjoy.

Related

jumping ID aunto increment after delete

When I was delete record Users, the ID primary key auto increment always jumping, I want ID auto increment is sequence again, this sample
| ID | UserName |
| 1 | Budi |
| 2 | Joko |
| 3 | Amir |
when I delete users Joko, then I add new other user, the ID number is jumping
| ID | UserName |
| 1 | Budi |
| 3 | Amir |
| 4 | Faris |
while I've browsing solution, I get some solution, but doesn't work.
here I've add modified file
config/app.php
'SQLkonek' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => 'root',
'paassword' => ' ',
'database' => 'klinikucing',
'encoding' => 'utf8mb4',
'timezone' => ' ',
'cacheMetadata' => true
]
then I call modified above through
controller/UsersController.php
public function delete ($id = null)
{
$this->request->allowMethod(['post', 'delete']);
$kon = ConnectionManager::get('SQLkonek');
$user = $this->Users->get($id);
$stm = $kon->execute(array(
['SET #count = 0'],
['DELETE FROM users WHERE ID = :ID'],
['UPDATE users SET users.ID = #count:= #count + 1'],
['ALTER TABLE users AUTO_INCREMENT =1']
))
->fetchAll('assoc');
If($this->Users->$stm) {
$this->Flash->success(__('Users success delete.'));
} else {
$this->Flash->error(__('User delete failed, try again.'));
}
return $this->redirect(['action' => 'index']);
}
The error message was shown
Warning (2): PDO::prepare() expects parameter 1 to be string, array given [CORE\src\Database\Driver\Mysql.php, line 138]
Warning (512): Unable to emit headers. Headers sent in file=C:\xampp\htdocs\klinikucing\vendor\cakephp\cakephp\src\Error\Debugger.php line=853 [CORE\src\Http\ResponseEmitter.php, line 48]
Warning (2): Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\klinikucing\vendor\cakephp\cakephp\src\Error\Debugger.php:853) [CORE\src\Http\ResponseEmitter.php, line 148
Warning (2): Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\klinikucing\vendor\cakephp\cakephp\src\Error\Debugger.php:853) [CORE\src\Http\ResponseEmitter.php, line 181]
Argument 1 passed to Cake\Database\Statement\PDOStatement::__construct() must be an instance of PDOStatement or null, boolean given, called in C:\xampp\htdocs\klinikucing\vendor\cakephp\cakephp\src\Database\Driver\Mysql.php on line 139
Error in: ROOT\vendor\cakephp\cakephp\src\Database\Statement\PDOStatement.php, line 33
My CakePHP version is 3.7.2
I hopefull that someone can help me, thanx
Don't renumber. Accept there will be gaps in AI due to deleting an other cause (like aborted transaction, INSERT IGNORE etc.).
As you change PK values you change the FK relationships they have.
With ID of a type of INT UNSIGNED or BIGINT UNSIGNED you're not going to run out of ID ever.

MySQL JOIN whether null or not

I'm pretty out of practice with MySQL and PHP, but I have a project I'm working on for a friend that involves selecting data from two tables, and combining them into one result - seems simple.
Table 1 has 13 fields, but the important ones are id (auto-increment, primary key) and serial (unique). The rest are just ones like customer, description, etc. etc.
Pictures has 3 fields, picID (auto-increment, primary key), imagePath and serial
I need to retrieve all data from Table 1, and if there is a matching photo (identified by the same serial - only ever 1 photo possible per serial) in Pictures, then retrieve that data too. I then output the data from Table1, and use imagePath from Pictures to build an image in HTML if one has been uploaded.
The query I've been using is:
$sql = "SELECT * FROM Table1 LEFT JOIN Pictures ON Table1.serial = Pictures.serial ORDER BY Table1.serial";
Which seems perfect, EXCEPT if any row from Table1 does not have a photo match in Pictures, the serial is no longer returned with the rest of the data, although the remainder of the row is all correct.
I have looked into the different types of JOIN, and whether it's just UNION that I need, but I am a bit stumped. How should I query to get each row of Table1 plus Pictures.imagePath added on to the matching Table1 row, if it exists?
Thank you for your time!!!! :)
EDIT with dumped array output
Array
(
[0] => Array
(
[id] => 51
[0] => 51
[client] => Test Client
[1] => Test Client
[location] => Ayreford House
[2] => Ayreford House
[description] => Ceiling cavity of building XYZ
[3] => Ceiling cavity of building XYZ
[serial] =>
[4] => 18001
[blah] => 123456
[5] => 123456
[fw] => Wall
[6] => Wall
[pm] => Plasterboard
[7] => Plasterboard
[stuff] => ventilation ducting
[8] => ventilation ducting
[ref] => S1000-2018
[9] => S1000-2018
[otheref] => XTX-1325
[10] => XTX-1325
[notes] => Updated photo
[11] => Updated photo
[date] => 2018-06-28 21:37:49
[12] => 2018-06-28 21:37:49
[picID] =>
[13] =>
[imagePath] =>
[14] =>
[15] =>
)
It's doing that because both Table1 and Pictures have a column called serial and it drops the table names when it is generating the array keys. Probably its doing something like this internally:
$result = array()
$result[0] = Table1.serial;
$result['serial'] = Table1.serial;
$result[1] = Table1.client;
$result['client'] = Table1.client;
....
$result[14] = Pictures.serial;
$result['serial'] = Pictures.serial;
So you end up with only Picture.serial as the value for the key 'serial' in the resulting array.
One way to fix this would be to specify your columns explicitly and don't include Pictures.serial, like this:
SELECT
Table1.id,
Table1.client,
Table1.location,
Table1.description,
Table1.serial,
Pictures.notes
FROM
Table1
LEFT JOIN
Pictures ON Table1.serial = Pictures.serial
ORDER BY
Table1.serial

mysql joins and groups

I'm new to this forum from the standpoint of posting, as this question may show. I'm having some issues with the way I want my data to appear.
So, I have 3 tables (I am only showing the columns that I want):
visitors:
center_id (where the visitor was) | state_id (where they came from)
centers:
center_id | center
states:
state_id | state
here is the query that I have been using
SELECT states.state, visitors.center_id, visitors.state_id, centers.center, COUNT(visitors.state_id) AS totalCount
FROM visitors
LEFT JOIN states ON states.state_id = visitors.state_id
LEFT JOIN centers ON centers.center_id = visitors.center_id
WHERE visitors.vdate = <some date> AND visitors.state_id <> '0'
GROUP BY centers.center, visitors.state_id
This produces the following array:
Array
(
[0] => Array
(
[state] => Connecticut
[location_id] => 1
[state_id] => 8
[center] => Little River
[totalCount] => 1
)
[1] => Array
(
[state] => California
[location_id] => 5
[state_id] => 6
[center] => North Augusta
[totalCount] => 1
)
[2] => Array
(
[state] => Colorado
[location_id] => 5
[state_id] => 7
[center] => North Augusta
[totalCount] => 2
)
[6] => Array
(
[state] => Connecticut
[location_id] => 9
[state_id] => 8
[center] => Santee
[totalCount] => 2
)
[7] => Array
(
[state] => Virginia
[location_id] => 9
[state_id] => 51
[center] => Santee
[totalCount] => 1
)
)
This is what I really want:
Array
(
[Little River] => Array
(
[0] => Array
(
[state] => Connecticut
[state_id] => 8
[totalCount] => 1
)
)
[North Augusta] => Array
(
[0] => Array
(
[state] => California
[state_id] => 6
[totalCount] => 1
)
[1] => Array
(
[state] => Colorado
[state_id] => 7
[totalCount] => 2
)
)
[Santee] => Array
(
[0] => Array
(
[state] => Connecticut
[state_id] => 8
[totalCount] => 2
)
[1] => Array
(
[state] => Virginia
[state_id] => 51
[totalCount] => 1
)
)
)
Ultimately I'm putting this into a table that looks something like this:
__________________
|State | Count|
-------------------
| Santee |
-------------------
| Georgia | 5 |
-------------------
| Alabama | 10 |
-------------------
| North Augusta |
-------------------
| another | 7 |
-------------------
Sorry for being long winded, but this was the only way that I could describe it.
I've also tried breaking it out in php, but I'm probably doing something wrong there too. I can make a table with 3 columns with the center listed with each state, but I'm realliy looking for a row that show the center followed by all of the states and counts for that center and on to the next center.
Any assistance would be appreciated.
A query may only return a two- (or less) dimentional result. You will need to parse this result set to transform it into a tree.
With PHP, there really is no difficulty:
foreach ($rawResultSet as $row) {
$finalResult[$row['center']][] = array(
$row['state'],
$row['state_id'],
$row['totalCount']
);
}

Select statement not returning all values

This function works fine, what is flipping me out is that the array returned has all the information needed except $row[15] which has data in it on the table Orders
function SelectOrder($orderid)
{
connect();
$result = mysql_query("SELECT * FROM `Orders` WHERE `OrderID` =".$orderid." LIMIT 0 , 30");
$row = mysql_fetch_row($result);
return $row;
}
print_r($row);
Prints
Array ( [0] => 24
[1] => Grei
[2] => Tristram
[3] => 19 2nd Blvd.
[4] => Richmond
[5] => J7V 5R6
[6] => Ontario
[7] => Canada
[8] => grei#email.ca
[9] => (514) 555-5555
[10] => Snow Removal
[11] => 210
[12] => 32.5
[13] => 23.07
[14] => 200.57
[15] =>
[16] => 123 same street
[17] => 1
[18] => 0 )
When I use the same select statement within PHPMyAdmin
SELECT *
FROM `Orders`
WHERE `OrderID` = 24
LIMIT 0 , 30
I get value [15] (SNAME = Frank Ditripani)
PHPMyAdmin SQL Results
OrderID-Fname-Lname-Address-City-Pcode-Prov-Country-Email-Phone-Service-Price-Discount-Tax PYMNTAmount-SNAME-SADD-Agreed-PayPalPaid
24-Grei-Tristram-19 2nd Blvd.-Richmond-J7V 5R6-Ontario-Canada-grei#email.ca-(514) 555-5555-Snow Removal-210-32.5-23.07-200.57-Frank Ditripani-123 same street-1-0
Both SNAME and SADD are the exact same properties in the table which is varchar(50) and SADD is returned but not SNAME.
This is the first time I have ever posted a question I usually find my answers here but this one is driving me nuts! and I am a bit embarrassed as the answer is probabley an easy one.
The query might be the same, but is the database the same?
Check that you are connecting to the same database!
My bet is the connection parameters are different for the two programs.
Check the connection character set - DB, client and connection should use the same one.

Making a conditional MySQL join involving a small table and a large table efficient

The MySQL query I'm currently trying to perform is functionally equivalent to this:
SELECT small_table.A, small_table.B, small_table.C, huge_table.X, huge_table.Y
FROM small_table LEFT JOIN huge_table
ON small_table.D = huge_table.Z
WHERE small_table.E = 'blah'
except that the query doesn't appear to terminate (at least not within a reasonable amount of time), probably because the second table is huge (i.e. 7500 rows with a total size of 3 MB). Can I perform a functionally equivalent join in a reasonable amount of time, or do I need to introduce redundancy by adding columns from the huge table into the small table. (I'm a total beginner to SQL.)
The clause WHERE small_table.E = 'blah' is static and 'blah' never changes.
Here is the EXPLAIN output as requested:
Array ( [0] => Array ( [0] => 1 [id] => 1 [1] => SIMPLE [select_type] => SIMPLE [2] => small_table [table] => small_table [3] => ref [type] => ref [4] => E [possible_keys] => E [5] => E [key] => E [6] => 1 [key_len] => 1 [7] => const [ref] => const [8] => 1064 [rows] => 1064 [9] => Using where [Extra] => Using where ) [1] => Array ( [0] => 1 [id] => 1 [1] => SIMPLE [select_type] => SIMPLE [2] => huge_table [table] => huge_table [3] => eq_ref [type] => eq_ref [4] => PRIMARY [possible_keys] => PRIMARY [5] => PRIMARY [key] => PRIMARY [6] => 4 [key_len] => 4 [7] => my_database.small_table.D [ref] => my_database.small_table.D [8] => 1 [rows] => 1 [9] => [Extra] => ) )
A few things ...
1) Are you executing this query directly in MySQL (either Workbench GUI or command line), or is this query embedded in PHP code? Your EXPLAIN output seems to suggest PHP. If you haven't done so already, try executing the query directly in MySQL and take PHP out of the mix.
2) Your EXPLAIN output looks Ok, except I'm wondering about your WHERE clause with small_table.E = 'blah'. The EXPLAIN output shows that there's an index on column E but the key length = 1, which is not consistent to the comparison with 'blah'. What data type did you use for the column definition for small_table.E?
3) MySQL is estimating that it needs to scan 1064 rows in small_table. How many total rows are in small_table, and how many do you expect should match this particular query?