Zend Framework 2 "select where not in" - php

I have this simple query where I have a $posts Array that contains IDs of certain posts. And I am selecting the files associated with these posts basically:
->from(
['DO' => 'DOCUMENT']
)
->columns(
[
'POST_ID',
'FILENAME'
]
)
->where('DO.FILENAME LIKE "%'.$format.'%"')
->where(['DO.POST_ID' => $posts])
->order('DO.FILENAME DESC');
Now I want to select the files that are not related to these posts. So I need to do opposite of this:
->where(['DO.POST_ID' => $posts])
I cannot figure out how?

You need to use NOT IN operation
->from(
['DO' => 'DOCUMENT']
)
->columns(
[
'POST_ID',
'FILENAME'
]
)
->where('DO.FILENAME LIKE "%'.$format.'%"')
->where->addPredicate(new Zend\Db\Sql\Predicate\Expression('DO.POST_ID NOT IN (?)', array($posts)))
->order('DO.FILENAME DESC');

use Zend\Db\Sql\Predicate\NotIn;
$adapter = $this->tableGateway->getAdapter();
$sql = new Sql($adapter);
$select = $sql->select();
$select->from('produto');
$select->where->addPredicate->notIn('DO.POST_ID', [1,3,5]);
$select->order('status ASC');
$selectStr = $sql->getSqlStringForSqlObject($select);
echo $selectStr;
$results = $adapter->query($selectStr, $adapter::QUERY_MODE_EXECUTE);

Related

How to use value from 'join' clause in 'where' clause?

