Rails 3, Kaminari - Error with :joins when using paginate - mysql

I have a function for prices with 2 joins and it works fine and dandy when I use it to call for prices. But now when I added Kaminari to be able to paginate, it gave me a error and I wonder if I can customize the "count*" function in Kaminari or is it my function for calling the products that's wrong?
This is in my controller
#prices = Price.select("`prices`.*").joins(:retailer, :retailer => :profile).
where(['product_id=? AND size_id=?', params[:prod_id], params[:si_id]]).
group(:retailer_id).order("SUM((prices.price * #{params[:amount].to_i}) + profiles.shippingCost)").page(params[:page])
Error code:
Mysql2::Error: Column 'retailer_id' in field list is ambiguous: SELECT COUNT(*) AS count_all, retailer_id AS retailer_id FROM `prices` INNER JOIN `retailers` ON `retailers`.`id` = `prices`.`retailer_id` INNER JOIN `profiles` ON `profiles`.`retailer_id` = `retailers`.`id` WHERE (product_id='1' AND size_id='3') GROUP BY retailer_id,retailer_id ORDER BY SUM((prices.price * 1) + profiles.shippingCost)
When I call the products without Kaminari the MYSQL looks like this.
SELECT `prices`.* FROM `prices` INNER JOIN `retailers` ON `retailers`.`id` = `prices`.`retailer_id` INNER JOIN `profiles` ON `profiles`.`retailer_id` = `retailers`.`id` WHERE (product_id='1' AND size_id='3') GROUP BY retailer_id ORDER BY SUM((prices.price * 1) + profiles.shippingCost)
Thanks in advance!

If ambiguous error then try explicit syntax for retailer_id.
e.g. retailers.retailer_id ,
profiles.retailer_id ,
prices.retailer_id.
ray

:retailer is duplicated inside your join clause.
Please change your join params to
.joins(:retailer => :profile)

Related

How to write mysql join sub query from 5 tables in laravel controller

