cbtshare has asked for the wisdom of the Perl Monks concerning the following question:

Hello All, In production there are two tables Facebook_321 and Facebook_321_ext Facebook_321:

id_code: 862012249 entry_time: 2016-10-28 23:36:08 parent_id_code: 783924049_861760507288022 author_name: Lia+nik+son author_code: 1294333813357 author_url: https://www.facebook.com/120357 author_image_url: http://graph.facebook.com/17/picture entry_url: https://business.facebook.com/28262849 entry_types: COMMENT status_code: MOD entry_text: +so%2C++it%27s+the+home+team%21 entry_data: false,"can_comment":false} last_update: 0000-00-00 00:00:00 pull_time: 2016-11-16 18:53:40 queue_code: NULL
Facebook_321_ext:
id_code: 281938224734_10154342971729735 item_name: pull_run_id item_value: 1480804468 item_data: NULL

I have been making queries against a set of tables based on time, but now there are many Facebook_321_ext tables that don't have a time column so I am basically querying the facebook_321 table based on time getting id_codes and storing them.But I am not sure I am doing it correctly, because I am getting an error

DBD::mysql::st fetchrow_array failed: fetch() without execute() at /ho +me/rdscopy.pl line 199. DBD::mysql::st fetchrow_array failed: fetch() without execute() at /ho +me/rdscopy.pl line 199

I dont think I am handling multiple data correctly, can I get some help please? Thank you

#get Id_Codes based on entry time my $feed_table_ext_idcode = $dbh2->prepare("SELECT id_code FROM $fee +d_table WHERE entry_time >= ?"); $feed_table_ext_idcode->execute($time); my $feed_table_ext_results = $dbh2->prepare("SELECT * from $feed_ta +ble_ext WHERE id_code = ?"); while (my @row = $feed_table_ext_idcode->fetchrow_array()) { #print "@row\n"; $feed_table_ext_results->execute(@row); }

My reasoning for the above code is that , there are many id_codes and data returned and I want to store those and insert them into another DB in staging.

Returned after querying facebook_321_ext table in production and need +to copy them to staging ************************** 24. row *************************** id_code: 281938224734_10154342971729735 item_name: PRE_MOD_Krttime item_value: 1480804542 item_data: NULL *************************** 25. row *************************** id_code: 281gfg154342971729735 item_name: PRE_MOD_SetQueue item_value: UNKNOWN item_data: NULL *************************** 26. row *************************** id_code: 281938224734_101gf29735 item_name: PRE_MOD_SetQueue_time item_value: 1480804587 item_data: NULL *************************** 27. row *************************** id_code: 281938224734_10154342971729735 item_name: PRE_MOD_Textalfggtect item_value: POSITIVE item_data: NULL *************************** 28. row *************************** id_code: 281938224734_10154342971729735 item_name: PRE_MOD_TgfentDetect_time item_value: 1480804573 item_data: NULL *************************** 29. row *************************** id_code: 281938224734_10154342971729735 item_name: pull_run_id item_value: 1480804468 item_data: NULL *************************** 30. row *************************** id_code: 281938224734_10154342971729735 item_name: pugfme item_value: 1480804471 item_data: NULL
So $feed_table_ext_results has the query, then @row will have all the id_code and information I need execute based on each id_code which would be done by $feed_table_ext_results->execute(@row);

My insert statement for staging would be below

my $ext_insert = $dbh3->prepare("INSERT IGNORE INTO $feed_table_ext (i +d_code, item_name, item_value, item_data) VALUES (?, ?, ?, ?)") or di +e $dbh3->errstr; while (my @insert_ext = $feed_table_ext_results->fetchrow_array()) { $ext_insert->exe +cute(@insert_ext) or die $sth_insert->errstr; }

