select joins and group by in codeigniter - join

In Codeigniter3, I have the following select join model:
public function get_post()
{
$q = $this->db->select('posts.id, posts.active, posts.title, posts.close_date, users.name')
->from('posts')
->join('users', 'posts.user_id = users.id', 'left')
->where('posts.active','1')
->where(['posts.active' => '1', 'posts.close_date >=' => date('Y-m-d')])
->order_by('posts.updated_at', 'DESC')->get();
return $q;
}
How can I list all posts with count posts for each user (count only posts where posts.active = 1 and posts.close_date >= current date)?
If CI can't do the job, please give me the sql query.

Here you go:
With complex queries like this, the best way is to store the sql script in a string variable and use $this->db->query() to execute it.
This query is in MySQL:
public function get_posts() {
$sql = "
SELECT `posts`.`id`, `posts`.`active`, `posts`.`title`, `posts`.`close_date`, users.name, COUNT(`posts`.`user_id`) AS `active_post_count`
FROM `posts`
LEFT JOIN `users` ON `posts`.`user_id` = `users`.`id`
WHERE `posts`.`active` = ?
AND `posts.close_date` >= ?
ORDER BY `posts`.`updated_at` DESC;
";
$now = new DateTime('now');
$binds = [1, $now->format('Y-m-d H:i:s')];
return $this->db->query($sql, $binds)->result_array();
}
Here's a sample code on how to access the post count:
$this->Your_model->get_posts()[0]['active_post_count'];
See CodeIgniter's docs on Generating Query Results:
If you want the result as an object instead, use result_object() over result_array().

Related

Scope Order by Count with Conditions Rails

I have a model Category that has_many Pendencies. I would like to create a scope that order the categories by the amount of Pendencies that has active = true without excluding active = false.
What I have so far is:
scope :order_by_pendencies, -> { left_joins(:pendencies).group(:id).order('COUNT(pendencies.id) DESC')}
This will order it by number of pendencies, but I want to order by pendencies that has active = true.
Another try was:
scope :order_by_pendencies, -> { left_joins(:pendencies).group(:id).where('pendencies.active = ?', true).order('COUNT(pendencies.id) DESC')}
This will order by number of pendencies that has pendencies.active = true, but will exclude the pendencies.active = false.
Thank you for your help.
I guess you want to sort by the amount of active pendencies without ignoring categories that have no active pendencies.
That would be something like:
scope :order_by_pendencies, -> {
active_count_q = Pendency.
group(:category_id).
where(active: true).
select(:category_id, "COUNT(*) AS count")
joins("LEFT JOIN (#{active_count_q.to_sql}) AS ac ON ac.category_id = id").
order("ac.count DESC")
}
The equivalent SQL query:
SELECT *, ac.count
FROM categories
LEFT JOIN (
SELECT category_id, COUNT(*) AS count
FROM pendencies
GROUP BY category_id
WHERE active = true
) AS ac ON ac.category_id = id
ORDER BY ac.count DESC
Note that if there are no active pendencies for a category, the count will be null and will be added to the end of the list.
A similar subquery could be added to sort additionally by the total amount of pendencies...
C# answer as requested:
method() {
....OrderBy((category) => category.Count(pendencies.Where((pendency) => pendency.Active))
}
Or in straight SQL:
SELECT category.id, ..., ActivePendnecies
FROM (SELECT category.id, ..., count(pendency) ActivePendnecies
FROM category
LEFT JOIN pendency ON category.id = pendency.id AND pendnecy.Active = 1
GROUP BY category.id, ...) P
ORDER BY ActivePendnecies;
We have to output ActivePendnecies in SQL even if the code will throw it out because otherwise the optimizer is within its rights to throw out the ORDER BY.
For now I developed the following (it's working, but I believe that it's not the best way):
scope :order_by_pendencies, -> { scoped = Category.left_joins(:pendencies)
.group(:id)
.order('COUNT(pendencies.id) DESC')
.where('pendencies.active = ?', true)
all = Category.all
(scoped + all).uniq}

Custom filter activeadmin is not working

I am trying to make a custom filter with active admin. This is my code where I setting hard code.
filter :versions_created, as: :date_range, label: "Resolvido em"
ransacker :versions_created, formatter: proc { |v,w|
v_date = "2016-09-09".to_date
w_date = "2016-09-09".to_date
time_range = v_date ..w_date
results = Occurrences.where({created_at:time_range} ).map(&:id)
results.present? ? results : nil
}do |parent|
parent.table[:id]
end
This apparently works because my log say:
//IS CORRECT
Occurrence Load (0.6ms) SELECT "occurrences".* FROM "occurrences" WHERE ("occurrences"."created_at" BETWEEN '2016-09-09' AND '2016-09-09')
CACHE (0.0ms) SELECT "occurrences".* FROM "occurrences" WHERE ("occurrences"."created_at" BETWEEN '2016-09-09' AND '2016-09-09')
//HEREEEE THE PROBLEM
*(0.5ms) SELECT COUNT(*) FROM "occurrences" WHERE ("occurrences"."id" >= NULL AND "occurrences"."id" <= NULL)
(0.6ms) SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM "occurrences" WHERE ("occurrences"."id" >= NULL AND "occurrences"."id" <= NULL) LIMIT 30 OFFSET 0) subquery_for_count*
My question is do you have any idea why the two other queries have values with NULL?

