Symfony2, Doctrine search and order by distance - symfony

I have a database of places which I store the latitude and longitude for. I want to query the database to find all places within a radius ($requestedDistance) of a specific latitude ($latitude) and longitude ($longitude).
The below query works and returns only those places within this radius, however how would I order them by distance so the closest is first? In the past, using raw SQL I have done the calculation within the SELECT statement and set it as 'distance' and then used HAVING distance < $requestedDistance ORDER BY distance, however I'm not sure how to add the calculation to the SELECT query using Doctrine Repository.
$d = $this->getDoctrine()->getRepository('XXXWebsiteBundle:Locations')->createQueryBuilder('l');
$d
->add('where','l.enabled = 1')
->andWhere('( 3959 * acos( cos( radians('.$latitude.') )
* cos( radians( l.latitude ) )
* cos( radians( l.longitude )
- radians('.$longitude.') )
+ sin( radians('.$latitude.') )
* sin( radians( l.latitude ) ) ) ) < '.$requestedDistance);
$result= $d->getQuery();
UPDATE
I've tried the following query thanks to #Lazy Ants:
$d = $this->getDoctrine()->getRepository('XXXWebsiteBundle:Locations')->createQueryBuilder('l');
$d
->select('l')
->addSelect(
'( 3959 * acos(cos(radians(' . $latitude . '))' .
'* cos( radians( l.latitude ) )' .
'* cos( radians( l.longitude )' .
'- radians(' . $longitude . ') )' .
'+ sin( radians(' . $latitude . ') )' .
'* sin( radians( l.latitude ) ) ) ) as distance'
)
->andWhere('l.enabled = :enabled')
->setParameter('enabled', 1)
->andWhere('distance < :distance')
->setParameter('distance', $requestedDistance)
->orderBy('distance', 'ASC');
However, it returns the following error:
`An exception occurred while executing 'SELECT COUNT(*) AS dctrn_count FROM
(SELECT DISTINCT il0 FROM (SELECT l0_.id AS il0, l0_.name AS name2, l0_.address1
AS address14, l0_.address2 AS address25, l0_.postcode AS postcode6, l0_.town AS
town7, l0_.county AS county8, l0_.enabled AS enabled11, l0_.date_created AS
date_created12, l0_.date_modified AS date_modified13, l0_.latitude AS
latitude19, l0_.longitude AS longitude20, 3959 * ACOS(COS(RADIANS(53.51331889999999))
* COS(RADIANS(l0_.latitude)) * COS(RADIANS(l0_.longitude) -
RADIANS(-2.935331099999985)) + SIN(RADIANS(53.51331889999999)) *
SIN(RADIANS(l0_.latitude))) AS sclr21 FROM locations l0_ WHERE l0_.enabled = ?
AND sclr21 < ? ORDER BY sclr21 ASC) dctrn_result) dctrn_table' with params
{"1":1,"2":30}:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'sclr21' in 'where clause'`

$d = $this->getDoctrine()->getRepository('XXXWebsiteBundle:Locations')->createQueryBuilder('l');
$d
->select('l')
->addSelect(
'( 3959 * acos(cos(radians(' . $latitude . '))' .
'* cos( radians( l.latitude ) )' .
'* cos( radians( l.longitude )' .
'- radians(' . $longitude . ') )' .
'+ sin( radians(' . $latitude . ') )' .
'* sin( radians( l.latitude ) ) ) ) as distance'
)
->andWhere('l.enabled = :enabled')
->setParameter('enabled', 1)
->having('distance < :distance')
->setParameter('distance', $requestedDistance)
->orderBy('distance', 'ASC');

You are using andWhere() without a where().
Replace the andWhere() with a where().
Please check also in your Entity definition if some property is mapped on a column called "sclr21", so you can discovery also on which property do you have the issue.

Related

Case When function with multiple conditions in Cognos Analytics 11.1.x

