|
| Optælling af begyndelsesbogstver. Fra : Arne Feldborg |
Dato : 02-04-04 10:10 |
|
Haløjsa...
Jeg har en database (MySql) med nogle tusinde navne opdelt i for og
efternavne. I en bestemt søgning ønsker jeg oplyst hvor mange fornavne
der er med hvert begyndelsesbogtstav fra 'A' til 'Z'
Jeg har hidtil listet samtlige forekommende fornavne ved en optælling
baseret på "group by firstname order by firstname".
Men databasen har nu nået en størrelse hvor dette ikke længere er
hensigtsmæssigt.
Det jeg ønske nu er blot at opyse hvor mange fornavne der der begynder
med 'A', hvor mange der begynder med 'B' osv., og så gå videre til de
enkelte begyndelsesbogtaver derfra.
Altså:
$sql = "SELECT count(*) from $tabel[ind] where firstname like 'a%'";
$sql = "SELECT count(*) from $tabel[ind] where firstname like 'b%'";
$sql = "SELECT count(*) from $tabel[ind] where firstname like 'c%'";
osv. osv.
Men det må da kunne gøres på en smartere måde.?
--
mvh, A:\Feldborg
Folketællinger Hammerum og Bølling herreder, kirkebøger Hammerum herred
http://www.haunstrup.dk/feldborg/genealogi/download/
| |
Jeppe Uhd (02-04-2004)
| Kommentar Fra : Jeppe Uhd |
Dato : 02-04-04 10:25 |
|
Arne Feldborg wrote:
> Haløjsa...
>
> Jeg har en database (MySql) med nogle tusinde navne opdelt i for og
> efternavne. I en bestemt søgning ønsker jeg oplyst hvor mange fornavne
> der er med hvert begyndelsesbogtstav fra 'A' til 'Z'
>
> Jeg har hidtil listet samtlige forekommende fornavne ved en optælling
> baseret på "group by firstname order by firstname".
> Men databasen har nu nået en størrelse hvor dette ikke længere er
> hensigtsmæssigt.
>
> Det jeg ønske nu er blot at opyse hvor mange fornavne der der begynder
> med 'A', hvor mange der begynder med 'B' osv., og så gå videre til de
> enkelte begyndelsesbogtaver derfra.
>
> Altså:
> $sql = "SELECT count(*) from $tabel[ind] where firstname like 'a%'";
> $sql = "SELECT count(*) from $tabel[ind] where firstname like 'b%'";
> $sql = "SELECT count(*) from $tabel[ind] where firstname like 'c%'";
> osv. osv.
>
> Men det må da kunne gøres på en smartere måde.?
Kan den her bruges ?
SELECT LEFT(firstname,1) AS firstletter,count(*) AS firstlettercount FROM
nametable GROUP BY LEFT(firstname,1)
--
MVH Jeppe Uhd - NX http://nx.dk
Webhosting for nørder og andet godtfolk
| |
Arne Feldborg (02-04-2004)
| Kommentar Fra : Arne Feldborg |
Dato : 02-04-04 10:49 |
|
"Jeppe Uhd" <inewsnospam@nx.dk> skrev Fri, 2 Apr 2004 11:25:07 +0200
>Kan den her bruges ?
>
>SELECT LEFT(firstname,1) AS firstletter,count(*) AS firstlettercount FROM
>nametable GROUP BY LEFT(firstname,1)
>
Jeps. Der virker aldeles udmærket, og (ihvertfald med de datatmængder
der pt. er tale om) også ganske hurtigt.
Mange tak for hjælpen, det var lige det jeg manglede.
P.S.
Jeg funderer over om hastigheden overhovedet vil aftage med stigende
datamængder - idet der jo aldrig vil kunne forekomme mere end 28
forbogsatver.?
--
mvh, A:\Feldborg
Folketællinger Hammerum og Bølling herreder, kirkebøger Hammerum herred
http://www.haunstrup.dk/feldborg/genealogi/download/
| |
Troels Arvin (02-04-2004)
| Kommentar Fra : Troels Arvin |
Dato : 02-04-04 10:55 |
|
On Fri, 02 Apr 2004 11:49:13 +0200, Arne Feldborg wrote:
> Jeg funderer over om hastigheden overhovedet vil aftage med stigende
> datamængder - idet der jo aldrig vil kunne forekomme mere end 28
> forbogsatver.?
Databasesystemet skal dog stadig løbe rækkerne igennem for at læse
fornavne, for igen at kunne tælle forbogstaver. - Men hvis du har et
indeks på "firstname", skal der uhyre store mængder data til, før det
bliver mærkbart langsommere.
--
Greetings from Troels Arvin, Copenhagen, Denmark
| |
Jeppe Uhd (02-04-2004)
| Kommentar Fra : Jeppe Uhd |
Dato : 02-04-04 12:07 |
|
Troels Arvin wrote:
> On Fri, 02 Apr 2004 11:49:13 +0200, Arne Feldborg wrote:
>
>> Jeg funderer over om hastigheden overhovedet vil aftage med stigende
>> datamængder - idet der jo aldrig vil kunne forekomme mere end 28
>> forbogsatver.?
>
> Databasesystemet skal dog stadig løbe rækkerne igennem for at læse
> fornavne, for igen at kunne tælle forbogstaver. - Men hvis du har et
> indeks på "firstname", skal der uhyre store mængder data til, før det
> bliver mærkbart langsommere.
Evt et index på firstname der kun tager en del af feltet med (eller er det
kun ved text typer man kan det?)
--
MVH Jeppe Uhd - NX http://nx.dk
Webhosting for nørder og andet godtfolk
| |
Troels Arvin (02-04-2004)
| Kommentar Fra : Troels Arvin |
Dato : 02-04-04 12:19 |
|
On Fri, 02 Apr 2004 13:06:40 +0200, Jeppe Uhd wrote:
> Evt et index på firstname der kun tager en del af feltet med (eller er
> det kun ved text typer man kan det?)
Det ville overraske mig, hvis man kan i MySQL, men man kan fx. i
PostgreSQL:
http://www.postgresql.org/docs/7.4/static/indexes-expressional.html
--
Greetings from Troels Arvin, Copenhagen, Denmark
| |
Jeppe Uhd (02-04-2004)
| Kommentar Fra : Jeppe Uhd |
Dato : 02-04-04 12:29 |
|
Troels Arvin wrote:
> On Fri, 02 Apr 2004 13:06:40 +0200, Jeppe Uhd wrote:
>
>> Evt et index på firstname der kun tager en del af feltet med (eller
>> er det kun ved text typer man kan det?)
>
> Det ville overraske mig, hvis man kan i MySQL, men man kan fx. i
> PostgreSQL:
> http://www.postgresql.org/docs/7.4/static/indexes-expressional.html
Jeg checkede lige, MySQL 4.0.17 kan i hvert fald...
ALTER TABLE `tablename` ADD INDEX `indexname` ( `columnname` ( 1 ) );
--
MVH Jeppe Uhd - NX http://nx.dk
Webhosting for nørder og andet godtfolk
| |
Peter Brodersen (02-04-2004)
| Kommentar Fra : Peter Brodersen |
Dato : 02-04-04 23:38 |
|
On Fri, 02 Apr 2004 11:54:54 +0200, Troels Arvin <troels@arvin.dk>
wrote:
>Databasesystemet skal dog stadig løbe rækkerne igennem for at læse
>fornavne, for igen at kunne tælle forbogstaver. - Men hvis du har et
>indeks på "firstname", skal der uhyre store mængder data til, før det
>bliver mærkbart langsommere.
Men idet et feltnavn ikke står alene, men er en del af en funktion (fx
LEFT(fornavn, 1) ), så bliver indekset ikke brugt i MySQL.
Endnu et par eksempler:
Index bliver ikke brugt:
SELECT fornavn FROM tabel WHERE LEFT(fornavn,1) = 'A';
Index bliver brugt:
SELECT fornavn FROM tabel WHERE fornavn LIKE 'A%';
--
- Peter Brodersen
Ugens sprogtip: smide (og ikke smidde)
| |
Stig Johansen (03-04-2004)
| Kommentar Fra : Stig Johansen |
Dato : 03-04-04 07:32 |
|
Peter Brodersen wrote:
> Men idet et feltnavn ikke står alene, men er en del af en funktion (fx
> LEFT(fornavn, 1) ), så bliver indekset ikke brugt i MySQL.
Ditto for MSSQL.
--
Med venlig hilsen
Stig Johansen
| |
Troels Arvin (04-04-2004)
| Kommentar Fra : Troels Arvin |
Dato : 04-04-04 21:10 |
|
On Sat, 03 Apr 2004 00:38:14 +0200, Peter Brodersen wrote:
> idet et feltnavn ikke står alene, men er en del af en funktion (fx
> LEFT(fornavn, 1) ), så bliver indekset ikke brugt i MySQL.
Du har ret i, at man normalt skal passe på med funktioner, hvis man gerne
vil have sit index brugt.
[...]
> Index bliver ikke brugt:
> SELECT fornavn FROM tabel WHERE LEFT(fornavn,1) = 'A';
>
> Index bliver brugt:
> SELECT fornavn FROM tabel WHERE fornavn LIKE 'A%';
I min MySQL 4.0.18 bruger MySQL mod forventning faktisk index i begge
tilfælde.
--
Greetings from Troels Arvin, Copenhagen, Denmark
| |
Peter Brodersen (04-04-2004)
| Kommentar Fra : Peter Brodersen |
Dato : 04-04-04 22:02 |
|
On Sun, 04 Apr 2004 22:09:33 +0200, Troels Arvin <troels@arvin.dk>
wrote:
>> Index bliver ikke brugt:
>> SELECT fornavn FROM tabel WHERE LEFT(fornavn,1) = 'A';
>>
>> Index bliver brugt:
>> SELECT fornavn FROM tabel WHERE fornavn LIKE 'A%';
>
>I min MySQL 4.0.18 bruger MySQL mod forventning faktisk index i begge
>tilfælde.
Du tror ikke, at indexet kun bliver brugt til at trække dataen ud fra,
fordi din SELECT kun indeholder felter, der indgår i det index (som
alternativ for at den bliver nødt til at slå op i selve datafilen)?
"Using index" under Extra betyder bare, at den bruger indexet til at
trække dataen ud fra - ikke til at begrænse dataen.
1:
EXPLAIN SELECT firstname FROM aut WHERE LEFT(firstname,1) = "P";
+-------+-------+---------------+-----------+---------+------+------+--------------------------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+-------+-------+---------------+-----------+---------+------+------+--------------------------+
| aut | index | NULL | firstname | 200 | NULL | 1012 | Using where; Using index |
+-------+-------+---------------+-----------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
2:
EXPLAIN SELECT id, firstname FROM aut WHERE LEFT(firstname,1) = "P";
+-------+------+---------------+------+---------+------+------+-------------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+-------+------+---------------+------+---------+------+------+-------------+
| aut | ALL | NULL | NULL | NULL | NULL | 1012 | Using where |
+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
I eksempel 1 nøjes den med at kigge i indexet for at finde data. Men
den skal stadigvæk alle 1012 rækker igennem i det index. Den optimerer
dog en smule ved ikke at skulle kigge i datafilen.
I eksempel 2 kigger den i datafilen. Også her skal den kigge 1012
rækker igennem.
Men:
3:
EXPLAIN SELECT firstname FROM aut WHERE firstname LIKE "P%";
+-------+-------+---------------+-----------+---------+------+------+--------------------------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+-------+-------+---------------+-----------+---------+------+------+--------------------------+
| aut | range | firstname | firstname | 100 | NULL | 46 | Using where; Using index |
+-------+-------+---------------+-----------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
4:
EXPLAIN SELECT id, firstname FROM aut WHERE firstname LIKE "P%";
+-------+-------+---------------+-----------+---------+------+------+-------------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+-------+-------+---------------+-----------+---------+------+------+-------------+
| aut | range | firstname | firstname | 100 | NULL | 46 | Using where |
+-------+-------+---------------+-----------+---------+------+------+-------------+
1 row in set (0.00 sec)
I eksempel 3 gør den både brug af indexet i forbindelse med hvor
omfattende, opslaget er (range-opslag, kun 46 rækker skal der kigges
på), og dataen stammer tillige blot fra indexet.
I eksempel 4 skal den godt nok ud og kigge i datafilen, men indexet
har gjort, at den kun skal kigge de 46 rækker igennem.
(testet på MySQL 4.0.18)
--
- Peter Brodersen
Ugens sprogtip: smide (og ikke smidde)
| |
Troels Arvin (04-04-2004)
| Kommentar Fra : Troels Arvin |
Dato : 04-04-04 22:52 |
|
On Sun, 04 Apr 2004 23:02:15 +0200, Peter Brodersen wrote:
>>I min MySQL 4.0.18 bruger MySQL mod forventning faktisk index i begge
>>tilfælde.
>
> Du tror ikke, at indexet kun bliver brugt til at trække dataen ud fra
Tak; du har ret.
--
Greetings from Troels Arvin, Copenhagen, Denmark
| |
René Lønstrup (02-04-2004)
| Kommentar Fra : René Lønstrup |
Dato : 02-04-04 18:50 |
|
Jeppe Uhd wrote:
> Kan den her bruges ?
>
> SELECT LEFT(firstname,1) AS firstletter,count(*) AS firstlettercount
> FROM nametable GROUP BY LEFT(firstname,1)
Det skulle vel ikke være muligt at lave noget smart alá ovenstående, hvor
alle tegn der /ikke/ hører under alfabetet (i mit konkrete tilfælde typisk
tal) sorteres og optælles samlet under sit eget tegn (eks. '#')?
Bruger MySQL 4.0.18 hvis det har noget at sige..
--
Mvh René Lønstrup
min web: http://www.rel7star.dk?r=usenet
min email: se om du kan regne dén ud..
| |
Jeppe Uhd (02-04-2004)
| Kommentar Fra : Jeppe Uhd |
Dato : 02-04-04 21:45 |
|
René Lønstrup wrote:
> Jeppe Uhd wrote:
>> Kan den her bruges ?
>>
>> SELECT LEFT(firstname,1) AS firstletter,count(*) AS firstlettercount
>> FROM nametable GROUP BY LEFT(firstname,1)
>
> Det skulle vel ikke være muligt at lave noget smart alá ovenstående,
> hvor alle tegn der /ikke/ hører under alfabetet (i mit konkrete
> tilfælde typisk tal) sorteres og optælles samlet under sit eget tegn
> (eks. '#')?
>
> Bruger MySQL 4.0.18 hvis det har noget at sige..
Jo da...
SELECT IF((96<(ASCII(LOWER(LEFT(name,1))))) &&
((ASCII(LOWER(LEFT(name,1)))<123)),LOWER(LEFT(name,1)),'#') AS n,count(*) AS
nn FROM mytable GROUP BY n;
Hvis der er nogen der har lyst til at optimere skal de være velkomne
--
MVH Jeppe Uhd - NX http://nx.dk
Webhosting for nørder og andet godtfolk
| |
Arne Feldborg (03-04-2004)
| Kommentar Fra : Arne Feldborg |
Dato : 03-04-04 22:43 |
|
"Jeppe Uhd" <inewsnospam@nx.dk> skrev Fri, 2 Apr 2004 11:25:07 +0200
>> Det jeg ønske nu er blot at opyse hvor mange fornavne der der begynder
>> med 'A', hvor mange der begynder med 'B' osv., og så gå videre til de
>> enkelte begyndelsesbogtaver derfra.
>>
>> Altså:
>> $sql = "SELECT count(*) from $tabel[ind] where firstname like 'a%'";
>> $sql = "SELECT count(*) from $tabel[ind] where firstname like 'b%'";
>> $sql = "SELECT count(*) from $tabel[ind] where firstname like 'c%'";
>> osv. osv.
>>
>> Men det må da kunne gøres på en smartere måde.?
>
>Kan den her bruges ?
>
>SELECT LEFT(firstname,1) AS firstletter,count(*) AS firstlettercount FROM
>nametable GROUP BY LEFT(firstname,1)
>
Jeg takker for såvel dette forslag som for de efterfølgende kommentarer.
Men et nyt problem er dukket op. Er det muligt at lave noget tilsvarende
på det første hele ord i fornavnet.?
Altså Aase, Aase Astrid, Aase Birthe, Aase Elinor og Aase Elisabeth skal
tælles som Aase og give resultatet 5.
Alice Feldborg, Alice Hougaard, Alice Kirstine og Alice Vejen skal
tælles som Alice og give resultatet 4.
Jeg har søgt i manualen, men kan ikke finde noget der ligner en word()
funktion, men den må jo dog være der et sted.?
--
mvh, A:\Feldborg
Folketællinger Hammerum og Bølling herreder, kirkebøger Hammerum herred
http://www.haunstrup.dk/feldborg/genealogi/download/
| |
Morten Wulff (04-04-2004)
| Kommentar Fra : Morten Wulff |
Dato : 04-04-04 10:45 |
|
On Sat, 03 Apr 2004 23:42:44 +0200, Arne Feldborg <feldborg@haunstrup.dk>
wrote:
> Men et nyt problem er dukket op. Er det muligt at lave noget tilsvarende
> på det første hele ord i fornavnet.?
Ja. Følgende giver så vidt jeg kan se det ønskede resultat:
mysql> SELECT * FROM names;
+----------------+
| firstname |
+----------------+
| aase |
| aase astrid |
| aase birthe |
| aase elinor |
| aase elisabeth |
| alice feldborg |
| alice hougaard |
| alice kirstine |
| alice vejen |
+----------------+
9 rows in set (0.00 sec)
mysql> SELECT LEFT(firstname, CASE WHEN LOCATE(' ', firstname) THEN
LOCATE(' ',
firstname) ELSE LENGTH(firstname) END) AS first, COUNT(*) AS count FROM
names GR
OUP BY first;
+-------+-------+
| first | count |
+-------+-------+
| aase | 5 |
| alice | 4 |
+-------+-------+
2 rows in set (0.00 sec)
> Jeg har søgt i manualen, men kan ikke finde noget der ligner en word()
> funktion, men den må jo dog være der et sted.?
Som du kan se, har jeg holdt fast i LEFT funktionen som den forrige poster
brgute i sit eksempel. Jeg bruger LOCATE til at finde det første mellemrum
i navnet og bruger det som position i LEFT funktionen.
Med venlig hilsen / Kind regards,
Morten Wulff
--
Self Injury Information and Support: www.psyke.org
"I have a school book with my name on it."
"Your parents must be so proud." ( http://www.actsofgord.com/)
| |
|
|