MySQL column not found despite being declared? - mysql

This query works:
select d.*,
(6371 * 3.1415926 * SQRT((:lat - dl.lat) * (:lat - dl.lat) + COS(:lat / 57.2957795) * COS(dl.lat / 57.2957795) * (:long - dl.long) * (:long - dl.long)) / 180) as xdistance
from `dudes` as d
left join `dude_locations` as dl on (dl.id_dude = d.id)
where
(6371 * 3.1415926 * SQRT((:lat - dl.lat) * (:lat - dl.lat) + COS(:lat / 57.2957795) * COS(dl.lat / 57.2957795) * (:long - dl.long) * (:long - dl.long)) / 180) <= dl.distance
group by d.id
limit 20
However, this query throws a "column xdistance not found" error:
select d.*,
(6371 * 3.1415926 * SQRT((:lat - dl.lat) * (:lat - dl.lat) + COS(:lat / 57.2957795) * COS(dl.lat / 57.2957795) * (:long - dl.long) * (:long - dl.long)) / 180) as xdistance
from `dudes` as d
left join `dude_locations` as dl on (dl.id_dude = d.id)
where
xdistance <= dl.distance
group by d.id
limit 20
All I'm trying to do is make it so the same calculation isn't made twice. Is this possible?
Any help would be appreciated.

where
d.xdistance <= dl.distance

It is possible that the query you want is something like this:
select d.*,
MIN((6371 * 3.1415926 * SQRT((:lat - dl.lat) * (:lat - dl.lat) + COS(:lat / 57.2957795) * COS(dl.lat / 57.2957795) * (:long - dl.long) * (:long - dl.long)) / 180) ) as xdistance
from `dudes` as d left join
`dude_locations` as dl
on (dl.id_dude = d.id)
group by d.id
having xdistance <= min(dl.distance)
limit 20;

Related

MySql calculate multiple column

I have code below and in my query but the results it gives me is way off chart, so I thought maybe my calculation is wrong. The Logic is to have multiple column sum minus and times to eachother and the result based on my database numbers has to be 4.581.709.50 but I get something like 164.610.000
SUM(c.gaji_pokok + c.uang_makan + c.tunjangan + c.kendaraan + c.overtime + c.komisi + c.lain_lain + c.cuti -
m.pot_absen_hari * m.pot_absen_rate - IFNULL(g.pot_absen_hari * g.pot_absen_rate, 0) - CONCAT((c.uang_makan)/0.25)*0.05 -
n.pot_komisi_dl - n.pot_komisi_p312 - n.pot_komisi_mteg - IFNULL(g.pot_komisi_kasbon, 0) - q.bpjs4 - o.pot_ppn_21pt - o.pot_pinjaman - o.pot_ppn21 - o.pot_bayar_bonus -
o.pot_bayar_thr - c.cuti) as bulan_ppn21,
Query
SELECT
a.nip,
SUM(c.gaji_pokok + c.uang_makan + c.tunjangan + c.kendaraan + c.overtime + c.komisi + c.lain_lain + c.cuti -
m.pot_absen_hari * m.pot_absen_rate - IFNULL(g.pot_absen_hari * g.pot_absen_rate, 0) - CONCAT((c.uang_makan)/0.25)*0.05 -
n.pot_komisi_dl - n.pot_komisi_p312 - n.pot_komisi_mteg - IFNULL(g.pot_komisi_kasbon, 0) - q.bpjs4 - o.pot_ppn_21pt - o.pot_pinjaman - o.pot_ppn21 - o.pot_bayar_bonus -
o.pot_bayar_thr - c.cuti) as bulan_ppn21,
IFNULL((
CASE
WHEN ((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate)<=50000000)
THEN (0.05*((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)))
WHEN ((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate)<=250000000)
THEN (0.15*((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.15)-(q.jht*12)))
WHEN ((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate)<=500000000)
THEN (0.25*((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.25)-(q.jht*12))) end),0) as tahun_pph21,
IFNULL((
CASE
WHEN ((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate)<=50000000)
THEN (0.05*((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)))
WHEN ((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate)<=250000000)
THEN (0.15*((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.15)-(q.jht*12)))
WHEN ((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate)<=500000000)
THEN (0.25*((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.25)-(q.jht*12))) end) -(
CASE
WHEN ((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate)<=50000000)
THEN (0.05*((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)))
WHEN ((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate)<=250000000)
THEN (0.15*((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.15)-(q.jht*12)))
WHEN ((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate)<=500000000)
THEN (0.25*((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.25)-(q.jht*12))) end)/12,0) - (
CASE
WHEN (((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate))<=50000000)
THEN (0.05*((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate)))
WHEN (((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate))<=250000000)
THEN (0.15*((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate))-5000000)
WHEN (((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate))<=500000000)
THEN (0.25*(0.03*(c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate))-55000000)*1.2
WHEN (((c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate))<=500000000)
THEN (0.25*(0.03*(c.gaji_pokok * 12)-((c.gaji_pokok * 12)*0.05)-(q.jht*12)-(r.pt_kp_rate))-55000000)*1.2 end) as tot_pph21
FROM `t_pegawai` a
LEFT JOIN t_penggajian_karyawan c ON c.nip=a.nip
LEFT JOIN t_departemen d ON d.id_departemen=a.id_departemen
LEFT JOIN t_jabatan e ON e.id_jabatan=a.id_jabatan
LEFT JOIN t_perusahaan f ON f.kode_unitbisnis = a.unit_bisnis
LEFT JOIN absensi k ON k.pin = a.pin
LEFT JOIN t_periode l ON l.nama_periode=c.bulan and YEAR(l.periode_start) = c.tahun
LEFT JOIN t_potongan_absen m ON m.nip=a.nip and m.nip=c.nip and m.bulan = l.id_periode and m.tahun = YEAR(l.periode_start)
LEFT JOIN t_potongan_gaji g ON g.nip=a.nip and g.nip=c.nip and g.bulan = l.id_periode and g.tahun = YEAR(l.periode_start)
LEFT JOIN t_potongan_komisi n ON n.nip=a.nip and n.nip=c.nip and n.bulan = l.id_periode and n.tahun = YEAR(l.periode_start)
LEFT JOIN t_potongan_ppn o ON o.nip=a.nip and o.nip=c.nip and o.bulan = l.id_periode and o.tahun = YEAR(l.periode_start)
LEFT JOIN t_jenjang_bpjs q ON q.nip=a.nip and q.tahun = YEAR(l.periode_start)
LEFT JOIN t_ptkp r ON r.pt_kp_name=a.status_ptkp
WHERE l.id_periode='8' AND f.kode_unitbisnis ='PJS-001' and k.Tanggal >= l.periode_start and k.Tanggal <= l.periode_end
GROUP BY a.pin
Any suggestion on calculation way to make it right?