I am using Cognos embedded in Watson Studio and attempted creating the following calculation with case statement (both month_3 and avg2m are measures).
Cognos reports XQE-V5-0017 V5 syntax error found for data item 'calculation-new' of query 'validateQuery', invalid token "<" found after "case (( allin_shaped_csv.month_3 - avg2m ) / avg2m ) when ".
May you help fixing the syntax error?
case (( allin_shaped_csv.month_3 - avg2m ) / avg2m )
when <-0.50 then -100;
when <-0.20 then -50;
when <0 then -20;
when 0 then 0;
when >0 then 20;
when >0.50 then 50;
when >0.99 then 100;
end case;
it looks it works this way :
case
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )<-0.50 then -100
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )<-0.20 then -50
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )<0 then -20
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )=0 then 0
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )>0 then 20
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )>0.50 then 50
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )>0.99 then 100
else 0
end

How do I hydrate and Entity with extra data

So I have a query that gets distance to a site. The query returns the entities sites correctly, and it calculates the distance. This is my query.
$query = $this->getEntityManager()->createQuery('SELECT s, ROUND( ( :milesOrKm * acos( cos( radians(:myLat) ) * cos( radians( s.latitude ) ) * cos( radians( s.longitude ) - radians(:myLong) ) + sin( radians(:myLat) ) * sin( radians( s.latitude ) ) ) )) AS distance FROM AppBundle:Site s ORDER By distance ASC')->setParameter('milesOrKm', $units)
When the results come in, they are an array with my site, but also a distance. This is close to what I need, but I want the distance field added to my entity even though it's not a stored doctrine field.
array:2 [▼
0 => array:2 [▼
0 => Site {#512 ▶}
"distance" => "1"
]
1 => array:2 [▼
0 => Site {#521 ▶}
"distance" => "2649"
]
]
Basically I want
array:2 [▼
0 => Site {#512 ▶}
1 => Site {#521 ▶}
]
How do I add the distance to my entity? I have a distance protected property (with no annotation so it's not loaded and saved).
I suspect I need a custom hydration, but I'm having trouble figuring that out. Any suggestions?
What you need is your own custom hydrator.
Here is good example of how to do it

Group By breaks Having clause

I am querying the DB to get all venues within a certain X Radius of a given latitude & longitude.
Everything works good until I insert a count & group by, causing the Having clause to no longer filter out records that are
SELECT
locations.id AS 'locations_id_c',
locations.city AS 'locations_city_c',
locations.province AS 'locations_state_c',
locations.latitude AS 'latitude_c',
locations.longitude AS 'longitude_c',
venues.id AS 'venues_id_c',
venues.name AS 'venues_name_c',
venues.venue_rank,
venues.median_fb_likes,
count(gigs.show_time),
count(band_profiles.name) AS 'Related Band',
#san fran lat & long = 37.7833° N, 122.4167° W
# ( 3959 * acos( cos( radians(37.7833) ) * cos( radians( locations.latitude) ) * cos( radians( locations.longitude ) - radians(-122.4167) ) + sin( radians(37.7833) ) * sin(radians(locations.latitude)) ) ) AS 'distance'
3956 * 2 * ASIN(SQRT( POWER(SIN((37.7833 - abs(locations.latitude)) * pi()/180/2),2) +COS(37.7833 * pi()/180 )*COS(abs(locations.latitude)*pi()/180) *POWER(SIN((locations.longitude + 122.4167)*pi()/180/2),2))) as 'distance'
FROM locations
INNER JOIN venues
ON locations.locatable_id = venues.id
AND venues.venue_rank >= 0
LEFT JOIN gigs
ON gigs.venue_id = venues.id
and gigs.show_time > NOW()
LEFT JOIN band_profiles
ON gigs.account_id = band_profiles.account_id
and band_profiles.name IS NOT NULL
WHERE
locations.locatable_type = 'Venue'
group by venues.id
HAVING distance < 50
ORDER BY venues.venue_rank DESC, distance DESC;
got it working
Seems the group by must happen on the main table, and not one of the joins.
Does anyone have an explanation why this is so?

encountered ")." was expecting one of "as" in teradata

I am getting above mentioned error while executing a query against Teradata Studio express
select
Union16.Item as Item,
Union16.Description as Description,
Union16.Nbr_Trans as Nbr_Trans,
Union16.Unit_price as Unit_price,
Union16.Amount as Amount,
MIN(Union16.Amount) as Total_Amount_
from (select AL1.ticket_document_number as ticket_document_number,
AL1.transaction_code as transaction_code,
AL1.void_status as void_status,
AL1.transaction_date as transaction_date,
AL1.pnr_record_locator as pnr_record_locator,
AL1.settlement_base_fare_amt as settlement_base_fare_amt,
AL1.settlement_total_tax_amt as settlement_total_tax_amt,
AL1.Multiplier as Multiplier,
(AL1.Multiplier * 2) as Service_Incentive_Fee,
(AL1.Multiplier * 2) as Transaction_Fee,
(case when AL1.TRANSACTION_CODE = 'ET' and AL1.VOID_STATUS = 'N' then 1
when AL1.TRANSACTION_CODE = 'RF' and AL1.VOID_STATUS = 'N' then -1
else 0
end) as NetTrans,
0 as Comm_Amount,
SUM(1) as Total_Trans,
AL1.period_end_date as period_end_date,
SUM(NetTrans * 2) as Service_Fee_due,
AL1.airline_code as airline_code,
1 as Item,
(('Supplier Link Service Incentive Fee # $' || '2') || '/Tix') as Description,
2 as Unit_price,
SUM(NetTrans * 2) as Amount,
SUM(NetTrans * 2) as Transaction_Fee_due,
SUM((NetTrans * 2) + (NetTrans * 2)) as Total_Due,
SUM(1) as Total_Total_Trans_,
SUM(NetTrans * 2) as Total_Service_Fee_due_,
SUM(NetTrans * 2) as Total_Transaction_Fee_due_,
SUM((NetTrans * 2) + (NetTrans* 2)) as Total_Total_Due_,
SUM(NetTrans) as Net_Trans,
SUM(NetTrans) as Total_Net_Trans_,
SUM(NetTrans) as Nbr_Trans
from (SELECT LAST_DAY(AL1.period_end_date) AS PEDHEADER,
AL1.TICKET_DOCUMENT_NUMBER as TICKET_DOCUMENT_NUMBER ,
(case when AL1.TRANSACTION_CODE = 'ET' and AL1.VOID_STATUS = 'N' then 1
when AL1.TRANSACTION_CODE = 'RF' and AL1.VOID_STATUS = 'N' then -1
else 0
end) as NetTrans,
(case
when AL1.VOID_STATUS = 'V' then 0
when AL1.VOID_STATUS <> 'V' and AL1.TRANSACTION_CODE in ('AT','ET') then 1
when AL1.VOID_STATUS <> 'V' and AL1.TRANSACTION_CODE = 'RF' then -1
when AL1.VOID_STATUS <> 'V' and AL1.TRANSACTION_CODE not in ('AT','ET','RF') then 0
end
) as Multiplier,
AL1.TRANSACTION_CODE as TRANSACTION_CODE ,
AL1.VOID_STATUS as VOID_STATUS,
cast(AL1.TRANSACTION_DATE as date) as TRANSACTION_DATE ,
AL1.PNR_RECORD_LOCATOR as PNR_RECORD_LOCATOR ,
AL1.SETTLEMENT_BASE_FARE_AMT as SETTLEMENT_BASE_FARE_AMT ,
AL1.SETTLEMENT_TOTAL_TAX_AMT as SETTLEMENT_TOTAL_TAX_AMT,
cast(AL1.PERIOD_END_DATE as date) as PERIOD_END_DATE ,
AL1.AIRLINE_CODE as AIRLINE_CODE,
airline_name as airline_name ,
SUM (1 ) as Total_records,
0 as Total_comm_due,
SUM ((Multiplier * 2) ) as total_serv_inc_fee,
SUM ((Multiplier * 2) ) as total_trans_fee_due,
((0 + SUM((Multiplier * 2) )) + SUM((Multiplier * 2) )) as Total_amt_due,
0 as Comm_Amount,
(Multiplier * 2) as Service_Incentive_Fee,
(Multiplier * 2) as Transaction_Fee,
1 as cntr
FROM ODS_VIEWS.BOP_ARC_SETTLEMENT AL1
LEFT OUTER JOIN
(select tabC.refvalcode, tabC.acct_cd, tabC.airline_name, tabC.refvaltm
from (select ref1.refvalcode , max(case when ref1.refvalattribcode='numericCode' then ref1.refvalvalue else null end) as acct_cd,
max(case when ref1.refvalattribcode='Codedescription' then ref1.refvalvalue else null end) as airline_name,
tabA.refvaltm
from bial.refvalue ref1, (select refvalcode, refvalvalue as airline_name, max(refvalueid) as "refvaltm"
from bial.refvalue
where refvalcodesetcode='Carrier'
and refvalattribcode='Codedescription'
group by refvalcode, refvalvalue) tabA
where tabA.refvalcode = ref1.refvalcode
and ref1.refvalcodesetcode='Carrier'
group by ref1.refvalcode, tabA.refvaltm ) tabC
,
(select tabB.acct_cd, max(tabB.refvaltm) as "refvaltm"
from (select ref1.refvalcode , max(case when ref1.refvalattribcode='numericCode' then ref1.refvalvalue else null end) as acct_cd,
max(case when ref1.refvalattribcode='Codedescription' then ref1.refvalvalue else null end) as airline_name,tabA.refvaltm
from bial.refvalue ref1, (select refvalcode, refvalvalue as airline_name, max(refvalueid) as "refvaltm"
from bial.refvalue
where refvalcodesetcode='Carrier'
and refvalattribcode='Codedescription'
group by refvalcode, refvalvalue) tabA
where tabA.refvalcode = ref1.refvalcode
and ref1.refvalcodesetcode='Carrier'
group by ref1.refvalcode, tabA.refvaltm ) tabB
group by tabB.acct_cd
) tabD
where tabC.refvaltm = tabD.refvaltm
and tabC.acct_cd = tabD.acct_cd
) AIRDET
ON AL1.AIRLINE_CODE = AIRDET.acct_cd
WHERE cast(AL1.PERIOD_END_DATE as date) BETWEEN 01-01-2015 AND 31-01-2015
AND AL1.FILE_TYPE='AM'
AND AL1.SUPPLIER_LINK_INDICATOR='D'
AND AIRLINE_NAME = 'Alaska Airlines'
AND AL1.oltp_deleted_timestamp IS NULL
group by
AL1.period_end_date ,
AL1.TICKET_DOCUMENT_NUMBER,
NetTrans ,
Multiplier ,
AL1.TRANSACTION_CODE,
AL1.VOID_STATUS,
AL1.TRANSACTION_DATE,
AL1.PNR_RECORD_LOCATOR,
AL1.SETTLEMENT_BASE_FARE_AMT,
AL1.SETTLEMENT_TOTAL_TAX_AMT,
AL1.AIRLINE_CODE,
airline_name,
Total_comm_due,
Comm_Amount,
Service_Incentive_Fee,
Transaction_Fee,
cntr,
AL1.oltp_deleted_timestamp,
AL1.SUPPLIER_LINK_INDICATOR,
AL1.FILE_TYPE,
AL1.AIRLINE_CODE
)
) Union16
group by
Union16.Item,
Union16.Description,
Union16.Nbr_Trans,
Union16.Unit_price,
Union16.Amount
order by
Item asc,
Description asc;
Simply you have close look at the query editor. You will notice that Teradata Studio marks the position of the error.
There's an alias missing for the Derived Table before ) Union16

The query performance is very low + correlated subquery

The query's aim is to get reserved rooms status is 3 or going to reserve in 30 to 45 minutes status in 2 or unreserved status in 1. reservation rooms are in RESEENH table and each reservation is in ORD_NOARCHIVE table which has begintime and endtime of reservation. So for each reservation room this query checks whether reservation is available at current time also its checks the meeting room parents and children. if children is reserved then parents are are blocked.
it takes 10 secs to fetch first 50 records.
with cte as
(
SELECT DISTINCT R.syscode,
R.behcode,
R.syscode AS FK_RESERVATIONUNIT, (
CASE
WHEN R.TYPE = 3 THEN '1'
WHEN R.TYPE = 1 THEN '2'
ELSE NULL
END ) AS LOCATION_TYPE,
R.sysobjalg AS FK_PROPERTY,
MP.syscode AS FK_MEASUREMENTPOINT,
MP.fk_plc_occupancy_state AS FK_PLC_OCCUPANCY_STATE,
F.syscode AS FK_FLOOR,
R.transitiontime,
r.type,
r.is_compoundreservationunit,
r.is_archived,
MP.fk_person,
os.transitionperiod
FROM reseenh R
--left outer join ordtrantbl RSS
--ON RSS.reservationunisyscode = R.syscode
left outer join objond F
ON F.syscode = R.fk_floor
left outer join pln_measurementpoint MP
ON MP.fk_reservationunit = R.syscode
AND MP.is_primary_measurement_point = 'T',
pln_ordersetting os
)
select cte.syscode,cte.behcode,cte.FK_RESERVATIONUNIT,
(CASE
WHEN O.begindatetime_user IS NULL THEN '1' --GREEN
WHEN O.begindatetime_user - (Nvl(cte.transitiontime, ( cte.transitionperiod ))/1440 ) > current_date THEN '2' -- ORANGE
WHEN O.begindatetime_user + (Nvl(cte.transitiontime, ( cte.transitionperiod )) /1440 ) > current_date THEN '3' -- RED
ELSE '3'
END ) AS LOCAVAILABILITY_STATUS_CODE,
cte.LOCATION_TYPE,
cte.FK_PROPERTY,
Coalesce(O.sysmelder, cte.fk_person) AS FK_PERSON,
O.syscode AS FK_ORDER,
O.ref_bostate_userdefined AS FK_ORDER_STATE_USER,
O.fk_bostate AS FK_ORDER_STATE_SYSTEM,
FK_MEASUREMENTPOINT,FK_PLC_OCCUPANCY_STATE,FK_FLOOR
from cte left outer join ord_noarchive O on O.syscode in
( SELECT MAX(ord.syscode) KEEP (DENSE_RANK FIRST ORDER BY ord.begindatetime_user) OVER (PARTITION BY ord.sysreseenh )
FROM ord_noarchive ORD
WHERE ( ( (
current_date >= ( ORD.begindatetime_user - ( Nvl(cte.transitiontime, ( cte.transitionperiod ))/1440) )
AND (
current_date - ( Nvl(cte.transitiontime, (cte.transitionperiod )) / 1440 ) ) <=ORD.enddatetime_user )
OR ( (
current_date + ( (
CASE
WHEN (
cte.TYPE = 1 ) THEN 30
ELSE 45
END ) / 1440 ) ) >= ( ORD.begindatetime_user - (Nvl(cte.transitiontime, ( cte.transitionperiod))/1440 ) )
AND (
current_date - ( Nvl(cte.transitiontime, ( cte.transitionperiod )) / 1440 ) ) < ORD.enddatetime_user ) )
AND ORD.sysreseenh IN
(
SELECT fk_reservationunit_parent
FROM pln_reservationunit_rut
WHERE fk_reservationunit_child IN
(
SELECT fk_reservationunit_child
FROM pln_reservationunit_rut
WHERE cte.is_compoundreservationunit = 'T'
AND fk_reservationunit_parent = cte.syscode)
UNION
SELECT cte.syscode
FROM dual
UNION
SELECT
CASE
WHEN cte.is_compoundreservationunit = 'T' THEN fk_reservationunit_child
ELSE fk_reservationunit_parent
END
FROM pln_reservationunit_rut
WHERE (
cte.is_compoundreservationunit = 'T'
AND fk_reservationunit_parent = cte.syscode )
OR (
cte.is_compoundreservationunit = 'F'
AND fk_reservationunit_child = cte.syscode ))
AND ORD.fk_bostate IN
(
SELECT syscode
FROM pln_bostate
WHERE pnname IN ( 'Requested',
'Made',
'AdministrativelyCompleted' )
AND fk_bodefinition = ref_bodefinition)
AND ORD.sysreseenh = O.sysreseenh
))
WHERE cte.is_archived = 'F'
AND cte.TYPE IN ( 1,
3 )
AND cte.fk_floor=495
No time to analyze the details of a very complex query, but my overall sense is that you are trying to do too many things at once. Separate the tasks. Check on room availability in one query, and check on the children/parent thing in a separate query.
Also, you could analyze the execution plan for the query and see what it bogging it down. My suspicion (again without time to really try to understand your query) is that at some point the mixing of tasks is translating into a many-to-many relationship where you have an intermediate result that is a cross product of rows between some of the tables in your query.

Resources