I made this SQL statement to use in a project i'm working on and i have used FluentPDO before but it has been a while and i have never used a subquery in it before, so was wondering if anyone out there knows a good way to do this, i know you can do a JOIN but i am not really familiar with that method and never seen it used before so i don't know enough to make it work, i'm trying to brush up on it so i can do this myself.
SELECT *
FROM users
WHERE username = 'admin'
AND password = 'testing'
AND company_id IN (SELECT company_id
FROM company
WHERE subdomain = 'testing');
$result = $db->from('users')
->innerJoin('company ON users.company_id = company.company_id')
->where('username', 'admin')
->where('password', 'testing')
->where('subdomain', 'localhost')
->fetch();
I figured out the answer, and wanted to post it for anyone that was wondering the same way i was.
Related
I am working on a Symfony 2.7 webapp that uses the FOSUserBundle. Everything works fine so far. Not I would like to add an Admin Backend, that allow to show details about different Users.
For example in a Phone Book App, on should be able to see how many contacts a selected user has created:
$contact_count = $this->contactsCountForUser(5);
...
public function contactsCountForUser($user_id) {
$repo = $this->em->getRepository('AppBundle:Contact');
$qb = $repo->createQueryBuilder('c');
$qb->select('COUNT(c)');
$qb->where('c.user = :userId');
$qb->setParameter('userId', $user_id);
$sql = $qb->getQuery()->getSql();
$count = $qb->getQuery()->getSingleScalarResult();
return $count;
}
This fails, since the following is created as SQL query:
SELECT COUNT(c0_.guid) AS sclr0 FROM contact c0_ WHERE (c0_.user_id = ?) AND (c0_.user_id = '1')
Problem 1:
Why is $qb->where('c.user = :userId') being translated to c0_.user_id = ?? Why isn't 5 beeing used as user_id?
Problem 2:
AND (c0_.user_id = '1') is automatically added to the query. I assume this is done by the FOSUserBundle which limits the query to the current user. Here ID 1 is the ID of the currently logged in user, which is the Admin... Obviously (c0_.user_id = ?) AND (c0_.user_id = '1') can never be true.
So: How do I convince Doctrine and/or the FOSUserBundle, that the admin should be able to execute queries on other users data?
Thanks to the comment of #LBA, I was able to find the source of the problem:
A piece of third-party code add an SQLFilter as UserAware annotation. This webpage describes in detail what is done and how it works.
Maybe this can help others to avoid this kind of "problem" and to figure out what is "wrong" :-)
About Problem 1: Even after solving Problem 2, Problem 1 is still the same. The userId is still translated to ? within the query. However this does not seem to influence the function of the code. As far as I can see everything is working as expected.
So I have been moving from framework to framework and one feature that I liked about CodeIgniter over Laravel was that it supplys Raw statements.
I did some research on Laravel and the statements that they can supply and I found the DB::raw($sql) statement.
I tried initially to do the statement like so:
$query = DB::raw("SELECT * FROM users WHERE username = 'admin');
foreach ($query as $q) {
$id = $q['id'];
}
but that didnt manage to work, so I did some more research looking at stack overflow questions and I managed to find the structure was a bit different, so I tried:
$query = DB::select(DB::raw("SELECT * FROM users WHERE username = 'admin');
then used the same foreach loop as I did in the first part to try to loop the data.
If this is the wrong way of using this method please let me know, also, I'm not planning on keeping this method for using raw statements and getting user data, I just am trying to know that is it able to be used.
use get() function :
DB::table('users')->select('*')->where('username', '=', 'admin')->get();
I'm making a WordPress plugin and I need to update tables for the current database in a query. However, instead of writing the database name into the sql, I need some way to select it in the query so that way it will work no matter what your database's name is. This is the code I currently have:
$stmt = $conn->prepare("UPDATE `wp_plugin_development` . `wp_users` SET `user_pass` = ? WHERE `user_login` = ?") or trigger_error($mysqli->error);
$stmt->bind_param('ss', $user_password[$i], $user_login[$i]);
wp_plugin_development is my current database name, but needs to be replaced with some other way of selecting the database name. I wish I could write something like UPDATE SELECT DATABASE() but that obviously doesn't work. Maybe there's an entirely different way to code this? I still consider myself new to all this, so I'm sorry if I'm missing something obvious. Any help is greatly appreciated.
You don't need the current database name, because the connection is already established with the current database.
You need the tablename! The prefix is set when setting up wordpress. You need the prefix, because every installation is different.
The proper Wordpress way is like this:
global $wpdb;
$table_name = $wpdb->prefix . 'plugin_development';
The prefix is stored (wp_). In WP; you don't use PDO or MySqli directly, you work with the global $wpdb object.
$wpdb->update($table_name, $data, $where, $format = null, $where_format = null);
If you really need the database name, it's stored in $wpdb->dbname;.
Here are examples and the class reference:
https://codex.wordpress.org/Class_Reference/wpdb
I was using another database as the connection method (this was defined in the $conn variable). So I made a new connection to the current database using $wpdb and named it $this_db. Now I don't have to specify the database name in the query and it works like I want it to. For better context, here's the code I added/changed:
$thisServername = $wpdb->dbhost;
$thisUsername = $wpdb->dbuser;
$thisPassword = $wpdb->dbpassword;
$thisDBname = $wpdb->dbname;
$this_db = new mysqli($thisServername, $thisUsername, $thisPassword, $thisDBname);
$stmt = $this_db->prepare("UPDATE `wp_users` SET `user_pass` = ? WHERE `user_login` = ?") or trigger_error($mysqli->error);
$stmt->bind_param('ss', $user_password[$i], $user_login[$i]);
So, for solving this specific issue, this solution works. Sorry I forgot to mention using the external database. That was an important thing I left out of the question. And thank you everyone for your input.
The function database() returns the DB name - http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_database -
so you can run SELECT DATABASE(); first to get the DB name.
This is a difficult question to ask as the code I have is working fine. Im just learning the YII platform and my issue isnt that I cant get what I want working, but moreso if there is a better way of doing this that takes advantage of the YII platform and its classes.
Basically I have a webstore using a platform called Lightspeed which uses the YII platform.
In the product detail section I am looking to pull its related products. Thankfully Lightspeed has the tables in place for this already (which gives me more reason to think I am doing this wrong).
Right now what Im doing seems a little hard coded.
In my view I have this to get the products...
$related_products = Product::GetRelatedProducts();
I have nothing in my controller, and in my model I have this..
public function getRelatedProducts()
{
$rawData=Yii::app()->db->createCommand('SELECT * FROM xlsws_product as Product LEFT JOIN xlsws_product_related as ProductRelated ON ProductRelated.related_id=Product.id WHERE ProductRelated.related_id=Product.id ')->queryAll();
return $rawData;
}
As I said there is nothing wrong with this code, but I see so much functionality in place with all the other queries in the model that it makes me think Im doing this incorrectly.
Examples include..
protected function getSliderCriteria($autoadd=0)
{
$criteria = new CDbCriteria();
$criteria->distinct = true;
$criteria->alias = 'Product';
$criteria->join='LEFT JOIN '.ProductRelated::model()->tableName().' as ProductRelated ON ProductRelated.related_id=Product.id';
if (_xls_get_conf('INVENTORY_OUT_ALLOW_ADD',0)==Product::InventoryMakeDisappear)
$criteria->condition = 'ProductRelated.product_id=:id AND inventory_avail>0 AND web=1 AND autoadd='.$autoadd.' AND parent IS NULL';
else
$criteria->condition = 'ProductRelated.product_id=:id AND web=1 AND autoadd='.$autoadd.' AND parent IS NULL';
$criteria->params = array(':id'=>$this->id);
$criteria->limit = _xls_get_conf('MAX_PRODUCTS_IN_SLIDER',64);
$criteria->order = 'Product.id DESC';
return $criteria;
}
Thats just an example of a widget that seems to use this data (although Im unsure how that data turns into arrays, as when I print out $criteria I get arrays containing query commands.
Let me know if you need more clarification on what Im looking for.
You're right that you're not leveraging Yii. Yii (and other MVC frameworks), abstract the database layer out into a model.
The getSliderCriteria() you show above is an example of building criteria to refine the interactions with the model.
What you should try and figure out is what model represents the data you're looking for in Lightspeed, then building and applying the criteria to it.
In most modern frameworks, you shouldn't be writing much (if any) raw SQL . . .
I have this query which I want to run in my PHP application back end. Notionally, sheet is a DB that keeps track of all the sheets we have. Purchases is a DB that keeps track of which users have access to which sheet. The query I want to run is given a user's id, I can get all the sheets that they should have access to. In query form:
select distinct s.wsid, s.name from sheets s, purchases p where
s.wsid = p.wsid AND p.uid = *value*;
where value is something input by the application
The way I see it there are two ways to go about getting this to work in the back end.
Option 1)
public function getPurchasedSheets($uid){
if( is_numeric($uid) ){ //check against injections
$query = "select distinct s.wsid, s.name from sheets s, purchases p
where s.wsid = p.wsid AND p.uid = ".$uid.";" ;
return $this->db->query($query);
} else {
return NULL; //or false not quite sure how typing works in PHP
}
}
Option 2)
public function getPurchasedSheets($uid){
if( is_numeric($uid) ){
$this->db->select('wsid, name');
$this->db->distinct();
$this->db->from('purchases');
//not sure which order the join works in...
$this->db->join('sheets', 'sheets.wsid = purchases.wsid');
$this->db->where('uid ='.$uid);
return $this->db->get();
} else {
return NULL;
}
}
Source for all the CodeIgniter Active Record commands:
codeigniter.com/user_guide/database/active_record.html
Is there some sort of performance or security difference from doing thing one way or another? Doing it the second way seems so much more confusing to me... This is compounded a little bit because I am not sure how to do referential disambiguation in this style of coding because purchases and sheets both have a uid field but they mean different things (in addition to not being very familiar with the SQL join command in the first place.). Uid (user id) in purchases means that user has purchased that sheet, while Uid in sheets denotes which user owns that sheet.
TL,DR: Basically, I am asking is there a reason I should sink time into looking how to do things the option 2 way?
The main benefits are:
Abstraction from the database engine, where the library can take care
of database-specific SQL syntax differences for you. Relevant if you
ever have/want to change the database you're working with. In theory,
the second form should still just work.
The 'Active Record' syntax
automatically escapes parameters for you.
Readability, although
that's a matter of taste.
Incidentally, if you're in a PHP 5 environment, the library supports method chaining:
if( is_numeric($uid) ){
return $this->db->select('wsid, name')
->distinct()
->from('purchases')
->join('sheets', 'sheets.wsid = purchases.wsid')
->where('uid ='.$uid)
->get();
// nb. didn't check your join() syntax, either :)
}
Probably off-topic: CodeIgniter's Active Record is more of a query builder than an implementation of Active Record. In case you're wondering. When viewed as a query builder, it makes a bit more sense ;) FWIW, I do love CodeIgniter. I jest from affection.
Query binding is the easiest to implement and does the same thing query building does - and doesn't limit you as much as you will find building does.
$query = $this->db->query('SELECT something FROM table WHERE name1=? AND name2=?', array($name1, $name2);
$result = $query->result();
http://codeigniter.com/user_guide/database/queries.html