I have a MySQL query like bellow, and I want to use it in laravel controller,
I know how to use join in laravel, but I don't know how to write it when we have another sub query in the join statement,
SELECT barangs.id, barangs.kode_barang, barangs.nama_barang,
IFNULL(a.QTY_IN,0) AS masuk, IFNULL(b.QTY_OUT,0) AS keluar,
IFNULL(c.PO_RETUR_QTY,0) AS po_retur, IFNULL(d.CUS_RETUR_QTY,0) AS cus_retur,
barangs.stok AS stok_akhir, barangs.harga_beli
FROM barangs
LEFT JOIN (
SELECT barang_masuk_detail.id_barang, barang_masuk.tgl_masuk, SUM(barang_masuk_detail.qty_terima) AS QTY_IN
FROM barang_masuk
LEFT JOIN barang_masuk_detail ON barang_masuk.id = barang_masuk_detail.id_brg_masuk
/* WHERE barang_masuk.tgl_masuk BETWEEN "2015-08-01" AND "2015-08-31" */
GROUP BY barang_masuk_detail.id_barang ASC
)AS a ON a.id_barang = barangs.id
LEFT JOIN (
SELECT barang_keluar_detail.id_barang, barang_keluar.tgl_kirim, SUM(barang_keluar_detail.qty_dikirim) AS QTY_OUT
FROM barang_keluar
LEFT JOIN barang_keluar_detail ON barang_keluar.id = barang_keluar_detail.id_brg_keluar
/* WHERE barang_keluar.tgl_kirim BETWEEN "2015-08-01" AND "2015-08-31"*/
GROUP BY barang_keluar_detail.id_barang ASC
)AS b ON b.id_barang = barangs.id
/*join retur try */
LEFT JOIN (
SELECT retur_beli_detail.barang_id, retur_beli.tgl_retur, SUM(retur_beli_detail.retur_qty) AS PO_RETUR_QTY
FROM retur_beli
LEFT JOIN retur_beli_detail ON retur_beli.id = retur_beli_detail.retur_id
/* WHERE retur_beli.tgl_retur BETWEEN "2015-08-01" AND "2015-08-31"*/
GROUP BY retur_beli_detail.barang_id ASC
)AS c ON c.barang_id = barangs.id
/*join retur dari customer */
LEFT JOIN (
SELECT retur_kirim_detail.barang_id, retur_kirim.tgl_retur, SUM(retur_kirim_detail.retur_qty) AS CUS_RETUR_QTY
FROM retur_kirim
LEFT JOIN retur_kirim_detail ON retur_kirim.id = retur_kirim_detail.retur_id
/* WHERE retur_kirim.tgl_retur BETWEEN "2015-08-01" AND "2015-08-31"*/
GROUP BY retur_kirim_detail.barang_id ASC
)AS d ON d.barang_id = barangs.id
if I run in the sqlyog it works as expected, but not sure how to write it in laravel syntax,
oh if possible to filter it using whereBetween in laravel base on request send from user, where I need put the syntax ?
like whereBetween([ $request->startDate, $request->endDate ]);
For the simple way to execute query with below syntax:-
DB::select("select * from table JOIN ...");
This will provide you collection of filtered data.
Edited Code
to use whereBetween() Laravel where query you need to write MySQL query like below
$startDate = $request->startDate;
$endDate = $request->endDate;
DB::select("
select * from table JOIN ...
where fieldName BETWEEN '$startDate' AND '$endDate'
");
To add more conditions, we need to write Plain MySQL query.

Inner Join "Invalid Object Name"

I'm trying to run this sql script but it keep on giving me this error
Msg 208, Level 16, State 1, Line 1
Invalid object name 'transaction_details'.
Here is my code and the contents of my other table:
my select query
SELECT transaction_details.transaction_id,transaction_status.transaction_id
FROM transaction_details
`INNER JOIN transaction_status
On transaction_status.transaction_id = transaction_details.transaction_id
WHERE transaction_status.status_of_transaction = 'pending'
The tables I wanted to join:
SELECT TOP 1000 [transaction_id]
,[user_id]
,[product_id]
,[job_description]
,[printing_process]
,[quantity]
,[transaction_date]
,[discount]
,[total]
,[shipping_date]
FROM [MejOnlineManagementDB00].[dbo].[transaction_details]
SELECT TOP 1000 [transaction_id]
,[user_id]
,[product_id]
,[status_of_transaction]
FROM [MejOnlineManagementDB00].[dbo].[transaction_status]
I'm pretty sure my names is correct I don't know what is causing the error.
Looks like just a typo.
Select the database that you want to use from the dropdown if you're using an IDE. Else, tell mysql to USE that database.
USE MejOnlineManagementDB00;
Also you can just include the database name in your query:
SELECT D.transaction_id
,S.transaction_id
FROM MejOnlineManagementDB00.transaction_details AS D
INNER JOIN MejOnlineManagementDB00.transaction_status AS S
ON S.transaction_id = D.transaction_id
WHERE S.status_of_transaction = 'pending'
You have a backtics at the beginning of the inner join (remove idt)
SELECT transaction_details.transaction_id,transaction_status.transaction_id
FROM transaction_details
INNER JOIN transaction_status
On transaction_status.transaction_id = transaction_details.transaction_id
WHERE transaction_status.status_of_transaction = 'pending'

Mysql row query to codeigniter query

I have the following Mysql query. Running as needed.
SELECT
t_doc.*, t_user.IDA, t_data.IDA
FROM
( SELECT DISTINCT IDau FROM t_doc ) IDau_list
LEFT OUTER JOIN
(
SELECT
IDd ,IDau
FROM
t_doc
WHERE
doc_type = 'doc'
GROUP BY IDau
)
doc_images ON doc_images.IDau = IDau_list.IDau
LEFT OUTER JOIN
(
SELECT
IDd ,IDau
FROM
t_auto_doc
WHERE
doc_type = 'jpg'
GROUP BY IDau
)
jpg_images ON jpg_images.IDau = IDau_list.IDau
LEFT OUTER JOIN
t_doc ON t_doc.IDdoc = COALESCE(jpg_images.IDd, doc_images.IDd)
LEFT OUTER JOIN
t_user ON t_user.IDau = t_doc.IDau
LEFT OUTER JOIN
t_data ON t_user.IDA = t_data.IDA
But, What I must bring this query to codeigniter Model, in which I have to adapt the query, as example like this...
$this->db->select('u.IDau, a.*');
$this->db->from('t_user u');
$this->db->join('t_doc d', 'd.IDau=u.IDau', 'left');
And ...More.....Here......
But, I got it difficult. Is some one out there might change it Please..
Thanks in advance
As #NEVERMIND Suggest I have accomplish the task using...
$query = $this->db->query("My QUERY WITH A BIT OF CHANGE");
Yes, I should make some change to get the exact Data as i needed.
Thanks for all of your comments and ideas.

Rails - How to force associations to use alias table name

p = Patient.find(30)
p.patient_problems
The above code generates the following query
SELECT `patient_problem`.* FROM `patient_problem` WHERE `patient_problem`.`patient_id` = 30 AND (`patient_problem`.`record_status_id` = 1)
But is there any way to assign/use alias table_name like
p.patient_problems(:alias=>'p1') # just for Ex.. This code will not work
p.patient_problems(:alias=>'p2') # just for Ex.. This code will not work
So it will generate the following queries
SELECT `p1`.* FROM `patient_problem` AS `p1` WHERE `p1`.`patient_id` = 30 AND (`p1`.`record_status_id` = 1)
SELECT `p2`.* FROM `patient_problem` AS `p2` WHERE `p2`.`patient_id` = 30 AND (`p2`.`record_status_id` = 1)
Additional Info
My problem is when I try to use joins
p.patient_problems(:all,:joins=>joins)
I get this error
ActionView::Template::Error (Mysql2::Error: Not unique table/alias: 'patient_problem': SELECT `patient_problem`.* FROM `patient_problem` LEFT OUTER JOIN party on party.id = patient_problem.patient_id
LEFT OUTER JOIN party_identifier on party.id = party_identifier.party_id
LEFT OUTER JOIN blood_type on blood_type.id = party.blood_type_id
LEFT OUTER JOIN education_level on education_level.id = party.education_level_id
LEFT OUTER JOIN religion on religion.id = party.religion_id
LEFT OUTER JOIN living_arrangement on living_arrangement.id = party.living_arrangement_id
LEFT OUTER JOIN patient_problem patient_problem on patient_problem.patient_id = party.id and patient_problem.record_status_id = 1
left join (select user_type,username,user_id,auditable_id from (select MAX(id) id from audits where audits.auditable_type = 'PatientProblem' and user_type is not null group by auditable_id ) t inner join audits v on v.id=t.id ) entered_by1 on entered_by1.auditable_id = patient_problem.id
left outer join user user1 on entered_by1.user_id = user1.id
left outer join party as party_user1 on party_user1.id = user1.person_id
LEFT OUTER JOIN patient_patient_search patient_patient_search1 on patient_patient_search1.patient_id = party.id
left join search search1 on patient_patient_search1.patient_search_id = search1.id
and patient_patient_search1.patient_search_id = '75' WHERE `patient_problem`.`patient_id` = 45 AND (`patient_problem`.`record_status_id` = 1) AND ( (patient_problem.occurrence_date > '2013-01-01 00:00:00' and patient_problem.occurrence_date < '2013-06-30 23:59:59' and patient_problem.patient_problem_status_id in (5) and patient_problem.code is not null and patient_problem.code in ('10725009') ) and ( patient_patient_search1.patient_search_id in (75.0) ) ))
Ofcourse I could do some string manipulation on the generated joins query and set alias to patient_problem. But I thought setting alias for associations would be more cleaner since the joins query generated are unpredictable(in my scenario)
I am not sure what the variable joins is or how it was constructed. To alias tables in a join build your query like
Rails 3
PatientProblem.joins("as p1 OUTER JOIN patient_problem as p2 on ...")
or
PatientProblem.find(:all, :joins => "as p1 OUTER JOIN patient_problem as p2 ON ...")
you can make singleton methods for that and write the query one time and use may time like
def self.p1
#your active record query here.
end
and call like
PatientProblem.p1
Update
You can simply change the table name in your code:
Patient.table_name="p2"
I'm not sure if this would break anything else though ... so good luck!
Orignal Answer
One solution may be to define a separate model for each type of patient_problem and then do something like this:
class PatientProblem2 < ActiveRecord::Base
self.set_table_name "p2"
...
end
Another solution may be to use the ActiveRecord query interface which will allows for significant query flexibility:
http://guides.rubyonrails.org/active_record_querying.html
Perhaps you can be more specific on the nature problem you are trying to solve.

Mysql: Get all results that has all this relations

I have two tables:
objects object_features
------------- -------------------
id id
name object_id
term_id
What I want to achieve is, giving a list of features, get all objects that has all of them.
I'm trying this:
SELECT objects.*
FROM `object_features` LEFT JOIN `objects` ON ( objects.id=object_features.object_id)
WHERE term_id IN ('1','3','4','10')
This is the php code I'm using:
$feature_list = array(1,3,4,10);
$sql = 'SELECT objects.*
FROM `object_features` LEFT JOIN `objects` ON ( objects.id=object_features.object_id)
WHERE term_id IN ('.implode(',', $feature_list).')';
This is near to what I need, but differing that it returns me any object that has any of the features given, instead of ALL the features
one option is to group by the data you want returned from object and add a having clause that counts object.id and tests to see if it is the same as the length of the array.
SELECT objects.id, objects.name
FROM `object_features` LEFT JOIN `objects` ON ( objects.id=object_features.object_id)
WHERE term_id IN ('1','3','4','10')
group by objects.id,objects.name
having count(objects.id) = 4
Cant swear to the syntax on that as I've been writing tsql recently and don't have an instance of mysql to test on.
try
'WHERE term_id = '.impode(' AND termid = ', $features_ids).')'
This will result in:
WHERE termid = 1 AND termid = 3 AND termid = 5
Actually you need a GROUP BY to group by each object and using a HAVING clause to allow only rows that have all the termids
SELECT objects.*
FROM `object_features` LEFT JOIN `objects` ON ( objects.id=object_features.object_id)
WHERE term_id IN ('1','3','4','10')
GROUP BY objects.id, objects.name
HAVING count(term_id) = 4
The SQL way of doing it would be:
SELECT objects.*
FROM objects
WHERE null not in
(
select of.object_id
from features f
left join object_features of on (f.id = of.id)
)
Assuming you have a features table with all the features.
If you need to list only certain features, you can do (check out the where condition on the subquery):
SELECT objects.*
FROM objects
WHERE null not in
(
select of.object_id
from features f
left join object_features of on (f.id = of.id)
where f.id in (1,2,3,4,5)
)