Reusing calculations in an SQL query

Is it possible to simplify this sql query? Lots of calculations are reused and it would be nice to name each expression and use the name instead of the full expression.
SELECT SUM(T2.price * T1.amount) As price,
(SUM(T2.price * T1.amount) - (SUM(T2.price * T1.amount) * (T3.discount / 100))) As base_price,
((SUM(T2.price * T1.amount) - (SUM(T2.price * T1.amount) * (T3.discount / 100))) * (T3.vat / 100)) As vat_amount,
(((SUM(T2.price * T1.amount) - (SUM(T2.price * T1.amount) * (T3.discount / 100))) * (T3.vat / 100)) + (SUM(T2.price * T1.amount) - (SUM(T2.price * T1.amount) * (T3.discount / 100)))) As total_price
I'm looking for a solution similar to this:
SELECT SUM(T2.price * T1.amount) As price,
(price - (price * (T3.discount / 100))) As base_price,
(base_price) * (T3.vat / 100)) As vat_amount,
(vat_amount) + (base_price) As total_price
I tried doing it with CTE's and subqueries as suggested but it ended up looking pretty complicated and undreadable so I decided to just do the calculations outside of sql (php in this case)
Maybe something like that:
select
(A.price - (A.price * B.p_discount)) As base_price,
((A.price - (A.price * B.p_discount)) * B.p_vat) As vat_amount,
(((A.price - (A.price * B.p_discount)) * B.p_vat) + (A.price - (A.price * B.p_discount))) As total_price
from
( select SUM(T2.price * T1.amount) As price, ...
from T1 join T2 on ....
) A
join
(select (T3.discount / 100) as p_discount , (T3.vat / 100) as p_vat ,*
from T3
) B on ...

Add more conditions to Haversine Formula in SQL query

