1

I am trying to query large amounts of data to a server, here is my code for that:

$queryString = "";

$connect = mysqli_connect("localhost", "username", "password", "database");

$loopLength = 20;
$currentGroup = 1;
$currentLoopAmount = 0;
$queryAmount = 5;

for($v = 0; $v < ceil($loopLength / $queryAmount); $v++){
    //echo "Looping Main: " . $v . "<br>";
    //echo $loopLength - (($currentGroup - 1) * 10) . "<br>";
    if($loopLength - (($currentGroup - 1) * $queryAmount) >= $queryAmount){
        $currentLoopAmount = $queryAmount;
    }
    else{
        $currentLoopAmount = $loopLength - (($currentGroup - 1) * $queryAmount);
    }

    //echo $currentLoopAmount;

    $queryString = "";

    for($q = (($currentGroup - 1) * $queryAmount); $q < $currentLoopAmount + (($currentGroup - 1) * $queryAmount); $q++){
        //echo "&nbsp;&nbsp;Looping Sub: " . $q . "<br>";
        $tempVariable = grabPageData($URLs[$q], $q);

        $queryString .= $tempVariable;
        if($q < $loopLength-1){
            $queryString .= ",";
        }
        else{
            $queryString .= ";";
        }
    }

    echo $queryString;

    $query = "INSERT INTO PublicNoticesTable (url, county, paperco, date, notice, id) VALUES " . $queryString;
    $result = mysqli_query($connect, $query);

    if($result){
        echo "Success";
    }
    else{
        echo "Failed : " . mysqli_error($connect) . "<br>";
    }

    $currentGroup += 1;
}

The $loopLength variable is dynamic and can be in the thousands or potentially hundred thousands. I designed this function to divide that massive number into a batch of smaller queries as I couldn't upload all the data at one time on my shared hosting service through GoDaddy. The $queryAmount variable represents how big the smaller queries are.

Here is an example of one of the value sets that gets inserted into the table: It is the data from a public notice that my code retrieved in the grabPageData() function.

('http://www.publicnoticeads.com/az/search/view.asp?T=PN&id=37/7292017_24266919.htm','Pima','Green Valley News and Sun','2017/07/30',' ___________________________ARIZONA SUPERIOR COURT, PIMA COUNTYIn the Matter of the Estate of:JOSEPH T, DILLARD, SR.,Deceased.DOB: 10/09/1931No. PB20170865NOTICE TO CREDITORS(FOR PUBLICATION)NOTICE IS HEREBY GIVEN that DANA ANN DILLARD CALL has been appointed Personal Representative of this Estate. All persons having claims against the Estate are required to present their claimswithin four months after the date of the firat publication of this notice or the claims will be forever barred. Claims must be presented by delivering or mailing a written statement of the claim to the Personal Representative at the Law Offices of Michael W. Murray, 257 North Stone Avenue, Tucson, Arizona 85701.DATED this 17th day of July, 2017./S/ Micahel W. MurrayAttorney for the Personal RepresentativePub: Green Valley News & SunDate: July 23, 30, August 6, 2017 Public Notice ID: 24266919',' 24266919'),

To attain this data, I run it through a function that crawls the page and grabs it. Then I put the webpage html code through this function:

function cleanData($data){
    $data = strip_tags($data);
    //$data = preg_replace("/[^a-zA-Z0-9]/", "", $data);
    //$data = mysql_real_escape_string($data);
    return $data;
}

Which gives me the content without tags as you see above. Here's the problem.

The function executes and everything seems just dandy. Then the function (depending on the $queryAmount variable which I don't keep over 10 for problem's sake) outputs, as you can see it would in the function something like...

Failed : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1

The weird part is that when I have large amounts of data like say the $loopLength variable is like 116. The result will output, "Failed : (error)Failed : (Error)Fai...(Error)Success. So it's only actually querying the last set of data??? Not sure.

I am not sure how to fix this and I want a fresh eye. Can somebody help me please. I have been working on this problem for... several hours trying to find solution.

