|
| [MySQL] Hvorfor findes der ikke en NEARERS~ Fra : Jekka |
Dato : 12-12-03 10:19 |
|
Jeg har nogle poster i min MySQL database:
A B
3,9912 9,0121
3,7212 6,7123
7,7126 8,1772
Hvis jeg så skal finde den linie, som kommer nærmest "A=4,0122, B=7,3212"
(det er jo så række 2) - hvordan kan dét gøres?
Jeg har overvejet lidt men kan alligevel ikke helt se hvordan (betweens..
round m.v.).
Det skal siges, at der er flere millioner records i den tabel, så jeg kan
ikke bare trække alle ud og så viderebehandle i PHP (og det er i forvejen
ikke verdens hurtigste maskine jeg har)
| |
Troels Arvin (12-12-2003)
| Kommentar Fra : Troels Arvin |
Dato : 12-12-03 10:39 |
|
On Fri, 12 Dec 2003 10:18:47 +0100, Jekka wrote:
> Jeg har nogle poster i min MySQL database:
[...]
Har du overvejet om en mere avanceret database kunne være relevant for
din ret avancerede problemstilling? MySQL har godtnok nogle
GIS/geometri-agtige features under udvikling, der måske kunne være
interessante for dig, men ifølge[1] er PostgreSQL p.t. det bedste valg
til den slags, i hvertfald hvis man sammenligner PostgreSQL, DB2 og MySQL.
Hvis PostgreSQL's indbyggede geometry-typer[2] og -funktioner[3] ikke er
tilstrækkelige, kan PostgreSQL udvides med "PostGIS"[4].
Noter:
1:
"Report on Cross Matching Catalogues",
http://wiki.astrogrid.org/pub/Astrogrid/DataFederationandDataMining/cross.htm
2:
http://www.postgresql.org/docs/current/static/datatype-geometric.html
3:
http://www.postgresql.org/docs/current/static/functions-geometry.html
4:
PostGIS: http://postgis.refractions.net/
--
Greetings from Troels Arvin, Copenhagen, Denmark
| |
Jesper Krogh (12-12-2003)
| Kommentar Fra : Jesper Krogh |
Dato : 12-12-03 10:40 |
|
I dk.edb.database, skrev Jekka:
> Jeg har nogle poster i min MySQL database:
>
> A B
> 3,9912 9,0121
> 3,7212 6,7123
> 7,7126 8,1772
>
> Hvis jeg så skal finde den linie, som kommer nærmest "A=4,0122, B=7,3212"
> (det er jo så række 2) - hvordan kan dét gøres?
mysql> describe test;
+-------+-------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------+------+-----+---------+-------+
| a | float | YES | | NULL | |
| b | float | YES | | NULL | |
+-------+-------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> select * from test;
+--------+--------+
| a | b |
+--------+--------+
| 3.9912 | 9.0121 |
| 3.7212 | 6.7123 |
| 7.7126 | 9.1772 |
+--------+--------+
3 rows in set (0.00 sec)
mysql> select a,b,ABS(a-4.0122)+ABS(b-7.3213) as diff from test order by diff li
mit 1;
+--------+--------+------------------+
| a | b | diff |
+--------+--------+------------------+
| 3.7212 | 6.7123 | 0.90000018692017 |
+--------+--------+------------------+
1 row in set (0.00 sec)
mysql>
Sådan noget?
--
../Jesper Krogh, jesper@krogh.cc
Jabber ID: jesper@jabbernet.dk
Tøm din hjerne for Linuxviden på http://www.linuxwiki.dk
| |
Thorbjørn Ravn Ander~ (12-12-2003)
| Kommentar Fra : Thorbjørn Ravn Ander~ |
Dato : 12-12-03 13:00 |
|
Jesper Krogh wrote:
> mysql> select a,b,ABS(a-4.0122)+ABS(b-7.3213) as diff from test order by diff li
Her skal man så overveje hvordan "tættest" beregnes for flere variable.
Denne er nok nemmest at beregne.
--
Thorbjoern Ravn Andersen "...plus...Tubular Bells!"
| |
Jekka (12-12-2003)
| Kommentar Fra : Jekka |
Dato : 12-12-03 13:39 |
|
> mysql> select a,b,ABS(a-4.0122)+ABS(b-7.3213) as diff from test order by
diff li
> mit 1;
> +--------+--------+------------------+
> | a | b | diff |
> +--------+--------+------------------+
> | 3.7212 | 6.7123 | 0.90000018692017 |
> +--------+--------+------------------+
>
> Sådan noget?
Nå, dét kan man da kalde et forståeligt eksempel! Ja, lige præcist sådan
noget (det virker). Det er dog bare lidt sløvt, når der nu er flere
millioner records i tabellen, men det kan vel ikke optimeres yderligere?
Helt konkret skal jeg bruge det til at søge i Kort og Matrikelstrelsens
database over adresser (ud fra længde-/breddegrad). Og dér er altså cirka
2,5mio. records
| |
Thorbjørn Ravn Ander~ (15-12-2003)
| Kommentar Fra : Thorbjørn Ravn Ander~ |
Dato : 15-12-03 12:03 |
|
Jekka wrote:
> Helt konkret skal jeg bruge det til at søge i Kort og Matrikelstrelsens
> database over adresser (ud fra længde-/breddegrad). Og dér er altså cirka
> 2,5mio. records
Så var det måske en ide at hitte på en måde så du kun kigger på det
landeområde i "nærheden" af hvor du er?
--
Thorbjoern Ravn Andersen "...plus...Tubular Bells!"
| |
Peter Brodersen (12-12-2003)
| Kommentar Fra : Peter Brodersen |
Dato : 12-12-03 14:32 |
|
On Fri, 12 Dec 2003 10:40:09 +0100, Jesper Krogh <jesper@krogh.cc>
wrote:
>mysql> select a,b,ABS(a-4.0122)+ABS(b-7.3213) as diff from test order by diff li
>mit 1;
Ehm, hvis vi har punktet 1,1 - så vil dit eksempel mene, at 2,2 og 3,1
er lige langt fra 1,1? Det er jo ikke tilfældet.
Du skal indbygge pythagoras. Det burde dog være en snild sag.
--
- Peter Brodersen
Ugens sprogtip: jamen (og ikke jammen)
| |
Jesper Krogh (12-12-2003)
| Kommentar Fra : Jesper Krogh |
Dato : 12-12-03 14:35 |
|
I dk.edb.database, skrev Peter Brodersen:
> On Fri, 12 Dec 2003 10:40:09 +0100, Jesper Krogh <jesper@krogh.cc>
> wrote:
>
> >mysql> select a,b,ABS(a-4.0122)+ABS(b-7.3213) as diff from test order by diff li
> >mit 1;
>
> Ehm, hvis vi har punktet 1,1 - så vil dit eksempel mene, at 2,2 og 3,1
> er lige langt fra 1,1? Det er jo ikke tilfældet.
>
> Du skal indbygge pythagoras. Det burde dog være en snild sag.
Det medgiver jeg.. nu gik første spørgsmål dog ikke på at det var et
koordinatsæt der blev regnet på. Og "nærmest" var ikke defineret..
--
../Jesper Krogh, jesper@krogh.cc
Jabber ID: jesper@jabbernet.dk
Tøm din hjerne for Linuxviden på http://www.linuxwiki.dk
| |
Jekka (12-12-2003)
| Kommentar Fra : Jekka |
Dato : 12-12-03 15:34 |
|
> >mysql> select a,b,ABS(a-4.0122)+ABS(b-7.3213) as diff from test order by
diff li
> >mit 1;
>
> Ehm, hvis vi har punktet 1,1 - så vil dit eksempel mene, at 2,2 og 3,1
> er lige langt fra 1,1? Det er jo ikke tilfældet.
>
> Du skal indbygge pythagoras. Det burde dog være en snild sag.
Og for dem som ikke mener "det burde være en snild sag"? Det er noget
med længde^2 * bredde^2 og så ét eller andet ... ?
| |
Jesper Krogh (12-12-2003)
| Kommentar Fra : Jesper Krogh |
Dato : 12-12-03 15:39 |
|
I dk.edb.database, skrev Jekka:
> > >mysql> select a,b,ABS(a-4.0122)+ABS(b-7.3213) as diff from test order by
> diff li
> > >mit 1;
> >
> > Ehm, hvis vi har punktet 1,1 - så vil dit eksempel mene, at 2,2 og 3,1
> > er lige langt fra 1,1? Det er jo ikke tilfældet.
> >
> > Du skal indbygge pythagoras. Det burde dog være en snild sag.
>
> Og for dem som ikke mener "det burde være en snild sag"? Det er noget
> med længde^2 * bredde^2 og så ét eller andet ... ?
Og til dette job, kan man endda droppe "ét eller andet" og nøjes med det
første.
--
../Jesper Krogh, jesper@krogh.cc
Jabber ID: jesper@jabbernet.dk
Tøm din hjerne for Linuxviden på http://www.linuxwiki.dk
| |
Jekka (12-12-2003)
| Kommentar Fra : Jekka |
Dato : 12-12-03 15:54 |
|
> > > >mysql> select a,b,ABS(a-4.0122)+ABS(b-7.3213) as diff from test order
by
> > diff li
> > > >mit 1;
> > >
> > > Ehm, hvis vi har punktet 1,1 - så vil dit eksempel mene, at 2,2 og 3,1
> > > er lige langt fra 1,1? Det er jo ikke tilfældet.
> > >
> > > Du skal indbygge pythagoras. Det burde dog være en snild sag.
> >
> > Og for dem som ikke mener "det burde være en snild sag"? Det er
noget
> > med længde^2 * bredde^2 og så ét eller andet ... ?
>
> Og til dette job, kan man endda droppe "ét eller andet" og nøjes med det
> første.
Dvs. "select a,b,ABS(a-(4.0122*4.0122))+ABS(b-(7.3213*7.3213)) as diff from
test order by diff" ? Skulle det give den store forskel? Jeg mener.. det gør
jo bare, at der bliver forholdsvis mere forskel på dem, men det ændre vel
ikke resultatet?
Output tidligere:
[2, 3.7212, 6.7123, 2.9910998344421]
[3, 7.7126, 9.1772, 4.8898005485535]
[1, 3.9912, 9.0121, 5.0209002494812]
Output nu:
[2, 3.7212, 6.7123, 65.840299129486]
[3, 7.7126, 9.1772, 74.173401355743]
[1, 3.9912, 9.0121, 77.069301128387]
| |
Jesper Krogh (12-12-2003)
| Kommentar Fra : Jesper Krogh |
Dato : 12-12-03 16:19 |
|
I dk.edb.database, skrev Jekka:
> > > Og for dem som ikke mener "det burde være en snild sag"? Det er
> noget
> > > med længde^2 * bredde^2 og så ét eller andet ... ?
> >
> > Og til dette job, kan man endda droppe "ét eller andet" og nøjes med det
> > første.
>
> Dvs. "select a,b,ABS(a-(4.0122*4.0122))+ABS(b-(7.3213*7.3213)) as diff from
> test order by diff" ? Skulle det give den store forskel? Jeg mener.. det gør
> jo bare, at der bliver forholdsvis mere forskel på dem, men det ændre vel
> ikke resultatet?
Det var forkert..
Det er hele den ABS() du skal gange med sig selv.
--
../Jesper Krogh, jesper@krogh.cc
Jabber ID: jesper@jabbernet.dk
Tøm din hjerne for Linuxviden på http://www.linuxwiki.dk
| |
Jekka (12-12-2003)
| Kommentar Fra : Jekka |
Dato : 12-12-03 17:20 |
|
> > Dvs. "select a,b,ABS(a-(4.0122*4.0122))+ABS(b-(7.3213*7.3213)) as diff
from
> > test order by diff" ? Skulle det give den store forskel? Jeg mener..
det gør
> > jo bare, at der bliver forholdsvis mere forskel på dem, men det ændre
vel
> > ikke resultatet?
>
> Det var forkert..
> Det er hele den ABS() du skal gange med sig selv.
a = 4.0122
b = 7.3213
select a, b,
(ABS(a-4.0122)*ABS(a-4.0122))+(ABS(b-7.3213)*ABS(b-7.3213)) as diff
from test order by diff
[2, 3.7212, 6.7123, 0.45556222087558]
[1, 3.9912, 9.0121, 2.8592463842771]
[3, 7.7126, 9.1772, 17.137327858909]
Tjaa.. der er jo lidt mere forskel på det end "originalt", så det er jo nok
godt nok. Resultatet ser da fint ud.
Men mht. process tiden - hvad er det smarteste mon.. at trække de 2,5 mio.
records ud af databasen og ind i PHP (og så arbejde videre med det dérfra)
eller finde en anden "formel" til SQL'en?
| |
Kim Hansen (12-12-2003)
| Kommentar Fra : Kim Hansen |
Dato : 12-12-03 17:43 |
|
"Jekka" <a@b.cde> writes:
> Dvs. "select a,b,ABS(a-(4.0122*4.0122))+ABS(b-(7.3213*7.3213)) as diff from
> test order by diff" ? Skulle det give den store forskel? Jeg mener.. det gør
> jo bare, at der bliver forholdsvis mere forskel på dem, men det ændre vel
> ikke resultatet?
SELECT a,b,pow(a-4.0122,2)+pow(b-7.3213,2) as diff ...
Måske er det hurtigere at bruge (a-4.0122)*(a-4.0122) i stedet for
pow(), det må du finde d af ved at teste.
Men det er sikkert endnu bedre at skifte til postgresql, den database
har en masse special-funktioner der er lavet til dette.
--
Kim Hansen | |\ _,,,---,,_ | Det er ikke
Dalslandsgade 8, A708 | /,`.-´` -. ;:-. | Jeopardy.
2300 København S | |,4- ) )-,_. ,\ ( `'-' | Svar _efter_
Tlf: 32 88 60 86 | '---''(_/--' `-'\_) | spørgsmålet.
| |
Peter Brodersen (12-12-2003)
| Kommentar Fra : Peter Brodersen |
Dato : 12-12-03 18:10 |
|
On Fri, 12 Dec 2003 15:38:37 +0100, Jesper Krogh <jesper@krogh.cc>
wrote:
>> Og for dem som ikke mener "det burde være en snild sag"? Det er noget
>> med længde^2 * bredde^2 og så ét eller andet ... ?
>Og til dette job, kan man endda droppe "ét eller andet" og nøjes med det
>første.
Pythagoras er a^2 + b^2 = c^2. Det er ikke heldigt at gange, for hvis
bredden er lig 0, så vil (længde^2 * bredde^2) også lig med 0 :)
Så det må blive noget i stil med:
SQRT(POW((a-4.0122),2)+POW((b-7.3213),2))
Jeg har udeladt ABS(), da det her vil give samme resultat. I
princippet kan man også udelade SQRT(), hvis man ikke vil have
afstanden ud, men blot bruger feltet til at sortere efter.
--
- Peter Brodersen
Ugens sprogtip: jamen (og ikke jammen)
| |
|
|