Replies are listed 'Best First'.
Re: Perl DBI execute statement
by choroba (Cardinal) on Dec 12, 2016 at 10:08 UTC
    Both your statements are called from $dbh2. Note that some DBD drivers (you didn't say which one you use) don't allow execution of a statement while another statement is still running, you need another connection for that. See for example Can i execute two queries connecting to same DB at a time..

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      I think *all* DBD's allow multiple select handles running at the same time on the same database handle. Some DBD's however do not allow two handles on the same table running simultaneously. Other DBD's do not allow mixing simultaneous handles on the same table that alter the table, like select+delete, select+update, update+delete, select+insert, update+insert, insert+delete etc. Most likely it is not the DBD that imposes these restrictions, but the (commit model of the) underlying database.


      Enjoy, Have FUN! H.Merijn

        Last time I uses DBD::ODBC with MS SQL Server 7 and 2000, only one statement could be active at any time, due to protocol limitiations of the MS SQL Server and its predecessor Sybase.

        The protocol has been "extended" (or should I say botched?) since then to allow a complete different way for other SQL statements to execute in parallel to the main statement (I think this is called MARS). See DBD::ODBC::FAQ and http://www.easysoft.com/developer/languages/perl/multiple-active-statements.html for the ugly details.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: Perl DBI execute statement
by Marshall (Canon) on Dec 12, 2016 at 07:30 UTC
    You have been told repeatedly not to use IGNORE in your prepare statement. Why do you keep doing that? I am curious about that point.

    "My insert statement for staging would be below:"

    my $ext_insert = $dbh3->prepare("INSERT IGNORE INTO $feed_table_ext (id_code, item_name, item_value, item_data) VALUES (?, ?, ?, ?)") or die $dbh3->errstr;

    Update:
    It is difficult for me to understand your objective, but perhaps something close to this is what you mean?
    ====== following your code ===== use Data::Dumper; #get Id_Codes based on entry time # my $feed_table_idcode = $dbh2->prepare("SELECT id_code FROM $feed_table WHERE entry_time >= ?"); #get all columns for each id_code in another table + my $feed_table_ext_results = $dbh2->prepare("SELECT * FROM $feed_table_ext WHERE id_code = ?"); $feed_table_idcode->execute($time); while (my @row = $feed_table_idcode->fetchrow_array() ) { my $id_code = $row[0]; $feed_table_ext_results->execute($id_code); print Dumper $feed_table_ext_results,"\n"; }
    Since these tables are both in the same DB, I think that some type of SQL JOIN will get the job done. Without a test DB, I won't attempt it, but that appears plausible to me.

      Thank you, the code is what I wanted, but I have figured out my issue, I get the following error:

      DBD::mysql::st fetchrow_array failed: fetch() without execute() at /ho +me/rdscopy.pl line 204. DBD::mysql::st fetchrow_array failed: fetch() without execute() at /ho +me/rdscopy.pl line 204.

      when there is no data in the table facebook_321_ext table in production, so the query reutrns nothing and then the insert statement below " while (my @insert_ext = $feed_table_ext_results->fetchrow_array())" which is line 204 gives that error, but it works when data is there upon other test.

      while (my @insert_ext = $feed_table_ext_results>fetchrow_array()) { $ext_insert->execute(@insert_ext) ; }
      Is there a way I can error check before executing?

        as poj has already pointed out "I suspect there are other problems" but you have at least successfully identified that you get that error when $feed_table_idcode->fetchrow_array does not return any rows, because then $feed_table_ext_results->execute never gets executed. One way to test if it has returned any rows is to set some sort of flag to false as a default state, and then set it to true if $feed_table_idcode->fetchrow_array did return a row, (and $feed_table_ext_results->execute gets executed). Then you can skip the $feed_table_ext_results>fetchrow_array loop if your flag is still false

        for instance $did_ex_flag=0; sets a flag to false, and $did_ex_flag=1; sets it to true, and if ($did_ex_flag) { ...} can be used to test it.

        another way, that might be more useful, would be to move the $feed_table_ext_results->fetchrow_array loop to right after the $feed_table_ext_results->execute statement. Of course you now realize the $feed_table_ext_idcode = statement needs to be before that point.

        Is there a way I can error check before executing?

        Yes, but I suspect there are other problems. How many lines are there in the whole script ? You need to show how the 3 execute statement are nested together

        poj
        This error message is saying that:
        my $nRows_affected = $feed_table_ext_results->execute(..)
        was never executed. Why that is, I don't know at the moment, but it appears that there a number of posts that address this issue.

        Please adjust the formatting of your code to something similar to this:

        while (my @insert_ext = $feed_table_ext_results->fetchrow_array()) { $ext_insert->execute(@insert_ext) ; }
        Instead of what you posted:
        while (my @insert_ext = $feed_table_ext_results>fetchrow_array()) { $ext_insert->execute(@insert_ext) ; }
        The Perl compiler doesn't care about huge indentations of the braces, but the humans do care.
      thank you for your reply, I use IGNORE, I am copying data from production to staging, and during this process, sometimes data will already be in staging and INSERT IGNORE will then not give me a duplicate key error. I will review and try to implement your code, it makes, sense.
        I am not a DB guru, but a failed INSERT sounds like a pretty big deal to me. Example: (primary_key,b,c,d). If an insert of that record fails because the primary_key exists, what about the values of b,c,d? Maybe this "INSERT" had new values for b,c,d?

        I would think that instead of an INSERT, an UPDATE might be more appropriate in your situation? If the UPDATE fails because no record with that primary key exists, then you INSERT a brand new record with that primary key and data fields, otherwise if the UPDATE succeeds, the data fields other than primary are updated.

Re: Perl DBI execute statement
by huck (Prior) on Dec 12, 2016 at 09:07 UTC

    There is a lot of other things you are not telling us. like what is line 199? (is it $feed_table_ext_results->fetchrow_array?) What is in $time. Are you sure that this line $feed_table_ext_idcode->fetchrow_array() is actually returning any rows? If it does not then $feed_table_ext_results->execute(@row); <never gets executed

    You need to also realize that the $feed_table_ext_idcode->fetchrow_array loop executes over and over for each $id you get after $time leaving only the results for the last id_code selections available in $feed_table_ext_results->fetch... but that does also assume it returns any rows

    An the fact that there are two errors listed for 199 seems to suggest that that statement is inside some sort of loop you may not be showing us

    and you should look up how to use $feed_table_ext_results->finish, i suspect you will need to insert somethng like that soon