Please I need help with adding one more condition to the below database query. I'm using Haversine Formula to get the 15 closest locations to my user's location. I have succeeded in doing this, however I wish to narrow the condition to only display the closest locations if serviceName equals a $serviceName in my query.
I wish to add WHERE serviceName="$serviceName";.
My Query:
$sql = "
SELECT uid, inCallPriceOneTime, lat, lng, distance
FROM
(
SELECT z.uid, z.inCallPriceOneTime, z.lat, z.lng,
p.radius, p.distance_unit *
DEGREES(ACOS(COS(RADIANS(p.latpoint)) *
COS(RADIANS(z.lat)) *
COS(RADIANS(p.longpoint - z.lng))
+ SIN(RADIANS(p.latpoint)) *
SIN(RADIANS(z.lat))))
AS distance
FROM selectedservice AS z
JOIN
(
SELECT $lat AS latpoint, $lng AS longpoint, 50.0 AS radius,
111.045 AS distance_unit
) AS p
WHERE z.lat
BETWEEN p.latpoint - (p.radius / p.distance_unit)
AND p.latpoint + (p.radius / p.distance_unit)
AND z.lng
BETWEEN p.longpoint - (p.radius / (p.distance_unit *
COS(RADIANS(p.latpoint))))
AND p.longpoint + (p.radius / (p.distance_unit *
COS(RADIANS(p.latpoint))))
) AS d
WHERE distance <= radius
ORDER BY distance LIMIT 15";
Any help will be greatly appreciated.
Thanks in advance.

Determining distances MySQL

