PDO fetchAll seems to fail when result has single row? - php

I'm stumped. Consider the following test table:
----------------
| art_projects |
----------------------------------
| project_name | project_creator |
|--------------|-----------------|
| Flying Feet | 1 |
| Dinosaurs | 2 |
| Roadblock | 1 |
----------------------------------
Paired with it, consider the following code (where $db is a confirmed-functional PDO instance):
$dbObj = $db->prepare("SELECT * FROM art_projects WHERE project_creator = ?");
$dbObj->execute([1]);
print_r($dbObj->fetchAll(PDO::FETCH_ASSOC));
Very simple, very little can go wrong. This functions as expected and returns the following result set:
----------------------------------
| project_name | project_creator |
|--------------|-----------------|
| Flying Feet | 1 |
| Roadblock | 1 |
----------------------------------
Here's where the problem starts. If I change the execute() to search for ID 2 instead of 1, I'd expect it would return a single-row result for Dinosaurs. It doesn't - I get this instead:
1
When I change $dbObj->fetchAll(...) to $dbObj->fetch(...), though, I get the expected single-row result. The heck...?
Now, I'm pretty new to PDO, but I'm assuming this is expected behavior; I can't seem to find anything about this being an "error", here or elsewhere on Google. Can someone explain this behavior to me?
Furthermore, is there an accepted/effective method to deal with this? IMHO, It's kind of a Catch-22 to test the length of the result set for the sake of using the right fetch method, and it's unreasonable to magically know when your result set is going to be single-row or multiple-row.

FETCH_ASSOC isn't a valid documented mode for PDO::FetchAll(). When it gets more than one result set row it's probably doing some sort of filling in of an associative array that wipes out the contents.
If I were you I'd loop and do the ordinary fetch() call once per row.

Related

Is it possible to reference a MySQL table dynamically?

I can't find anything about dynamically referencing a MySQL table entry in my particular case. Most everything I've read leans towards it not being possible, but I'm hoping someone can prove me wrong.
Essentially, I've got multiple MySQL tables that I'm trying to pull data from on an Android app. I want to access 2 at a time. The 1st Table's name always stays the same, history. The 2nd Table's name, however, may be different at times. It's value is determined within the app and referenced with :job in my php script (I'll use moon for my example). The 2nd table itself is generated dynamically through the app, so I guess I'm trying to set up a reference within a php script I have saved to a server so that I can access the 2nd Table.
Sorry for the confusing description, I hope these tables will help explain what I'm trying to get at.
Table #1: history (always stays the same)
| site | code | hours|
|---------|---------|------|
| moon | first | 1 |
| moon | second | 2 |
| moon | third | 3 |
| earth | fourth | 4 |
Table #2: moon (this one I want to dynamically reference)
| code | hours|
|---------|------|
| first | 10 |
| second | 11 |
| third | 12 |
And my current code:
...
/*** Table #1 ***/
SELECT code,
SUM(hours) AS total, '' AS target
FROM history
WHERE site = :job /* :job ends up being moon in this example */
GROUP BY code
UNION ALL
/*** Table #2 ***/
SELECT code,
'' AS total, SUM(hours) AS target
FROM :job /* <--- I'm trying to do something along these lines and use 'moon', or 'earth', or whatever... */
GROUP BY code
...
And later I get :job from the app: (moon)
$query_params = array(
':job' => $_POST['jobname'],
);
Result I'm Looking For: (works perfect if I directly use Table #2's name (ie moon) in my php file)
| code | hours|target|
|---------|------|------|
| first | 1 | 10 |
| second | 2 | 11 |
| third | 3 | 12 |
The code absolutely works as expected when I replace the :job in the 2nd table with the actual name of the table. I'm wondering if there is some way to still do it dynamically though?
Thanks for any and all advice!
I've done some pretty extensive searching and haven't come up with anything that works for me.
Is it possible to reference a mysql table entry value from a second table entry dynamically?
https://dev.mysql.com/doc/refman/5.7/en/derived-tables.html
MySQL table.* AS reference
Retrieve parent-child hierarchy from a self-referencing mysql table

MySQL - Do queries *always* begin searching at the start of the table?