rails gem will_paginate on top of custom method not working

In my controller, my filter_with_params() method is causing a syntax error in postgres when I try and stack will_paginate on top of it.
In my controller I call:
#styles = Style.filter_with_params(params).paginate(:page => params[:page], :per_page => 6)
Model method:
class Style < ActiveRecord::Base
def self.filter_with_params(params)
scoped = where("styles.item != ''")
if params[:t]
scoped = scoped.joins(:tags)
scoped = scoped.select("distinct styles.*, count(*) AS count")
scoped = scoped.where(tags: { name: params[:t] })
scoped = scoped.group('styles.id')
scoped = scoped.having("count(*) = #{params[:t].size}")
end
scoped
end
basically my filter method is looking for tags, and then i need to paginate on top of those results. Anyone with similar experience?
I'm using Rails 3 on this app
here is the postgres error
PG::Error: ERROR: syntax error at or near "distinct" LINE 1: SELECT COUNT(*) AS count_all, distinct styles.*, count(*) AS...
^
: SELECT COUNT(*) AS count_all, distinct styles.*, count(*) AS count, styles.id AS styles_id FROM "styles" INNER JOIN "tagizations" ON "tagizations"."style_id" = "styles"."id" INNER JOIN "tags" ON "tags"."id" = "tagizations"."tag_id" WHERE "tags"."name" IN ('engagement') AND (styles.polenza_item != '') GROUP BY styles.id HAVING count(*) = 1
Your SQL has a problem. You need to say distinct clause before the count ('count(*) as count_all'). That is, once you remove the first call to the count function, it should work.
SELECT distinct styles.*, count(*) AS count, styles.id AS styles_id FROM "styles" INNER JOIN "tagizations" ON "tagizations"."style_id" = "styles"."id" ...
You can test your query in your rails console:
>> sql = "SELECT distinct styles.*, count(*) AS count, styles.id AS styles_id..."
>> a = ActiveRecord::Base.connection.execute(sql)
>> a[0]
Hope this helps.

NOT EXISTS SQL query in rails 3.2

