MySql query with limit showing one less element - php

I have a php file which generates a webshop layout.The problem is when I started to split the products to pages. I have the following query wich runs in the products database where every kind of product can be found. There is a prodducttype column which specifies under which menu it should be displayed.
The query
$sql = "SELECT id,descr, nm, img, price FROM c1640644.products WHERE
producttype = '".$GLOBALS["useableproductid"]."' LIMIT ".($start- 1).",".$stop;
There is one row which always missing
I used echo to display the query just before running it its the following:
SELECT id,descr, nm, img, price FROM c1640644.products WHERE
producttype = 'laptop' LIMIT 0,8
Briefly about the database:
Currently 3 types of products laptops, headphones, desktops.
When displaying laptops they are from ID 1- 17 and ID=1 is missing. Headphones from ID 18-22 and ID=21 is missing. Desktops from ID 23-27 and ID=23 is missing. Always the same products are missing.
The displaying method is:
while($row = $result->fetch_assoc()){
echo $row["nm"]; //just an example echo in the code it gets displayed with design
...
}
Thank you for all the answers!

The most reasonable explanation for the observed behavior ("missing" row for 'laptop' and a "missing" row for 'headphone') is that the rows do not satisfy the predicate, equality comparison to producttype. (This assumes there are fewer than $stop-$start rows is being returned.
I'd verify the values of producttype.
SELECT producttype, COUNT(1)
FROM c1640644.products
GROUP BY producttype
ORDER BY producttype
Is the count returned equal to the number of rows you expect to be returned? In particular, I'd look for values that are visually close to "laptop", but would not satisfy an equality match, such as 'laptop ultra-portable', or 'lapt0p'. Those values would not satisfy an equality comparison to 'laptop'.
Without an ORDER BY clause, MySQL is free to return rows in any order. The result from the query with the LIMIT clause is indeterminate. It's possible that a query with LIMIT 0,8 and LIMIT 8,16 may include the same row. It's also possible that a row will be "skipped".
If the case is that there is always "one row missing", I'm suspicious that there's a fetch before the while loop. The loop shown in the question looks right. It's also possible that nm column contains an empty string, and it makes it look like a row is "skipped". For debugging that, consider including echo "row fetched"; as the first line inside the loop. Or initializing a counter variable before the loop $i=0;, and then inside the loop, increment $i and include $i in the string that in the debug output.

Related

PHP odbc_exec not returning all rows

This simple query
SELECT
DBA.Goods.ID, /* PK in the Goods table */
DBA.Goods.Name,
DBA.GoodsGroup.Name as GdGrp,
DBA.InvoiceItem.Qty,
DBA.InvoiceItem.ID, /* PK in the InvoiceItem table */
DBA.InvoiceItem.PrintName,
DBA.InvoiceItem.Price,
DBA.InvoiceItem.InvoiceID, /* PK in the Invoice table, a parent table of a sort */
DBA.InvoiceItem.InvoiceItemOrder,
DBA.InvoiceItem.ProcPrice,
FROM (
DBA.Goods INNER JOIN DBA.InvoiceItem
ON DBA.Goods.GoodsSk = DBA.InvoiceItem.GoodsSK
)
INNER JOIN DBA.GoodsGroup
ON DBA.Goods.GroupID = DBA.GoodsGroup.ID
WHERE DBA.InvoiceItem.InvoiceID = $invoiceID /* ID of a specific invoice, used here to get to its contents, i.e. specific items within that invoice */
when run in DBExplorer (a DB tool for executing raw SQL queries), returns 5 rows (contents of an invoice). Everything is setup in such a way that an invoice may contain multiple goods of the same ID (but with different prices and procurement prices, printing names - e.g. bucket-white, bucket-blue, bucket-red, etc). Each of the items gets a unique ID within the Items table. The aforementioned 5 rows are the expected result (i.e. the goods in the list are the actual goods sold).
However, when the query is sent to the database via:
$result = odbc_exec($conn,$query);
odbc_num_rows($results) is not 5, as expected and seen in DBExplorer, but 3 - the (percieved) duplicates are not returned (of all the buckets in the previous example, only one is returned).
Furthermore, while looping through the results with
while($rowItems = odbc_fetch_object($result) {
...
}
there are only 3 iterations, instead of the expected 5.
Thinking that the column order might be causing problems (silly, I know), I moved the DBA.InvoiceItem.ID to the top, making it the first column in the result set. However, that did nothing.
Why is this happening, and how can I make it return the full result set?
Note
I am aware that there are similar questions on SO:
php odbc_exec not returning all results
why doesn't this code return all rows?
Not getting all rows from a query with odbc_exec in php
but none of them actually address the issue presented here - how to get ALL of the rows as seen in the DB tool, instead of a reduced result set.
The trouble was with the query. As soon as I'd changed it by changing the joining order, everything worked as expected. The key was to make DBA.InvoiceItem the main table, and join everything with it. I still have no (clear) idea why this worked.

MySql Order by Field last uploaded get first in front of ordered id's

I'm trying to order some datas and use ORDER BY FIELD. The order for the given id's looks well, but when i add another record in database this record just get in front of the ordered id's datas. When i add another record i want that record to be the last after the ordered ones. The code i use is below:
$result = mysqli_query($conn, 'SELECT * FROM echipa ORDER BY FIELD(id_profesor, 14,17,16,24,25,22,26,19,20,21,18,23)');
One solution where you don't have to repeat the expression is to convert the 0 to a NULL and then the NULL to something else:
ORDER BY COALESCE(NULLIF(FIELD(id_profesor, 14,17,16,24,25,22,26,19,20,21,18,23), 0), 9999)
Another is to use the fact that a descending sort puts NULLs last:
ORDER BY FIELD(id_profesor, 14,17,16,24,25,22,26,19,20,21,18,23) DESC
However, you might want to reverse the order of the list to keep the rows in the original order.
Or, if you really want to be fancy, you can do something like this:
ORDER BY - NULLIF(FIELD(id_profesor, 14,17,16,24,25,22,26,19,20,21,18,23), 0) DESC
I would consider the intention rather inscrutable in this case.
You can use an if statement in the order by:
SELECT *
FROM echipa
ORDER BY IF(FIELD(id_profesor, 14,17,16,24,25,22,26,19,20,21,18,23)=0,1,0),
FIELD(id_profesor, 14,17,16,24,25,22,26,19,20,21,18,23)
The problem is field returns 0 for non matching records, which would return at the top of the list. This forces records not found to the bottom.

Adding count(*) to existing mysql query causes unwanted action in php

$results_ts = mysqli_query($connection, "SELECT id, title, description, content
FROM prose WHERE title LIKE '%$search_title%' LIMIT 10");
if(isset ($_GET['search_title'])){
while($title_arr = mysqli_fetch_array($results_ts)){
echo $title_arr[id]; //and so on...
And that works as I wanted.
but when I try to add , count(*) after where content is, than while() loop echoes only one result, even when $title_arr[4](which stands for count) results in many.
Is it possible to do it this sort of way, or should I be running two separate queries?
You shouldn't do that in one query.
Think about the result you're expecting: when you do a count(*) query, what you get back is a result with only one row and one value. If you select multiple lines, then what should it do? Inject the count into each row of the data?
From a logical perspective, those are two different things you're looking for.
EDIT: counting the rows in your result after the fact is probably the best option, but that won't work if you're only looking for the first 10 entries, and there's no reason to SELECT the whole table if you don't need all the data. That's why count(*) is fulfilling such a different role.
COUNT() is an aggregate function so you can't use it like this. But if all you want is the number of rows this query would have returned you can use SQL_CALC_FOUND_ROWS to get the number of rows that would have been returned if thee was no LIMIT clause. You then can get the results by calling SELECT FOUND_ROWS() after your query is run.

MySQL fetch multiple values with one query and turn them into printable variables

i have a question regarding the simplification of my PHP code.
I am building a product selection module for a webshop. I want to fetch the value of certain columns from the top 3 rows from a table called 'BestProducts'.
Let's say I would like to know the Product price of the first, second and third product in the table.
With the PHP skills I have at the moment, I would query the database 3 times, to fetch the product price of the three products individually. After the query I would convert the results from object into a printable variable (also individually).
I'm sure there must be a more efficient and thus less time/performance consuming way to fetch these three prices and to turn them into printable variables, so that I can show the prices on my webpage.
I think i should fetch three product prices by using only one query, and then extract this query into three separate variables. I do not know, however, how to do this exactly. Help is greatly appreciated!!
You can use LIMIT to limit the amount of results that yor query will output, try something like this
SELECT * FROM yourtable LIMIT 0,3 ORDER BY somecolumn
this result will output the first 3 results of the table ordered by the specified column, and then fetch them in a loop, maybe using this
http://php.net/manual/en/function.mysql-fetch-array.php
If I understood correctly you want to get the first 3 rows of your BestProducts table, to do that you can make a query like this:
$query = "SELECT your_column1, your_column2, your_columnN FROM BestProduct ORDER BY your_criteria DESC LIMIT 3;
I will suppose you already have a connection with your database, so the next step it's to execute the query and iterate over the result
if ($result = $mysqli->query($query)) {
/* to get the associative array */
while ($row = $result->fetch_assoc()) {
printf ("%s (%s)\n", $row["your_column1"], $row["your_column2"]);
}
/* free the result set*/
$result->free();
}
Reference: http://www.php.net/manual/es/mysqli-result.fetch-assoc.php

Why does mysql_num_rows return 1 for a SELECT on an empty table?

The code:
$review = mysql_query("SELECT conceptID, MIN(nextReview) FROM userconcepts WHERE userID='$userID'");
$nrows = mysql_num_rows($review);
echo "$nrows<br />\n";
The query works when the table has such entries and returns the correct column values. However, when the table is empty, as I can confirm right now in HeidiSQL, mysql_num_rows still returns 1, but the column values are empty. (The problem still remains if the table has other values for different userIDs).
I expect this query to return the empty set sometimes during normal operations, and I want to take action based on the existence of a result, but I also want to use the result if it exists. Any idea why this code is not working as I expect it to work (I expect it to return 0 if the table is empty)?
First of all, the query has a very simple problem: you're showing the conceptID field, but not grouping by it. If you want to show a field on a SELECT that uses aggregate functions, you should show it; not doing so is an error, and will make many engines not execute your query.
That aside, whenever you have an aggregate function, and you don't group by anything (i.e., don't add a GROUP BY clause), the result is one row. Regardless of the amount of rows in the table.
The reason why is because when a SQL engine executes a query with only aggregation functions, then it returns one row. So:
select count(*)
from table
where 1 = 2
is going to return 1 row with the value 0. This is the way that all SQL engines work.
Your query is a little different:
select conceptID, MIN(nextReview)
FROM userconcepts
WHERE userID='$userID'"
In most SQL dialects, you would get an error of the from "conceptID not in group by clause" or something like that. That is, the query would have a syntax error.
MySQL supports this. It will return the minimum value of nextReview (from the rows that meet the where condition) along with an arbitrary value of conceptID (from those same rows). In this case, there are no rows, so the values will be set to NULL.
Perhaps, you want one row per conceptId. That query would be:
select conceptID, MIN(nextReview)
FROM userconcepts
WHERE userID='$userID'
group by conceptId

Categories