We got the following Entities: GeoShape (abstract, id, latitude and longitude), GeoCircle (just a radius) and GeoPolygon (just a polygon column).
Now i want to query all shapes with something like this:
if polygon is not null then
return ST_CONTAINS(polygon, ...)
else lat,lng in circle then
return in cirlce
But what i got is this:
if polygon is not null and ST_CONTAINS(polygon, ...) then
return true
else lat,lng in circle then
return in cirlce
I tried to create the following querybuilder but cannot archive what i want:
$queryBuilder
->join(sprintf('%s.geoShape', $alias), 'geoShape')
->where($queryBuilder->expr()->andX(
$queryBuilder->expr()->isNotNull('polygon'),
$queryBuilder->expr()->eq('ST_CONTAINS(polygon, Point(:longitude, :latitude))', true)
))
// thats my problem. i don't know how to do the else case
->orWhere('
6371000 * acos(
cos(
radians( :latitude )
) * cos(
radians( geoShape.center.latitude )
) * cos(
radians( geoShape.center.longitude ) - radians( :longitude )
) + sin(
radians( :latitude )
) * sin(
radians( geoShape.center.latitude )
)
) <= :radius
')
->setParameters(
array(
'latitude' => $location->getLatitude(),
'longitude' => $location->getLongitude(),
'radius' => $radius
)
);
return $queryBuilder;
The polygon has to be more important then the circle. If the location is not in the polygon then the query should stop and not check for the circle. Only if no polygon is set.
I found a solution. Now i just ask for the type in both cases.
$qb
->join(sprintf('%s.geoShape', $alias), 'shape')
->leftJoin(GeoPolygon::class, 'p', Join::WITH, 'shape.id = p.id')
->leftJoin(GeoCircle::class, 'c', Join::WITH, 'shape.id = c.id')
->where($qb->expr()->andX(
$qb->expr()->isInstanceOf('shape', GeoPolygon::class),
$qb->expr()->eq('ST_CONTAINS(p.polygon, Point(:longitude, :latitude))', true)
))
->orWhere($qb->expr()->andX(
$qb->expr()->isInstanceOf('shape', GeoCircle::class),
$qb->expr()->lte('
6371000 * acos(
cos(
radians( :latitude )
) * cos(
radians( shape.center.latitude )
) * cos(
radians( shape.center.longitude ) - radians( :longitude )
) + sin(
radians( :latitude )
) * sin(
radians( shape.center.latitude )
)
)
', $radius)
))
->setParameters(
array(
'latitude' => $location->getLatitude(),
'longitude' => $location->getLongitude()
)
);
return $qb;
Related
Hi and thanks for reading,
I am manually calculating a trend line in Power BI using linear regression. I used the formula from here: https://xxlbi.com/blog/simple-linear-regression-in-dax/
My problem is that the numerator of the slope is always 0
(This--> (Count_Items * Sum_XY - Sum_X * Sum_Y)).
I have no idea why (count_items* Sum_XY) - (sum_x * sum_y) is always 0.
Here is my DAX formula I used:
measure = VAR Known =
FILTER (
SELECTCOLUMNS (
CALCULATETABLE ( VALUES ( 'table'[Date] ), ALLSELECTED ('table') ),
//ALLSELECTED ( 'table'[Date] ),
"Known[X]", value('table'[Date]),
"Known[Y]", sum('table'[TotalPeople])
),
AND (
NOT ( ISBLANK ( Known[X] ) ),
NOT ( ISBLANK ( Known[Y] ) )
)
)
VAR Count_Items =
COUNTROWS ( Known )
VAR Sum_X =
SUMX(Known,Known[X])
VAR Sum_X2 =
SUMX ( Known, Known[X] ^ 2 )
VAR Sum_Y =
SUMX ( Known, Known[Y] )
VAR Sum_XY =
SUMX ( Known, Known[X] * Known[Y] )
VAR Average_X =
AVERAGEX ( Known, Known[X] )
VAR Average_Y =
AVERAGEX ( Known, Known[Y] )
VAR Slope =
DIVIDE (
(Count_Items * Sum_XY - Sum_X * Sum_Y),
(Count_Items * Sum_X2 - Sum_X ^ 2)
)
VAR Intercept =
Average_Y - Slope * Average_X
//I am only returning the numerator of the slope because always being 0 ruins the equation.
RETURN
Count_Items * Sum_XY - Sum_X * Sum_Y
Here is some example data from my table:
Date,TotalPeople
3/21/2020 12:00:00 AM,4
3/22/2020 12:00:00 AM,3
3/23/2020 12:00:00 AM,5
etc
I has a Django models for location based services and try to filter location by radius.
I try use .extra() query but not working. The value of distance can only use for sort, not filter.
# models.py
class Location(models.Model):
latitude = models.FloatField()
longitude = models.FloatField()
place_name = models.CharField(max_length=65)
class Meta:
db_table = "shop_location"
def __str__(self):
return self.place_name
# views.py
shop_locations = Location.objects.extra(
select={
'distance': '6371 * acos( cos( radians(9) )'
'* cos( radians( COALESCE(latitude, 0) ) )'
'* cos( radians( COALESCE(longitude, 0) )'
'- radians(11) ) + sin( radians(9) )'
'* sin( radians( COALESCE(latitude, 0) ) ) )'
},
).extra(order_by=['distance']).filter(distance<10) # on radius 10KM
But return error name 'distance' is not defined.
How to fix it.
I don't want use GeoDjango.
I try to migrate a legacy MySQL query to TYPO3 8.7 with Doctrine.
Legacy SQL statement:
SELECT
tt_address.*,
( 6371.41 * acos( cos( radians('.$lat.') ) * cos( radians(tt_address.tx_geosearch_lat ) ) * cos( radians(tt_address.tx_geosearch_lng ) - radians('.$lng.') ) + sin( radians('.$lat.') ) * sin( radians(tt_address.tx_geosearch_lat ) ) ) ) AS distance
FROM tt_address
My attempt with TYPO3 8.7:
$statement = $queryBuilder
->select(
'tt_address.*',
'( 6371.41 * acos( cos( radians(' . $queryBuilder->createNamedParameter($lat, \PDO::PARAM_STR) . ') ) * cos( radians(tt_address.tx_geosearch_lat ) ) * cos( radians(tt_address.tx_geosearch_lng ) - radians(' . $queryBuilder->createNamedParameter($lng, \PDO::PARAM_STR) . ') ) + sin( radians(' . $queryBuilder->createNamedParameter($lat, \PDO::PARAM_STR) . ') ) * sin( radians(tt_address.tx_geosearch_lat ) ) ) ) AS distance'
)
->from('tt_address')
This leads to a completely broken SQL query:
SELECT `tt_address`.*,
`( 6371`.`41 * acos( cos( radians(48.0818583) ) * cos( radians(tt_address`.`tx_geosearch_lat ) ) * cos( radians(tt_address`.`tx_geosearch_lng ) - radians(11.9879884) ) + sin( radians(48.0818583) ) * sin( radians(tt_address`.`tx_geosearch_lat ) ) ) )` AS `distance`
FROM `tt_address`
Any pointers on how to solve this?
I'm not sure if this is possible with the querybuilder. Nevertheless I would do it with a connection:
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($tableName);
$row = $connection->executeQuery('select * from ' . $tableName . ' where uid = 1')->fetchAll();
You can use addSelectLiteral() for your query:
$statement = $queryBuilder
->select(
'tt_address.*'
)
->addSelectLiteral('
6371.41 * acos(
cos(
radians(' . $queryBuilder->createNamedParameter($lat, \PDO::PARAM_STR) . ')
) * cos(
radians(tt_address.tx_geosearch_lat)
) * cos(
radians(tt_address.tx_geosearch_lng) - radians(' . $queryBuilder->createNamedParameter($lng, \PDO::PARAM_STR) . ')
) + sin(
radians(' . $queryBuilder->createNamedParameter($lat, \PDO::PARAM_STR) . ')
) * sin(
radians(tt_address.tx_geosearch_lat)
)
) AS distance
')
->from('tt_address')
I need to write an statement IF VALUE 1 equals A2 and VALUE 2 equals B2 and VALUE 3 equals C2 then return the price of D2 but if D2 is blank return the price from the previous date of A2. So the example below If VALUE 1 is 6/30/2012 and VALUE 2 is Sweater and VALUE 3 is SW123456 the results will be 19.00 (from 3/31/2012) since 6/30/2012 is blank.
TABLE example:
A B C D
DATE TYPE ITEM NO PRICE
6/30/2012 Sweater SW123456
3/31/2012 Sweater SW123456 19.00
VALUE 1: 6/30/2012
VALUE 2: Sweater
VALUE 3: SW123456
RESULTS:
I've moved your inputs (VALUE 1 etc) and RESULT to G1:G4, so we can use the whole range A:D for the data.
First, you want to look up the latest date before or on the date you're looking at that has a match for all other criteria and has a price that's not empty. You can do this by using the formula:
= MAX( INDEX( A:A, MATCH( 1, (A:A <= G1 ) * ( B:B = G2 ) * ( C:C = G3 ) * ( NOT( ISBLANK( D:D ) ) ), 0 ) ) )
This is an array formula, so you should confirm by ctrl+shift+Enter rather than just Enter. In your example, this should give you 3/31/12. For the sake of argument, let's call this "myDate".
Secondly, you need to find the price which matches the VALUE 2 and VALUE 3, as well as the date you've just found. This can be done as follows:
= INDEX( D:D, MATCH( 1, ( A:A = myDate ) * ( B:B = G2 ) * ( C:C = G3 ), 0 ) )
This is again an array formula. Now, all we need to do is replace "myDate" with the first function, which gives us:
= INDEX( D:D, MATCH( 1, ( A:A = MAX( INDEX( A:A, MATCH( 1, ( A:A <= G1 ) * ( B:B = G2 ) * ( C:C = G3 ) * ( NOT( ISBLANK( D:D ) ) ), 0 ) ) ) ) * ( B:B = G2 ) * ( C:C = G3 ), 0 ) )
Again, this is an array formula, so confirm with ctrl+shift+Enter.
Try this:
=INDEX($D:$D,MATCH(MAX(IF($A:$A<G1,IF($B:$B=G2,IF($C:$C=G3,IF($D:$D<>"",$A:$A))))),IF($A:$A<G1,IF($B:$B=G2,IF($C:$C=G3,IF($D:$D<>"",$A:$A)))),0))
This is an array formula and needs to be confirmed with Ctrl-Shift-Enter.
I set up my sheet like this, so you can understand the references:
Supose a student attandance system.
For a student and a course we have N:M relation named attandance.
Also whe have a model with attandances status (present, absent, justified, ...).
level( id, name, ... )
student ( id, name, ..., id_level )
course( id, name, ... )
status ( id, name, ...) #present, absemt, justified, ...
attandance( id, id_student, id_course, id_status, date, hour )
unique_together = ((id_student, id_course, id_status, date, hour),)
I'm looking for a list of students with >20% of absent for a level sorted by %. Something like:
present = status.objects.get( name = 'present')
justified = status.objects.get( name = 'justified')
absent = status.objects.get( name = 'absent')
#here the question. How to do this:
Student.objects.filter( level = level ).annotate(
nPresent =count( attandence where status is present or justified ),
nAbsent =count( attandence where status is absent ),
pct = nAbsent / (nAbsent + nPresent ),
).filter( pct__gte = 20 ).order_by( "-pct" )
If it is not possible to make it with query api, any workaround (lists, sets, dictionaris, ...) is wellcome!
thanks!
.
.
.
---- At this time I have a dirty raw sql writed by hand --------------------------
select
a.id_alumne,
coalesce ( count( p.id_control_assistencia ), 0 ) as p,
coalesce ( count( j.id_control_assistencia ), 0 ) as j,
coalesce ( count( f.id_control_assistencia ), 0 ) as f,
1.0 * coalesce ( count( f.id_control_assistencia ), 0 ) /
( coalesce ( count( p.id_control_assistencia ), 0 ) + coalesce ( count( f.id_control_assistencia ), 0 ) ) as tpc
from
alumne a
inner join
grup g
on (g.id_grup = a.id_grup )
inner join
curs c
on (c.id_curs = g.id_curs)
inner join
nivell n
on (n.id_nivell = c.id_nivell)
inner join
control_assistencia ca
on (ca.id_estat is not null and
ca.id_alumne = a.id_alumne )
inner join
impartir i
on ( i.id_impartir = ca.id_impartir )
left outer join
control_assistencia p
on (
p.id_estat in ( select id_estat from estat_control_assistencia where codi_estat in ('P','R' ) ) and
p.id_control_assistencia = ca.id_control_assistencia )
left outer join
control_assistencia j
on (
j.id_estat = ( select id_estat from estat_control_assistencia where codi_estat = 'J' ) and
j.id_control_assistencia = ca.id_control_assistencia )
left outer join
control_assistencia f
on (
f.id_estat = ( select id_estat from estat_control_assistencia where codi_estat = 'F' ) and
f.id_control_assistencia = ca.id_control_assistencia )
where
n.id_nivell = {0} and
i.dia_impartir >= '{1}' and
i.dia_impartir <= '{2}'
group by
a.id_alumne
having
1.0 * coalesce ( count( f.id_control_assistencia ), 0 ) /
( coalesce ( count( p.id_control_assistencia ), 0 ) + coalesce ( count( f.id_control_assistencia ), 0 ) )
> ( 1.0 * {3} / 100)
order by
1.0 * coalesce ( count( f.id_control_assistencia ), 0 ) /
( coalesce ( count( p.id_control_assistencia ), 0 ) + coalesce ( count( f.id_control_assistencia ), 0 ) )
desc
'''.format( nivell.pk, data_inici, data_fi, tpc )
If you don't care too much whether it uses the query api or python after the fact, use itertools.groupby.
attendances = Attendance.objects.select_related().filter(student__level__exact=level)
students = []
for s, g in groupby(attendances, key=lambda a: a.student.id):
g = list(g) # g is an iterator
present = len([a for a in g if a.status == 'present'])
absent = len([a for a in g if a.status == 'absent'])
justified = len([a for a in g if a.status == 'justified'])
total = len(g)
percent = int(absent / total)
students.append(dict(name=s.name, present=present, absent=absent, percent=percent))
students = (s for s in sorted(students, key=lambda x: x['percent']) if s['percent'] > 25)
You can pass the resulting list of dicts to the view the same way you would any other queryset.