I have an sql query like this:-
SELECT * FROM `permissions` join entities where NOT EXISTS (select
entity_id,permission_id from role_permissions where role_id=5 and
entities.id = role_permissions.entity_id and permissions.id =
role_permissions.permission_id)
I would like to get the corresponding rails query.
I have tried this.
Permission.joins("join entities").joins("LEFT OUTER JOIN role_permissions on
permission_id != permissions.id and entities.id != entity_id and
role_permissions.role_id= role_id").select("role_permissions.entity_id,role_permissions.role_id,
role_permissions.permission_id").group('role_permissions.entity_id,
role_permissions.permission_id')
But it doesn't works.
thanks
hari
I have been particularly in love with EXISTS queries lately, precisely because it does not require you to fully join another table. As far as I know, you do have to explicitly write the SQL clause, but you can still make it work with Activerecord. You can even put this in a scope within a lambda block.
Permission.joins(:entities).where(<<-SQL
NOT EXISTS(
select
* from role_permissions where role_id=#{your_role_id} and
entities.id = role_permissions.entity_id
and permissions.id = role_permissions.permission_id
)
SQL
)
Try like this for a default SQL query:
sql = "SELECT some_field FROM `permissions` join entities where NOT EXISTS (select entity_id,permission_id from role_permissions where role_id=5 and entities.id = role_permissions.entity_id and permissions.id = role_permissions.permission_id)"
results = ActiveRecord::Base.connection.execute(sql)
results.each do |result|
#register_users << { some_field: result[0] }
end
Try this
UPDATED BASED ON FIRST COMMENT
Permission.joins(:entities).joins("LEFT OUTER JOIN role_permissions on
permission_id != permissions.id and entities.id != entity_id and
role_permissions.role_id= role_id")
.select("role_permissions.entity_id,role_permissions.role_id,
role_permissions.permission_id")
.group('role_permissions.entity_id, role_permissions.permission_id')

How to use multiple on clause in joining in zend framework 2

I am doing like this sql into zend framework sql pattern.
SELECT
jobs . *,
c.id AS cid,
c.name AS name,
c.companyImage AS companyImage,
c.logo AS logo,
count(app.userId) AS t_app,
app.applyStatus AS applyStatus,
app.userId AS appUserId
FROM
jobs
LEFT JOIN
companies AS c ON jobs.companyName = c.id
LEFT JOIN
applicants AS app ON jobs.id = app.jobId AND app.applyStatus = 1
WHERE
jobs.ownerId = 16 AND jobs.draftId != 0
GROUP BY jobs.id
ORDER BY jobs.id DESC
LIMIT 3
For this sql I already write this code for zend framework 2
$adapter = $this->tableGateway->getAdapter();
$sql = new Sql($adapter);
$select = $sql->select();
$select->from('jobs')
->join(array('c' => 'companies'), 'jobs.companyName = c.id', array('cid' => 'id', 'name', 'companyImage', 'logo'), 'left')
->join(array('app' => 'applicants'), ' jobs.id = app.jobId AND app.applyStatus = 1', array('t_app' => new Expression('count(app.userId)'), 'applyStatus', 'appUserId' => 'userId'), 'left')
->where("jobs.ownerId ={$userId} AND jobs.draftId != 0")
->group('jobs.id')
->order('jobs.id DESC')
->limit(3);
$statement = $sql->getSqlStringForSqlObject($select);
$results = $adapter->query($statement, $adapter::QUERY_MODE_EXECUTE);
but does not work properly and its give a message like below.
SQLSTATE[42S22]: Column not found: 1054 Unknown column '1' in 'on clause'
The issue is this part:
app.applyStatus = 1
The framework is escaping 1 as if it were a column name, 1.
You need to enclose this part in an Expression too
new Expression('jobs.id = app.jobId AND app.applyStatus = 1')
I think the use of Expressions in the 'ON' parameter of the join method may depend on the version of ZF2 you are using, I think it was added 2.1+
Building on this answer. If you also want your table & column identifiers to be escaped, use this syntax:
use Zend\Db\Sql\Expression;
...
$onExpression = new Expression('? = ? AND ? = ?',
['jobs.id', 'app.jobId', 'app.applyStatus', 1],
[Expression::TYPE_IDENTIFIER, Expression::TYPE_IDENTIFIER,
Expression::TYPE_IDENTIFIER, Expression::TYPE_LITERAL]
);
$select->from('jobs')
->join(array('app' => 'applicants'), $onExpression, array('t_app' => new Expression('count(app.userId)'), 'applyStatus', 'appUserId' => 'userId'), 'left');
The Expression constructor accepts the string, then arguments, then argument types.
public function __construct($expression = '', $parameters = null, array $types = [])
This will create a security issue. Zf2 changes your query to this:
Select * from tableA inner join tableB
on `tableA`.`column` = `tableB`.`column`
AND `tableB`.`column` = `1`
It adds
`
to each part for security issues! By using new Expression you are bypassing it and if you get applyStatus from user entry, get sure about its filtering!

Resources