There is join, and I need to include value from it in 'where'. Is there any way to do this? In other words, I want to apply 'where' clause only to that values, which being joined. I'm really got confused with it, and may be this task can be solved more easily.
$this->table = "CoolTable";
$sql = new Sql($this->getAdapter());
$select = $sql->select()
->columns(array(/*some expressions...*/))
->from($this->table)
->join(
array('ct' => 'CoolTable'),
new Expression('
ct.a = CoolTable.a AND
ct.b = CoolTable.b
'),
array()
)
/*another joins...*/
->where(array(
'CoolTable.a' => $someExternalVar,
'CoolTable.b = ?' => '$ct.a',
))
What about my tries:
'CoolTable.b = ?' => '$ct.a'
'CoolTable.b' => 'ct.a'
'CoolTable.b' => new Expression('ct.a') /*it's a really pity, yes*/
new Predicate\PredicateSet(
array(
new Operator(
'CoolTable.b',
Operator::OPERATOR_EQUAL_TO,
'ct.a'
),
),
Predicate\PredicateSet::TYPE_VALUE
),

Laravel Query Builder "select" strange behaviour

I have a problem with the following code:
public function index() {
$qObj = \DB::table('customers as c')
->join('companies_has_customers as chc', 'chc.comhc_cus_id', '=', 'c.cus_id')
->join('cuscategory as cc', 'chc.comhc_cca_id', '=', 'cc.cca_id')
->join('transactions as t','t.trn_cus_id', '=','c.cus_id')
->select('t.trn_id');
$qObj->where('comhc_com_id', '=', $this->companyId);
$res = array(
'count' => $qObj->count(),
'items' => $qObj->get()
);
//print_r($this->showLastQuery());
return parent::prepareResponse($res, 200, 'customers');
}
And this piece of code produces following SQL query:
select * from `customers` as `c`
inner join `companies_has_customers` as `chc` on `chc`.`comhc_cus_id` = `c`.`cus_id`
inner join `cuscategory` as `cc` on `chc`.`comhc_cca_id` = `cc`.`cca_id`
inner join `transactions` as `t` on `t`.`trn_cus_id` = `c`.`cus_id`
where comhc_com_id` = 1
QUESTION:
Why QueryBuilder produce select *... instead of select t.trn_id... as is requested in above syntax?
Change the order:
$res = array(
'items' => $qObj->get(),
'count' => $qObj->count()
);
and it will work.
But better, instead of querying DB twice, do this:
$items = $qObj->get();
$res = array(
'items' => $items,
'count' => count($items)
);
The problem with your code is count() method behaviour - it resets the columns property (set with select), that's all.
Put it in $qObj->get(['t.trn_id']) like this:
$res = array(
'items' => $items = $qObj->get(['t.trn_id']),
'count' => count($items) // count the cached $items
);
Instead of select ( Remove select('t.trn_id')).

Codeigniter Join messing up 'id' field

I have a codeigniter query to get a list of questions from my database. I'm using some joins to get the category name and the answer type. Its working good to output everything, but when i try and output the id of the row from the "questions" table, it displays as "2" which is the answer_type_id.
Maybe I'm doing this wrong, i'm fairly new to joins. Any help is appreciated:
function get_questions($category_id) {
$this->db->select('*');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id');
$this->db->order_by('priority', 'desc');
$query = $this->db->get();
$data = array();
foreach ($query->result() as $row) {
$data[] = array(
'id' => $row->id,
'category' => $row->category,
'type' => $row->type,
'question' => $row->question,
'answer' => $row->answer_type,
'priority' => $row->priority,
);
}
return $data;
}
Update===============
I have added "left" for my join type but the problem persists. The question id's should be 2 and 3. But when i print my array returned, they are both 2 (which is the answer_type_id).
Here is the updated code (only left join changed)...
function get_questions($category_id) {
$this->db->select('*');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id', 'left');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id', 'left');
$this->db->order_by('priority', 'desc');
$query = $this->db->get();
$data = array();
foreach ($query->result() as $row) {
$data[] = array(
'id' => $row->id,
'category' => $row->category,
'type' => $row->type,
'question' => $row->question,
'answer' => $row->answer_type,
'priority' => $row->priority,
);
}
return $data;
}
And here is the output it returns:
Array (
[0] => Array (
[id] => 2
[category] => Herbs
[type] => 2
[question] => What Type of Vehicle do You own?
[answer] => Drop down list [priority] => 0
)
[1] => Array (
[id] => 2
[category] => Herbs
[type] => 3
[question] => What is Your Favorite Herb
[answer] => Drop down list [priority] => 0
)
)
The reason you are not getting the proper ids is you are selecting *.
Use aliases so that give them separate names and you will be access them
as you want like this.
function get_questions($category_id) {
$this->db->select('questions.*');
$this->db->select('answer_type.answer_type_id');
$this->db->select('answer_type.other_column');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id', 'left');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id', 'left');
$this->db->order_by('priority', 'desc');
return $this->db->get()->result_array();
}
Also Codeigniter database class provide a method call result_array()
Which is already alternate of the loop you are using. So use it instead of
extra loop code.
Just change it to this:
'id' => $row->category_id
The problem is that the id column is ambiguous. In cases where your selecting columns across tables with columns that have the same name, you can also use the AS keyword to rename a column.
For example:
$this->db->select("questions.*, categories.id AS cat_id, answer_type.id AS ans_id");
By chance are you (maybe) only getting one row as a result, where all the ids match?
You should specify your join type, or be more specific in your query, so that you keep the question.id value.
For this question, you could specify the join as a left join, to keep all the data from questions table and tack on from categories and answer_types where its found.
see CodeIgniter ActiveRecord docs
The questions id needs to be defined as its own name. To pull ALL the data from the other tables, follow up with asterisks for the other tables, like so...
function get_questions($category_id) {
$this->db->select('questions.id as questions_id, questions.*, categories.*, answer_type.*');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id', 'left');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id', 'left');
$this->db->order_by('priority', 'desc');
$query = $this->db->get();
$data = array();
foreach ($query->result() as $row) {
$data[] = array(
'id' => $row->questions_id,
'category' => $row->category,
'type' => $row->type,
'question' => $row->question,
'answer' => $row->answer_type,
'priority' => $row->priority,
);
}
return $data;
}
Use alias for your id columns like the above example.
...
$this->db->select("questions.*, categories.id AS cat_id, answer_type.id AS ans_id");
...
...
Now you get your data because only have one id column.
Here you have an article: http://chrissilich.com/blog/codeigniter-active-record-aliasing-column-names-to-prevent-overwriting-especially-columns-named-id/

Zend subquery arguments

The query below represents what I am trying to do, I need to pull in a list of blog_posts and also join with a users table.
What it is also doing is pulling in a random 'picture_filename' from blog_updates_pictures. It needs blog_updates as a join to reference the blog_update_id.
What I'd like to do now is also COUNT the number of blog_updates for each blog_post. I think this is a subquery but every implementation fails. It would also be good to have the count accept arguments (ie. blog_updates where date = ?). Also, there may be no updates or pictures to a blog_post.
$select = $db->select ();
$select->from ( array ('b' => 'blog_posts' ), array('headline', 'date_created'));
$select->join ( array ('u' => 'users' ), 'u.user_id = b.user_id', array ( 'email' ) );
$select->joinLeft ( array ('bu' => 'blog_updates' ), 'bu.blog_id = b.blog_id', array () );
$select->joinLeft ( array ('bup' => 'blog_updates_pictures' ), 'bu.blog_update_id = bup.blog_update_id', array ('picture_filename' ) );
Can someone show me the way?
Thanks
What I'd like to do now is also COUNT the number of blog_updates for each blog_post.
You can achieve that using aggregation - use GROUP BY bu.blog_id, and as additional column COUNT(bu.blog_id) AS blog_updates_count. It should work.
Create subselects as:
$subselect = $db->select()
->from(
array ('bu' => 'blog_updates' ),
array(
'blog_id',
'updates' => 'count(*)'
)
)
->group("bu.blog_id");
And then join the $subselect with your main $select as:
$select->join(
array( 't' => $subselect),
"t.blog_id = b.blog_id",
array( 'updates' )
);
If we had the table structure you might get a more complete answer

How to get all table columns without defining them in query?

I have two tables, User and Company. I have joining them like this:
$table = $this->getDbTable();
$select = $table->select();
$select->setIntegrityCheck( false );
$select->from( array('User'), array( 'id' => 'id',
'name' => 'User.name',
'gender' => 'User.gender',
'Company_id' => 'User.Company_id'
));
$select->join( 'Company', 'Company.id = User.Company_id',
array( 'Company_name' => 'Company.name' ,
'Company_address' => 'Company.address'
));
$rows = $table->fetchAll( $select );
It is working and giving me accurate result. Problem is that I have to mentions column names in above codes. I want to get all columns without mentioning them in above piece of code.
For example I want something like this that get all columns(But it is not providing all column values):
$table = $this->getDbTable();
$select = $table->select();
$select->setIntegrityCheck( false );
$select->from( array('User') );
$select->join( 'Company', 'Company.id = User.Company_id' );
$rows = $table->fetchAll( $select );
Thanks
Leaving away the second parameter to the from call should work: http://framework.zend.com/manual/en/zend.db.select.html#zend.db.select.building.columns

Categories