My code is as follows and should work but for some reason it is not recognizing wm_stores.lat in the join statement. Anyone have any ideas?
SELECT wm_dcs.dc_id, wm_stores.store_id
FROM wm_dcs
JOIN wm_stores
ON wm_stores.lat BETWEEN wm_dcs.lat - (250.0 / 69.0)
AND wm_dcs.lat + (250.0 / 69.0)
AND wm_stores.lon BETWEEN wm_dcs.lon - (250.0 / (69.0 * COS(RADIANS(wm_dcs.lat))))
AND wm_dcs.lon + (250.0 / (69.0 * COS(RADIANS(wm_dcs.lat))))
AND (69.0 * DEGREES(ACOS(COS(RADIANS(wm_dcs.lat) * COS(RADIANS(stores.latitude))
* COS(RADIANS(dc.longitude - stores.longitude))
+ SIN(RADIANS(dc.latitude))
* SIN(RADIANS(wm_stores.lon)))))) <= 250.0;
Different Version of code:
set #dc_lat = 40.811973 ;
set #dc_lon = -73.946299 ;
select wm_stores.store_id,
( 3959 * acos( cos( radians(#dc_lat) ) * cos( radians(wm_stores.lat ) )
* cos( radians( wm_stores.lon ) - radians(#dc_lon) ) + sin( radians(#dc_lat) )
* sin( radians( wm_stores.lat ) ) ) ) AS distance
from wm_stores
having distance <= 250
order by distance asc;
In your query
SELECT wm_dcs.dc_id, wm_stores.store_id
FROM wm_dcs
JOIN wm_stores
ON wm_stores.lat BETWEEN wm_dcs.lat - (250.0 / 69.0)
AND wm_dcs.lat + (250.0 / 69.0)
AND wm_stores.lon BETWEEN wm_dcs.lon - (250.0 / (69.0 * COS(RADIANS(wm_dcs.lat))))
AND wm_dcs.lon + (250.0 / (69.0 * COS(RADIANS(wm_dcs.lat))))
AND (69.0 * DEGREES(ACOS(COS(RADIANS(wm_dcs.lat) * COS(RADIANS(stores.latitude))
* COS(RADIANS(dc.longitude - stores.longitude))
+ SIN(RADIANS(dc.latitude))
* SIN(RADIANS(wm_stores.lon)))))) <= 250.0;
I noticed there is no table like stores but you have used stores.latitude and stores.longitude in your query. May be this is causing the error message Unknown column 'stores.latitude' in 'on clause'.
I suggest you to re-examine the code
AND (69.0 * DEGREES(ACOS(COS(RADIANS(wm_dcs.lat) * COS(RADIANS(stores.latitude))
* COS(RADIANS(dc.longitude - stores.longitude))
+ SIN(RADIANS(dc.latitude))
* SIN(RADIANS(wm_stores.lon)))))) <= 250.0;

Arel subselects with ActiveRecord?

I'm using a slightly-modified version of the geocoded gem which returns this query when I call near on my model (calling Deal.near(southwest), where southwest is an array of geo coordinates):
SELECT
deals.*,
3958.755864232 * 2 * ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180 / 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat * PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() / 180 / 2), 2) )) AS distance,
CAST(DEGREES(ATAN2( RADIANS(addresses.lng - -122.42336332798004), RADIANS(addresses.lat - 37.772476604436974))) + 360 AS decimal) % 360 AS bearing
FROM "deals"
INNER JOIN "companies" ON "companies"."id" = "deals"."company_id"
INNER JOIN "addresses" ON "addresses"."addressable_id" = "companies"."id" AND "addresses"."addressable_type" = 'Company'
WHERE (
addresses.lat BETWEEN 37.483013038215276 AND 38.06194017065867
AND addresses.lng BETWEEN -122.78956461309022 AND -122.05716204286986
)
GROUP BY
deals.id,
deals.created_at,
deals.updated_at,
deals.active,
deals.company_id,
deals.title,
deals.limitations,
deals.redemption_count,
addresses.lat,
addresses.lng
HAVING 3958.755864232 * 2 * ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180 / 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat * PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() / 180 / 2), 2) )) <= 20
ORDER BY 3958.755864232 * 2 * ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180 / 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat * PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() / 180 / 2), 2) )) ASC
My issue is that this will return multiple Deal records if that Deal's company has multiple Addresses, which I don't want.
In MySQL, I could just omit address.lat, address.lng in the GROUP_BY clause and it will properly group the records, but I can't do this in PostgreSQL.
I know I could wrap the whole query above in another SELECT and GROUP_BY, like this:
SELECT
id, created_at, updated_at, active, title, punches_to_complete, company_id, description, lat, lng, MIN(distance), bearing
FROM ( ... ) AS t
GROUP BY company_id
... where the ellipsis is the query from above. That (I believe) should get me the desired result in both MySQL and PostgreSQL.
The only problem is that I have no idea how to write this in ARel!
I had tried the following, a la this tip from the ARel guru, but I couldn't really make it work quite right (calling to_sql as the OP had said fixed his issue escapes the quotes, which freaks PostgreSQL out).
Can anyone help me with this???
UPDATE:
I've managed to get this done with an additional scope, like so:
scope :nearest, lambda { |coords|
subquery = "(#{Deal.near(coords).to_sql}) AS t1"
columns = Deal.columns.map{ |c| c.name }.join(',')
Deal.select(columns)
.select('MIN(distance) AS distance')
.from(subquery)
.group(columns)
.order('distance ASC')
}
However, this totally breaks chainability, as now I cannot call something like current_user.deals.nearest(coords), since that tags on an additional WHERE deals.user_id = 1 to the query outside of the subselect. I tried compensating for this by moving this logic into a class method and blanking the wheres clause on the SelectManager manually, like this:
def self.nearest(coords)
subquery = "(#{Deal.near(coords).to_sql}) AS t1"
columns = Deal.columns.map{ |c| c.name }.join(',')
query = Deal.select(columns)
.select('MIN(distance) AS distance')
.from(subquery)
.group(columns)
.order('distance ASC')
query.arel.ast.cores[0].wheres = []
query
end
... but that doesn't seem to work either: the additional WHERE clause is still appended:
Failure/Error:
#user.deals.nearest(southwest).first.distance.to_f.round(2).should ==
ActiveRecord::StatementInvalid:
Mysql2::Error: Unknown column 'deals.user_id' in 'where
clause': SELECT id,created_at,updated_at,user_id,company_id,
MIN(distance) AS distance FROM (SELECT deals.*, 3958.755864232 * 2 *
ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180
/ 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat *
PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() /
180 / 2), 2) )) AS distance, CAST(DEGREES(ATAN2( RADIANS(addresses.lng
- -122.42336332798004), RADIANS(addresses.lat - 37.772476604436974)))
+ 360 AS decimal) % 360 AS bearing FROM deals INNER JOIN companies
ON companies.id = deals.company_id INNER JOIN addresses ON
addresses.addressable_id = companies.id AND
addresses.addressable_type = 'Company' WHERE deals.user_id =
26 AND (addresses.lat BETWEEN 37.483013038215276 AND 38.06194017065867
AND addresses.lng BETWEEN -122.78956461309022 AND -122.05716204286986)
GROUP BY
deals.id,deals.created_at,deals.updated_at,deals.user_id,deals.company_id,
addresses.lat, addresses.lng HAVING 3958.755864232 * 2 *
ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180
/ 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat *
PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() /
180 / 2), 2) )) <= 20 ORDER BY 3958.755864232 * 2 *
ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180
/ 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat *
PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() /
180 / 2), 2) )) ASC) AS t1 WHERE deals.user_id = 26 GROUP BY
id,created_at,updated_at,user_id,company_id ORDER BY distance ASC
LIMIT 1
Is what I'm trying to do even possible with ARel? The additional scopes above feel really dirty to me (parsing the subquery to raw SQL? I thought ARel was supposed to make it so I never did that!)
Related question: Can ARel formulate cross-db queries for CTEs (Common Table Expressions)?