From raw SQL to Laravel Eloquent or query builder - php

I've used a slow Eloquent query and I changed it to faster one but with raw SQL
There is GroupBy used in the later part of code and now it fails.
$app_visits = DB::select(DB::raw('select id, place from table where 1=1'));
$app_visits = $app_visits->groupBy('place');
is there an easy way to use similar method with the raw table I'm getting?

Can't you just also use in the raw query the groupby?
$app_visits = DB::select(DB::raw('select id, place from table where 1=1 GROUP BY place'));

Related

How can I use an SQL query's result for the WHERE clause of another query?

Okay, basically I have a table that contains statements like:
incident.client_category = 1
incident.client_category = 8
incident.severity = 1
etc.
I would like to use the contents from this table to generate other tables that fulfill the conditions expressed in this one. So I would need to make it something like
SELECT * FROM incident WHERE incident.client_category = 1
But the last part of the where has to come from the first table. Right now what I'm trying to do is something like
SELECT * FROM incident WHERE (SELECT condition FROM condition WHERE id = 1)
id = 1 stands for the condition's id. Right now I only want to work with ONE condition for testing purposes. Is there a way to achieve this? Because if there isn't, I might have to just parse the first query's results through PHP into my incident query.
Table schemas:
Engineering Suggestion - Normalize the DB
Storing a WHERE clause, like id = 10, in a field in a MySQL table, is not a good idea. I recommend taking a look at MySQL Normalization. You shouldn't store id = 10 as a varchar, but rather, you should store something like OtherTableid. This allows you to use indices, to optimize your DB, and to get a ton of other features that you are deprived of by using fields as WHERE clauses.
But sometimes we need a solution asap, and we can't re-engineer everything! So let's take a look at making one...
Solution
Here is a solution that will work even on very old, v. 5.0 versions of MySQL. Set the variable using SET, prepare a statement using PREPARE, and execute it using EXECUTE. Let's set our query into a variable...
SET #query = CONCAT(
"SELECT * FROM incident WHERE ",
(SELECT condition FROM condition WHERE id = 1)
);
I know for a fact that this should work, because the following definitely works for me on my system (which doesn't require building any new tables or schema changes)...
SET #query = CONCAT("SELECT id FROM myTable WHERE id = ", (SELECT MAX(id) FROM myTable));
If I SELECT #query;, I get: SELECT id FROM myTable WHERE id = 1737901. Now, all we need to do is run this query!
PREPARE stmt1 FROM #query;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
Here we use a prepare to build the query, execute to execute it, and deallocate to be ready for the next prepared statement. On my own example above, which can be tested by anyone without DB schema changes, I got good, positive results: EXECUTE stmt1; gives me...
| id | 1737901 | .
here is one way to achieve your goal by using what is called dynamic sql, be ware that this works only select from condition table returns only one record.
declare #SQLSTRING varchar(4000)
, #condition VARCHAR(500) -- change the size to whatever condition column size is
SELECT #condition = condition
FROM
condition
WHERE
id = 1
SET #SQLSTRING= 'SELECT * FROM incident WHERE ' + #condition
exec sp_executesql(#SQLSTRING)
Since you have also tagged the question with PHP, I would suggest using that. Simply select the string from the condition table and use the result to build up a SQL query (as a string in PHP) including it. Then run the second query. Psudo-code (skipping over what library/framework you re using to call the db):
$query = "select condition from condition where id = :id";
$condition = callDbAndReturnString($query, $id);
$query = "select * from incident where " . $condition;
$result = callDb($query);
However, be very careful. Where and how are you populating the possible values in the condition table? Even how is your user choosing which one to use? You run the risk of opening yourself up to a secondary SQL injection attack if you allow the user to generate values and store them there. Since you are using the value from the condition table as a string, you cannot parametrise the query using it as you (hopefully!) normally would. Depending on the queries you run and the possible values there as conditions, there might also be risk even if you just let them pick from a pre-built list. I would seriously ask myself if this (saving parts of SQL queries as strings in another table) is the best approach. But, if you decide it is, this should work.

Codeigniter 3 Oracle Set Query Builder Case Insensitivity

Using Codeigniter 3 at work with Oracle 12c and sporadic uses of the Query Builder class.
Query Builder is selecting from Oracle with escaped table names. I would like to configure the class to not do this. I'd like this call:
$query = $this->db->get('customers');
to go from
select * from 'customers';
to
select * from customers;
in generated SQL.
Is there a config item I don't know about or am I going to have to fix one of my coworker's queries every three weeks until the end of time?
You have to use next syntax
$this->db->select('SELECT * FROM customers', false)->get();
since second parameter in select($tablename, $escape=NULL) method will prevent table name or field names escaping when set to FALSE.

Make eloquent give only sql clause

I was trying to rip off every connection function of Laravel's eloquent to give me SQL clause without querying it with PDO ( I also cleaning off every PDO instances from the code) and make eloquent a standalone package. I just want it to give me sql clause without connect to any db when I use an eloquent model just like this :
Request : Users::with('group')->take(5)->get();
Response : Select * from users.....
Can this be done ?
use ->toSql() instead of ->get()

Do I need to clean user input for DB::query calls in laravel?

Reading the Laravel documentation I see that:
Note: The Laravel query builder uses PDO parameter binding throughout to protect your application against SQL injection attacks. There is no need to clean strings being passed as bindings.
Does that still apply if I only craft queries in the following manner?
DB::query("SELECT * from table WHERE id like " . $id);
Let's take that sentence and emphasise the key phrase:
There is no need to clean strings being passed as bindings.
In your example, $id is not being passed as a binding, it is just being injected into the raw SQL, so it is not protected.
You should follow standard practice for preventing SQL injection:
in cases like this, where the input is always an integer, you could use intval($id)
you could get the underlying PDO object with DB::getPdo()/DB::getReadPdo() and use PDO::quote() to correctly escape strings
although the documentation is rather poor, Laravel's DB facade can run fully parameterised queries, such as DB::select('SELECT * FROM users WHERE users.id = ?', array($userId));
Parameterised queries are usually considered the gold standard in injection prevention, and are what Eloquent is using internally when you use the query builder. The idea is that you first give the database (or, at minimum, the database driver) the complete query with no user input at all, so there is no doubt which tables and columns should be in use. You then pass in the user input as completely separate data, which is never actually written into the SQL, just applied to the query you already sent.
Parameterised queries can't do everything for you, though - for instance, most libraries, including PDO, can't bind a table or column name as a parameter. That's because it will actually create a different query every time it is run, negating the separation between query and data. If you want to do that, you therefore need some other method of ensuring safety - usually, a whitelist of allowed values is the best idea.
No, DB::query() is not part of the concept of Query Builder. Instead, this will be protected:
DB::table('table')->where('id', 'like', $id)->get();
But the best way to protect your queries is to use Query Builder at its max:
DB::table('table')->where('id', 'like', $id)->get();
Another way to protect your queries, if you really are forced to write a raw query, is to cast your data to the type they are supposed to be:
DB::query(DB::raw("SELECT * from table WHERE id like " . (int) $id));
In this case if $id is 'some exploit' the query will be:
SELECT * from table WHERE id like 0
In Query Builder you can also pass your parameters (bindings) like this to harden the security of your queries:
DB::select('SELECT * FROM users WHERE users.id = ?', array($userId));

Query a Query - MySQL and PHP

I was recently trying to do a project*, which caused me to ask this question. Although since then I've found an alternative solution, I am still curious if what I envisioned doing is, in any way, possible.
Essentially, I am wondering if there is anyway to perform a MySQL query on a MySQL query result in php. For example:
$result = mysql_query("SELECT * FROM foo WHERE bar=".$barValue);
AND THEN, be able to perform multiple queries on $result:
$newResult = mysql_query("SELECT * FROM $result WHERE otherBar=".$barValue);
OR
$otherNewResult = mysql_query("SELECT * FROM $result WHERE otherOtherBar=".$barValue." ORDER BY foobar ASC");
AND so on and so forth...
I realize that I could append the original query with my new WHERE statements and ORDER BYs, but that causes my to query the database unnecessarily and it prevents me from writing more objected oriented code (because I can't pass around a result to be queried, but rather have to requery the database in every function...)
Any advice, pieces of code, frameworks, or ramblings appreciated.
*BTW, my project was having to query a large database of people for people born in certain age groups and then query those age groups for different demographics.
Edit
No, writing a custom function to query the database is not worth the object-orientation (and modifiability) it would give me
You could do a nested query in the same SQL query and keep PHP out of it:
'SELECT * FROM (SELECT * FROM foo WHERE bar="something") AS q1 WHERE q1.bar2 = "something else"'
The question has already been answered. However following explanation will help someone who might be interested in knowing the details of it.
What are Nested query / subquery:
Subqueries are also known as nested queries. A subquery is a SELECT statement within another statement. MySQL supports all SQL standards and additionally provides MySQL specific features.
Why should I use Subquery:
Subquery is structured and it is possible to isolate each parts of statement
Subquery is more readable that complex joins and unions
Subquery provides alternative means to perform action which otherwise would require complex joins and unions
What Subquery returns:
A subquery can return a single value, a single row, a single column, or a table. These are called scalar, column, row, and table subqueries.
Reference: http://dev.mysql.com/doc/refman/5.7/en/subqueries.html
http://www.w3resource.com/sql/subqueries/nested-subqueries.php

Categories