I can't find a clear answer for this anywhere in MySQL documentation.
When I run a query, something like:
Code Block 1
$stmt = $db->prepare('SELECT id, name FROM table WHERE status=1');
does the search start at the beginning of the table, at row 0 (or the lowest available row)?
What I'm trying to do is go through a table one row at a time, and then exit when I get to the end:
Code Block 2
$curRow = 0;
while(true){
$stmt = $db->prepare('SELECT id, name FROM table WHERE status=? AND id>? LIMIT 1');
$stmt->execute(array(0, $curRow));
$result = $stmt->fetchAll();
if(count($result)){
$curRow = $result[0]['id'];
$stmt2 = $db->prepare('UPDATE table SET status=? WHERE id=?');
$stmt2->execute(array(1, $curRow));
... do some other stuff ...
}else{
exit();
}
}
And so far, in testing, this has worked exactly as intended. But will it always be so?
Possible erroneous case:
Start out with the following table:
table
id | name | status
-- | ---- | ------
1 | ... | 0
2 | ... | 0
3 | ... | 0
4 | ... | 0
5 | ... | 0
6 | ... | 0
And run the query in Code Block 2. Say it starts at the first row, so now we have $curRow=1, and the table looks as follows:
table
id | name | status
-- | ---- | ------
1 | ... | 1
2 | ... | 0
3 | ... | 0
4 | ... | 0
5 | ... | 0
6 | ... | 0
All is well. The code does whatever it needs to, and then continues with the loop. Any of the remaining rows will satisfy the conditions in $stmt (i.e. status=0 and id>$curRow).
Will the statement always look at consecutive rows when checking the conditions? If not, it could end up at any arbitrary row, say the third:
table
id | name | status
-- | ---- | ------
1 | ... | 1
2 | ... | 0
3 | ... | 1
4 | ... | 0
5 | ... | 0
6 | ... | 0
And now we have $curRow=3, which means the query will never go back and look at the second row.
I know it's tricky business speaking in absolutes (always, never, every time, ...), but is there a way to ensure that the query begins at the lowest available row? Or does MySQL handle this automatically?
There is no guarantee for any reliable order when you do not explicitly set it to a key. It might seem to be ordered for now, but over time, with more data, maybe with more servers, partitioned data, union'ed data, it will change quickly to something unexpected.
Better use ORDER BY:
$stmt = $db->prepare('SELECT id, name FROM table WHERE status=1 ORDER BY ID ASC');
Make sure you have an index on the column you want to order by, it will speed up things!
You should not write such a code which has such assumptions of your database. Your code might get less maintainable, harder to debug when some change comes to your database and that'll be a total headache for you. You should think of other mechanisms / workarounds to get the job done which is also more professional.
You might want to add a column which will provide that they can be ordered. For example date, ID, whatsoever.
Look up ORDER BY clause.

AND and GROUP BY in Aerospike PHP Client

I am currently examining aerospike for replacing my company MySQL database. Currently, in MySQL, we have a table that stores the transaction data, the table looks like this :
+--------+------------+-----------+------------+-----+--------+
| trx_id | trx_date | client_id | product_id | qty | total |
+--------+------------+-----------+------------+-----+--------+
| 1 | 2015-01-01 | 1 | 1 | 100 | 100000 |
| 2 | 2015-01-02 | 2 | 2 | 200 | 200000 |
| 3 | 2015-01-03 | 3 | 3 | 300 | 300000 |
+--------+------------+-----------+------------+-----+--------+
For reporting, we usually do something like :
SELECT MONTH(trx_date), SUM(qty), SUM(total) FROM transaction WHERE client_id = 1 AND product_id = 1 GROUP BY MONTH(trx_date)
to get the monthly transaction data for a client.
I've read the documentation for the Aerospike PHP client and I don't seem to find anything similar to AND, GROUP BY, or MONTH.
So, in Aerospike PHP client, what is the recommended way to achieve something like that?
Thanks.
Aerospike is a NoSQL key-value store, and as such you can't expect to use SQL with it. However, using Lua as the User-Defined Function (UDF) language, you can extend the basic functionality.
What you are looking for is an aggregation, applying a stream UDF to the results of a query.
There is an example of implementing a GROUP BY x HAVING in the PHP client's documentation for the aggregate() method. The thing to remember is that you want the secondary index query to eliminate as many records as you can, so that predicate should used for the 'WHERE', and the secondary filtering for the 'AND' should happen inside the stream UDF's filter on the smallest possible data set.
Reading the UDF Development Guide would also help.

Why does this query return different values?

I'm trying to pull information from my database, but the query I'm using is only pulling all of the values after the first one. I have no LIMIT set, but I did try setting a LIMIT 0,30 with no change. In phpMyAdmin, the query returns what I expect. In my PHP file, it returns what I've explained.
The query is :
SELECT * FROM `mainSite_others` WHERE forGame='$gameName'
gameName is previously provided, and I suspect no errors because it does return at least two values. The forGame value in the database is all the same, a constant "+Stellar+Dawn".
The PHP code is:
while ($gameOther = $database->fetchArray($gameOtherQry)) {
echo $gameOther['otherName'];
}
Don't worry about the $database->fetchArray part, that is just my DB class, which works fine as far as I know.
The table I am extracting from looks like this (this is with all the values contained):
id | forGame | otherType | otherName | otherDesc
9 | +Stellar+Dawn | Character | Car | Car
10 | +Stellar+Dawn | Item | Brugson Burson | a guy
11 | +Stellar+Dawn | Item | Space Pie | A pie from space
I am using mySQLi.
Any ideas? Thank you.
You're probably doing a fetch call BEFORE you reach the while loop, which "loses" the first row of the results.

PHP Sum from Access using Array

I have a question involving PHP arrays and adding up the values.
I have an access database with information in this scheme
----------------------
| time | code |
|------|-------------|
| 600 | broke down |
| 500 | broke down |
| 300 | waiting |
| 200 | waiting |
| 400 | remove coil |
Anyways, you get the idea. I have multiple code values, but can have multiple time values for one code. What I am trying to accomplish with PHP is to add up all time values and only display one code value.
The result I want would be:
1100 | Brokedown (600 & 500 added together)
500 | Waiting (300 & 200 added together)
400 | Remove Coil
Just for example. I think I should be using a multidimensional array, but I just cannot seem to wrap my head around what to do exactly with it. A point in the right direction would be greatly appreciated.
Why not SQL?
SELECT Code, Sum([Time])
FROM Table
GROUP BY Code
Time is a reserved word, so I guess it is an imaginary name. If it is real, you must enclose it in square brackets, or better, change it.
You can actually use SQL for this to return what you're looking for.
SELECT SUM(time), code FROM table_name GROUP BY code

Categories