I am trying to make a database query where I search for all of the items which have a lower current level than low stock level. When running the query I am getting no results and I'm not sure why.
This is my query
public static function getLowStockItemsCache()
{
dd(\DB::table('items')->where('current_level', '<', 'low_stock_level')->get());
}
When I die and dump this I get an empty collection.
In my database I have the following records
Both of these fields at set at int(11)
If I reverse the query I get all 13 records.
Am I missing something small, as it's confusing me greatly and should be simple.
The third parameter is the value parameter which means it will be escaped when building the query to avoid SQL injection. If you want to compare two columns, you have to specifically tell the Query Builder that that part of the query should not be processed, either by using whereRaw to pass the raw SQL condition:
\DB::table('items')->whereRaw('current_level < low_stock_level')->get());
Or by using DB::raw() for the value only, so it's not escaped:
\DB::table('items')->where('current_level', '<', DB::raw('low_stock_level'))->get());
Laravel use 3 step argument on the "where" clause,
Pair::where('1st','2nd','3rd')
by default the 2nd arg is normally default equal sign, saying the 1st arg is equal to the 3rd arg,
Pair::where('name', 'john')->get();
Pair::where('stock', '<', '100')->get();
When you find this logics then you understand the "where" tricks
Related
I am using a Laravel query builder to search for categories.
Here it is:
$array[] = $categories->where('pk_i_id', $category_id)->first();
I have to manually convert the category id to string, even though in database it is Integer type. Why do I have to do this?
Actually - I have to do this on Linux machine with Lamp stack installed. On Windows machine with Xampp it considers the column as integer as it should.
The issue sounds more like that $categories is already a Collection, not a Builder. Both the Collection and the Builder have a where() method, but their logic is not the same.
The where() method on the Builder will add a parameterized where clause to the query run against the database. In this case, the type of variable doesn't matter.
However, the where() method on the Collection will loop through the collection and return those results where the field in the first parameter is strictly equal (===) to the value passed in the second parameter. To change this, you can pass false as the third parameter, and it will use a loose comparison (==) instead of strict. Additionally, you could use whereLoose(), which is a shortcut for where() with the third parameter as false.
$array[] = $categories->where('pk_i_id', $category_id, false)->first();
// or
$array[] = $categories->whereLoose('pk_i_id', $category_id)->first();
If the incorrect field types are causing more issues that what you've described, then you may want to work on fixing the underlying issue. As has been pointed out in the linked posts, on your LAMP stack you need to replace the mysqld driver with the mysqlnd driver.
I have been working on laravel using eloquent query builders. I have a situation in which I am filtering records based on search queries. I have an integer field, for which I want to filter data in ranges. User can select any of available ranges for example;
0-15, 15-30 and 30 and above.
For this purpose I found Query-builders whereBetween() clause very helping. But It becomes difficult for me for last option when I want to select for 30 and above.
I would really appreciate if someone could help me with some trick make this query
->whereBetween('time_taken', [$lower-limit,$uper_limt])
working for all cases.
I don't want to write an additional line for this case, at which I can use simple where clause
->where('time_taken','>=',$uper_limt).
The practical solution here is to just choose the appropriate SQL condition (I'm using a ternary operator here to keep it more compact):
$query = App\Operation::query();
(empty($upper_limit)) ? $query->where('time_taken','>=', $lower_limit)
: $query->whereBetween('time_taken', [$lower_limit, $upper_limit]);
$results = $query->get();
Sure it would be nice to have just one line:
$results = App\Operation::whereBetween('time_taken', [$lower_limit, $upper_limit])->get();
But that's not possible in this case, not unless you want to extend the Laravel Query Builder and modify the way it handles empty parameters in the range passed as the value.
Writing clean and concise code is something we all strive to achieve, but one line solutions are not always possible. So my advice is to stop fixating (something I sometimes do myself) on things like this, because in some cases it's a lost cause that just ends up wasting time.
You can try any of these:
Method 1:
->whereBetween('time_taken', [$lower-limit,ModelName::max('time_taken')])
Method 2:
->whereBetween('time_taken', [$lower-limit,DB::table('table_name')->max('time_taken')])
Method 3:
$max = ModelName::max('time_taken');
//or
$max = DB::table('table_name')->max('time_taken');
//then
->whereBetween('time_taken', [$lower-limit,$max])
max() returns the highest value from your corespondent column.
I'm using Laravel built in paginate method in a query where i need search in Fulltext against a large dataset (about 100K rows with huge amount of text each).
All working fine, except i do not understand the logic in how laravel counts the results: why must execute the same query two times (the select count() as aggregate) for retrieve the total count of results, and not use the php function count(), that works great in this scenario.
Because with this method, I can literally half the time of this search, that sometimes can take up to 10 second!!
It is really necessary to use 2 query, or it is possible in some way to override this logic?
Or maybe it's me that I'm missing something behind this logic?
The query is executed twice, once to get the total number of records returned by the final query, and the second time to return only the required dataset.
So, if you have a table of 100,000 records, the first query will count the records returned by the SQL query, let's say 8,900 records match your requirement, it will return an integer of 8,900.
The second query then uses the page number you want, multiples it by the count per page, and then returns the relevant 15 or so records from just this page, which is the LIMIT and OFFSET values within your SQL query.
It is worth noting that GROUP BY paginated results are not handled in the same way. If you add GROUP BY to the end of any SQL statement within eloquent, it returns a single SQL query. This query grabs all the relevant datasets, counts the number of rows returned, and then slices the array to return just the 15 or so records you require.
The difference between these two methods is the first returns 2 tiny query responses. Firstly the total count, and secondly 15 or so datasets from your table.
The GROUP option returns a dataset for EVERY record which matches your SQL requirements. If this is a total of 8,900 records, it will be a total of 8,900 eloquent model objects.
As you can see, if you have a database with a good number of records in it, the the second method, while it may execute the SQL statement quicker, will tie up a lot more resource.
If your SQL statements are taking too long to execute twice, you may need to consider optimising your table, or adding a further INDEX. Just a thought.
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
In my program I launch an SQL query and get back a result resource. I then iterate through the rows of this result resource using the mysql_fetch_array() function and use the contents of the fields of each row to construct a further SQL query.
The result of launching this second query is the first set of results that I want. However, because the number of results produced by doing this is not many I want to make the search less specific by dropping the last record used to make the query.
e.g. the query which produces the first set of results I want could be:
SELECT uid FROM users WHERE (gender=male AND relationship_status=single
AND shoe_size=10)
I would then want to drop the last record so that my query became:
SELECT uid FROM users WHERE (gender=male AND relationship_status=single)
I have already written code to produce the first query but as I mentioned above I use the mysql_fetch_array function to iterate through ALL of the records. In subsequent "rounds" I only want to iterate through successively less records so that my query is less specific. How can I do this?
This seems like an very inefficient method too - so I'm welcome to any simple ideas which might make it more efficient.
EDIT: Thanks for the reply - Yeah I am actually doing this in my program. I am basically trying to implement a basic search algorithm by taking all the preferences a user has specified in the DB and using it to form a query to look for people with those preferences. So the first time search using all the criteria, then on successive attempts search using one less criteria and negate the user ids which were previously returned. At the moment I am constructing the query from scratch for each "round", but I want to find a way I can do this using the last query
Using the queries above, you could do:
SELECT uid
FROM users
WHERE uid NOT IN (
SELECT uid
FROM users
WHERE
(gender=male
AND relationship_status=single
AND shoe_size=10)
)
This will essentially turn your first query into a sub-query, and use that to negate the results returned. Ie, it will return all the rows, NOT IN the first query.