/ Forside / Teknologi / Udvikling / SQL / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
SQL
#NavnPoint
pmbruun 1704
niller 962
fehaar 730
Interkril.. 701
ellebye 510
pawel 510
rpje 405
pete 350
gibson 320
10  smorch 260
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/)

Søg
Reklame
Statistik
Spørgsmål : 177558
Tips : 31968
Nyheder : 719565
Indlæg : 6408925
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste