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.
Related
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.
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'));
There is an old project written in symfony 1.4
And there is SQL that it is not possible to create using Doctrine. For an example, consider this test SQL:
SELECT id,name FROM users
UNION ALL
SELECT id*10 as id,name FROM users
puvlic function getPager(){
$sql = "SELECT id,name FROM users
UNION ALL
SELECT id*10 as id,name FROM users";
$pager = new sfDoctrinePager('Users', 10);
$pager->setQuery($sql);
$pager->setPage(2);
$pager->init();
return $pager;
}
It gives the following error:
Fatal error: __clone method called on non-object in ...
Help please solve the problem.
With stock sfDoctrinePager class it's not possible to use a custom SQL string. It only accepts an instance of Doctrine_Query (see sfDoctrinePlugin sources).
You should construct a Doctring_Query object that does exactly what you need (which is likely not possible because of UNION). It requires a query object because pager needs to modify query before executing it (add LIMIT and OFFSET) in a platform-independent way (for example, it's different on MySQL vs. MS-SQL).
If you really need to use custom SQL with UNION, the only way to achieve it is to implement your custom sfDoctrinePager implementation that accepts SQL and assumes your target DB platform, certain SQL query structure, etc.
Am trying to making a specific query as follow
$query = "SELECT * FROM users WHERE uid IN (1,10,50,60,94,102)";
how can i use a mysql escape string for where clause or if i just use it like that, is it ok?
The way you are doing now is not an UPDATE query. You are only retrieving records from the database. In order to update records from the database, you need to use the UPDATE DML. The syntax for that is
UPDATE tableName
SET columnName = newValue
WHERE columnN = value // <== this is your condition
Returning back to your question, the way you are doing the query doesn't need mysql_escape_string because you are only passing integer values. Currently, more PHP developers are not using mysql_escape_string anymore because it's already been discourage and as the PHP Manual site says this function is already depreciated. Alternatively, PDO_MYSQL or MYSQLi extensions should be used instead.
Instead of hard coding sql queries like Select * from users where user_id =220202 can these be made dynamic like Select * from $users where $user_id = $input.
Reason i ask is when changes are needed to table/column names i can just update it in one place and don't have to ask developers to go line by line to find all references to update. It is very time consuming. And I do not like the idea of exposing database stuff in the code.
My major concern is load time. Like with dynamic pages, the database has to fetch the page content, same way if queries are dynamic first system has to lookup the references then execute the queries, so does it impact load times?
I am using codeignitor PHP.
If it is possible then the next question is where to store all the references? In the app, in a file, in the DB, and how?
---EDIT:
Even better: Can the SQL query itself be made dynamic? I can just reference $sqlA instead of the whole query? This way if I have to re-write the query I can just update 1 file.
Because you are using Codeigniter, I would reccomend utilizing the Active Record Class to accomplish what you are trying to do.
The active record class enables you to build queries dynamically in steps allowing you to build them logically. So to take your example using active record...
( this could be accomplished with less code, I'm just trying to illustrate Active Record )
$this->db->select('*');
$this->db->from($table);
$this->db->where($user_id, $input);
and so to show what I mean about building the query logically, you can build whatever logic you want INTO the query building process. Lets say you have a $limit variable that you set if you want to limit the number of results you get. BUT if it isn't set (or NULL) you don't want to set the limit clause.
if ( $isset($limit) ) {
$this->db->limit($limit);
}
and now to execute your query now that it has been built
$query = $this->db->get();
Then just deal with $query with your database class just like you would any other CodeIgniter query object.
Of course you can, if that's what you wish. I'd rather recommend you taking more time to design you database but changes in the schema are inevitable in the long run.
I don't think load time would be an issue with this because ussually the bottleneck in this applications is in the database.
Finally my recommendation is to save this in a file just by declaring the column names as php variables
It depends on the database driver(s) you are using. The old PHP database drivers did not support placeholders (PHP 3.x). The modern (PDO) ones do. You write the SQL with question marks:
SELECT * FROM Users WHERE User_ID = ?
You then provide the value of the user ID when you execute the query.
However, you cannot provide the column name like this - only values. But you could prepare a statement from a string such as:
SELECT * FROM Users WHERE $user_id = ?
Then you provide the value at execute time.
mysql_query() takes a string and it doesn't need to be a constant string, it can be a variable.
$SQL = "SELECT foo FROM bar b";
SQLSet = mysql_query($SQL);
Aa you can see, you can use ordinary string manipulation to build your whole SQL query.
$SQL="SELECT * FROM MyTable";
$BuzID = 5;
$Filter = "Buz=".$BuzID;
if (is_numeric($BuzID)) SQL .= " WHERE ".$Filter;
SQLSet = mysql_query($SQL);
This will expand to "SELECT * FROM MyTable WHERE Buz=5" if $BuzID is set to any number.
If not the statement will just be "SELECT * FROM MyTable"
As you can see, you can build very complex SQL statements on the fly without need of variable support in the SQL server.
IF you want constants such as database name, user login, you can but them in a separate include located outside the public directory.
SecretStuff.inc.php
$__DatabaseName = "localhost";
$__UserName = "DatabaseAccess";
$__Password = "E19A4F72B4AA091C6D2";
Or have the whole PHP database connection code in the same file.