Sorry for making this question a pain in the butt :(

EDIT:

I changed the code from previously to use mysql prepared statements and what not... See below:

$grabDataResults = [
        "url" => "",
        "county" => "",
        "paperco" => "",
        "date" => "",
        "notice" => "",
        "id" => "",
    ];

$connect = mysqli_connect("localhost", "bwt_admin", "Thebeast1398", "NewCoDatabase");

if($stmt = mysqli_prepare($connect, "INSERT INTO PublicNoticesTable (url, county, paperco, date, notice, id) VALUES (?, ?, ?, ?, ?, ?)")){

mysqli_stmt_bind_param($stmt, 'ssssss', $grabDataResults["url"], $grabDataResults["county"], $grabDataResults["paperco"], $grabDataResults["date"], $grabDataResults["notice"], $grabDataResults["id"]);

$loopLength = 1;

for($v = 0; $v < $loopLength; $v++){
    $grabDataResults = grabPageData($URLs[$v], $v);
    mysqli_stmt_execute($stmt);
    printf("%d Row inserted.\n", mysqli_stmt_affected_rows($stmt));
    printf("Error:\n", mysqli_stmt_error($stmt));
    echo "(" . $grabDataResults["url"] . "," . $grabDataResults["county"] . "," . $grabDataResults["paperco"] . "," . $grabDataResults["date"] . "," . $grabDataResults["notice"] . "," . $grabDataResults["id"] . ")";
}

mysqli_stmt_close($stmt);

mysqli_close($connect);
}

Unfortunately this is what I get from the output:

1 Row inserted. 0 Error: 

No error actually prints out and the row is inserted. However when I navigate to my database, and look at the values that have been stored.. They are all empty. The echo statement outputs this:

(http://www.publicnoticeads.com/az/search/view.asp?T=PN&id=31/7292017_24266963.htm,Yuma,Sun (Yuma), The,2017/07/30,, 24266963)

So I know that all of the variables contain something except for the $notice variable which gets destroyed by my cleanData() function for some reason.

Pixelknight1398
  • 537
  • 2
  • 10
  • 33
  • 1
    From the comments on the questions so far - I would definitely use prepared statements and bind the values. If your data is from web pages, the chances of having values which will break your SQL if inserted directly is very high, https://stackoverflow.com/questions/9629328/how-to-use-mysqli-prepared-statements-in-php may help. – Nigel Ren Jul 30 '17 at 06:16
  • I did some research on created prepared statements and binding the values for the sake of not inserting directly... Seems like it would be a huge mess for my code trying to dynamically generate the query statement and stuff. I suppose I can give it a shot but like I said I could be generating thousands upon thousands of rows of data, no telling what that bind statement would look like, let alone the query itself. – Pixelknight1398 Jul 30 '17 at 07:05
  • You can prepare the statement with an insert for 1 row, and then each rows worth of data you simply execute the prepared statement with the one rows worth of data. – Nigel Ren Jul 30 '17 at 07:45
  • Please see my edit. I went ahead and changed my code to have this statement. The same principle applies as before... The `grabPageData()` function returns the same structure array as `$grabDataResults`... I figured that if I loop through and reset the array values I could then execute the prepare statement on this. You can see also the output I recieve. – Pixelknight1398 Jul 31 '17 at 07:11
  • Put the mysqli_stmt_bind_param in the loop - so fetch the data( `grabPageData` ), bind it, then execute - repeat. – Nigel Ren Jul 31 '17 at 08:06

3 Answers3

0

The main error I can see on your query, are the query itself. You're using a INSERT INTO with separated fields and values. But you forget to use the pharentesis on values.

Remember, the use of INSERT INTO are as follows:

First option:
INSERT INTO table field1 = value1, field2 = value2;

Second option:
INSERT INTO table (field1, field2) VALUES (value1, value2);

Also, remember to escape every field and value for avoid more errors: Example:

First option:
INSERT INTO `table` `field1` = 'value1', `field2` = 'value2';

Second option:
INSERT INTO `table` (`field1`, `field2`) VALUES ('value1', 'value2');

If you're using mysqli driver, for more security, you can use prepared statements, to get your values automatically escaped. In that case, the syntax of the query are as follows:

First option:
INSERT INTO `table` `field1` = ?, `field2` = ?;

Second option:
INSERT INTO `table` (`field1`, `field2`) VALUES (?, ?);

Also, instead of using mysqli_query(), you need to use mysqli_prepare(), mysqli_bind_param() and mysqli_execute(). You can check more data about they syntax here: http://php.net/manual/en/mysqli.prepare.php

At least, you can use mysqli_real_escape_string() function for getting your input properly escaped and checked. You can check documentation of this function here: http://php.net/manual/en/mysqli.real-escape-string.php

Sakura Kinomoto
  • 1,784
  • 2
  • 21
  • 30
  • I am sorry I must be misunderstanding what you are saying? My insert code is `INSERT INTO PublicNoticesTable (url, county, paperco, date, notice, id) VALUES " . $queryString` which you can see that I surrounded the fields in parenthesis. Then finally I don't want to copy and paste the $queryString variable example but you can refer back to my question to see an example. It's messy in a single line but it shows the value set as (value, value, value, value, value, value), and then the final set ends with a semicolon. I will try to add the parenthesis to $queryString and see if that works. – Pixelknight1398 Jul 30 '17 at 04:31
  • You have surrounded field names, but not field values as I've suggested on all my examples. – Sakura Kinomoto Jul 30 '17 at 04:32
  • I did as you suggested and you can see the results of the query string in the comments from B. Desai's answer – Pixelknight1398 Jul 30 '17 at 04:44
  • I editted my code to include `mysqli_prepare() mysqli_bind_param() mysqli_execute()`. Please see changes to question. – Pixelknight1398 Jul 31 '17 at 07:17
0

You code is correct. Just you need to add () arround querystring Akso you need to remove ; from query string end. SO remove following else condition

else{
    $queryString .= ";";
}

change you query like :

$query = "INSERT INTO PublicNoticesTable (url, county, paperco, date, notice, id) VALUES (" . $queryString . ")";

Also it advisable to use prepared statements to prevent from sql injections

B. Desai
  • 16,414
  • 5
  • 26
  • 47
  • Ok so I made the changes you suggested and I got a new error shown as `Failed : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1` for each failed query. And then there is no longer a success value at the end it's now a fail with this error: `Failed : Operand should contain 1 column(s)` – Pixelknight1398 Jul 30 '17 at 04:35
  • Have you removed this else part? `else{ $queryString .= ";"; }` ? – B. Desai Jul 30 '17 at 04:36
  • What is the output of `echo $query`? – B. Desai Jul 30 '17 at 04:38
  • `INSERT INTO PublicNoticesTable (url, county, paperco, date, notice, id) VALUES (('http://www.publicnoticeads.com/az/search/view.asp?T=PN&id=37/7292017_24266919.htm','Pima','Green Valley News and Sun','2017/07/30',' ___________________________ARIZONA SUPERIOR COURT, PIMA COUNTYIn the Matter of the Estate of:JOSEPH T, DILLARD, SR.,Deceased.DOB: 10/09/1931No. PB20170865NOTICE TO CREDITORS(FOR PUBLICATION)NOTICE IS HEREBY GI... ...ativePub: Green Valley News & SunDate: July 23, 30, August 6, 2017 Public Notice ID: 24266919',' 24266919'))` I had to cut it because its massive – Pixelknight1398 Jul 30 '17 at 04:43
  • Bear in mind the query is loading webpages full of data so I couldn't fit all of it into a comment... Also we can see that with the addition of the parenthesis around the values set as I have been suggested to put in... It appears to have too many parenthesis. Even if I remove them however, I am stuck with the original error. – Pixelknight1398 Jul 30 '17 at 04:43
  • So you already have `()` around values so remove it from `VALUES (" . $queryString . ")";` just replace it as you have before. Also remain `else` part in comment – B. Desai Jul 30 '17 at 04:46
  • 1
    Have you tried to execute the query on console client for check more errors? I think the problem are becase special characters. Have you tried to escape each value with string mysqli_real_escape_string ( mysqli $link , string $escapestr )? – Sakura Kinomoto Jul 30 '17 at 04:49
  • Ok so I got a rather interesting result from uncommenting the mysqli_real_escape_string() function from my `cleanData()` function and it outputs `INSERT INTO PublicNoticesTable (url, county, paperco, date, notice, id) VALUES ('http://www.publicnoticeads.com/az/search/view.asp?T=PN&id=37/7292017_24266919.htm','Pima','Green Valley News and Sun','2017/07/30','',' 24266919')` as the query.... Obviously you can see that it completely destroyed the page data that I need and there is nothing in that value spot anymore... I had already tried this before that's why it was simply commented. – Pixelknight1398 Jul 30 '17 at 05:00
  • The above query did succeed by the way. So I do believe that the problem originates from the page data. And to be honest I have no idea how to execute the query on console client. Can you point me in the right direction for learning to do so? – Pixelknight1398 Jul 30 '17 at 05:01
  • I have checked multiple online query checkers and they all say that my full query is good to go so I am not sure what is wrong :/ – Pixelknight1398 Jul 30 '17 at 05:09
0

You need to bind the data after fetching it and before executing it...

$loopLength = 1;

for($v = 0; $v < $loopLength; $v++){
    $grabDataResults = grabPageData($URLs[$v], $v);

    mysqli_stmt_bind_param($stmt, 'ssssss', $grabDataResults["url"],
           $grabDataResults["county"], $grabDataResults["paperco"], 
           $grabDataResults["date"], $grabDataResults["notice"], 
           $grabDataResults["id"]);

    mysqli_stmt_execute($stmt);
    printf("%d Row inserted.\n", mysqli_stmt_affected_rows($stmt));
    printf("Error:\n", mysqli_stmt_error($stmt));
    echo "(" . $grabDataResults["url"] . "," . $grabDataResults["county"] . "," . $grabDataResults["paperco"] . "," . $grabDataResults["date"] . "," . $grabDataResults["notice"] . "," . $grabDataResults["id"] . ")";
}
Nigel Ren
  • 56,122
  • 11
  • 43
  • 55