Avatar billede hcthorsen Praktikant
23. september 2009 - 11:24 Der er 19 kommentarer og
1 løsning

Hjælp til søgning

Jeg skal bruge et udtræk, hvor jeg opgør hvor mange personer der findes i min database mellem 0-2 år, 2-5 år, 5-15 år, 15-70 år og over 70 år. Jeg kan godt finde ud af at gøre det ved hjælp af flere søgninger, men kan det ikke gøres lidt mere raffineret? Udgangspunktet er følgende:

$sql = mysqli_query ($conn, "SELECT alder, COUNT(alder) AS antal FROM db WHERE user = '$_SESSION[user]' AND alder !='' GROUP BY alder");
Avatar billede elkoger Nybegynder
23. september 2009 - 12:14 #1
SELECT alder, COUNT( alder ) AS antal, alder > 70 as over
FROM db
WHERE alder != ''
GROUP BY alder;

alder     antal     over
20     2     0
25     1     0
5     1     0
71     1     1
99     4     1


noget i den du'r vi er ude i?
Avatar billede hcthorsen Praktikant
23. september 2009 - 13:34 #2
Jeg beklager, men jeg forstår ikke helt dit svar. Jeg vil gerne have talt sammen hvor mange der opfylder:

0<alder<=2
2<alder<=5
5<alder<=15
15<alder<=70
70<alder
Avatar billede hcthorsen Praktikant
23. september 2009 - 13:46 #3
OK, nu forstår jeg dit svar. Tjah, det var ikke helt sådan jeg mente. Som nævnt i kommentar #2 skal jeg have talt op hvor mange der er i de 5 grupper

0<alder<=2
2<alder<=5
5<alder<=15
15<alder<=70
70<alder

Jeg kan godt finde ud af at gøre det i flere tempi, men kan det gøres i en søgning? Resultatet kunne være

gruppe antal
1        5
2        10
3        13
4        4
5        17
Avatar billede hcthorsen Praktikant
23. september 2009 - 22:56 #4
Nå, jeg smider selv et svar. Nu har jeg taget lidt flere aldersklasser med. Det er ikke kønt, men det virker (sjovt, det siger min kone også):


$sql = mysqli_query ($conn,"
(SELECT COUNT(*) AS antal, '-2' AS leg FROM db WHERE alder <= 2 AND user = '$_SESSION[user]' AND alder !='' ) UNION
(SELECT COUNT(*) AS antal, '3-5' AS leg FROM db WHERE alder > 2 AND alder <= 5 AND user = '$_SESSION[user]') UNION
(SELECT COUNT(*) AS antal, '6-10' AS leg FROM db WHERE alder > 5 AND alder <= 10 AND user = '$_SESSION[user]') UNION
(SELECT COUNT(*) AS antal, '11-15' AS leg FROM db WHERE alder > 10 AND alder <= 15 AND user = '$_SESSION[user]') UNION
(SELECT COUNT(*) AS antal, '16-20' AS leg FROM db WHERE alder > 15 AND alder <= 20 AND user = '$_SESSION[user]') UNION
(SELECT COUNT(*) AS antal, '21-30' AS leg FROM db WHERE alder > 20 AND alder <= 30 AND user = '$_SESSION[user]') UNION
(SELECT COUNT(*) AS antal, '31-40' AS leg FROM db WHERE alder > 30 AND alder <= 40 AND user = '$_SESSION[user]') UNION
(SELECT COUNT(*) AS antal, '41-50' AS leg FROM db WHERE alder > 40 AND alder <= 50 AND user = '$_SESSION[user]') UNION
(SELECT COUNT(*) AS antal, '51-60' AS leg FROM db WHERE alder > 50 AND alder <= 60 AND user = '$_SESSION[user]') UNION
(SELECT COUNT(*) AS antal, '61-70' AS leg FROM db WHERE alder > 60 AND alder <= 70 AND user = '$_SESSION[user]') UNION
(SELECT COUNT(*) AS antal, '71-80' AS leg FROM db WHERE alder > 70 AND alder <= 80 AND user = '$_SESSION[user]') UNION
(SELECT COUNT(*) AS antal, '81-90' AS leg FROM db WHERE alder > 80 AND alder <= 90 AND user = '$_SESSION[user]') UNION
(SELECT COUNT(*) AS antal, '91-100' AS leg FROM db WHERE alder > 90 AND alder <= 100 AND user = '$_SESSION[user]') UNION
(SELECT COUNT(*) AS antal, '101-' AS leg FROM db WHERE alder > 100 AND user = '$_SESSION[user]')
");
Avatar billede arne_v Ekspert
24. september 2009 - 04:28 #5
Lav en support tabel med grupperne.

Demo:

mysql> CREATE TABLE person (
    ->    personname VARCHAR(30) NOT NULL,
    ->    age INTEGER,
    ->    PRIMARY KEY(personname)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql>
mysql> CREATE TABLE agegroup (
    ->    low INTEGER NOT NULL,
    ->    high INTEGER NOT NULL,
    ->    PRIMARY KEY(low,high)
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> INSERT INTO person VALUES('Anders Andersen', 17);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO person VALUES('Borge Borgesen', 23);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO person VALUES('Christian Christensen', 24);
Query OK, 1 row affected (0.00 sec)

mysql>
mysql> INSERT INTO agegroup VALUES(0, 17);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO agegroup VALUES(18, 64);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO agegroup VALUES(65, 200);
Query OK, 1 row affected (0.00 sec)

mysql>
mysql> SELECT * FROM person;
+-----------------------+------+
| personname            | age  |
+-----------------------+------+
| Anders Andersen      |  17 |
| Borge Borgesen        |  23 |
| Christian Christensen |  24 |
+-----------------------+------+
3 rows in set (0.00 sec)

mysql>
mysql> SELECT CONCAT(CAST(agegroup.low AS CHAR),'-',CAST(agegroup.high AS CHAR))
,COUNT(person.age) AS n
    -> FROM person RIGHT JOIN agegroup ON agegroup.low <= person.age AND person.
age <= agegroup.high
    -> GROUP BY CONCAT(CAST(agegroup.low AS CHAR),'-',CAST(agegroup.high AS CHAR
));
+--------------------------------------------------------------------+---+
| CONCAT(CAST(agegroup.low AS CHAR),'-',CAST(agegroup.high AS CHAR)) | n |
+--------------------------------------------------------------------+---+
| 0-17                                                              | 1 |
| 18-64                                                              | 2 |
| 65-200                                                            | 0 |
+--------------------------------------------------------------------+---+
3 rows in set (0.00 sec)

mysql>
mysql> DROP TABLE agegroup;
Query OK, 0 rows affected (0.00 sec)

mysql> DROP TABLE person;
Query OK, 0 rows affected (0.00 sec)
Avatar billede hcthorsen Praktikant
24. september 2009 - 08:50 #6
Det kan jeg bruge. Har søgt inspiration i din guide. Skal du ikke lave en ny med CAST og CONCAT?

Du kan finde points på

http://www.eksperten.dk/spm/887489

Tak for hjælpen.
Avatar billede hcthorsen Praktikant
24. september 2009 - 09:31 #7
På mine data bliver resultatet

CONCAT( CAST( agegroup.low AS CHAR ) ,
'-' , CAST( agegroup.high AS CHAR ) )  n 

0-2                    8
101-200                0
16-20                  8
21-30                  6
3-5                    4
31-40                  9
41-50                  10
51-60                  8
6-15                    6
61-70                  18
71-80                  9
81-90                  3
91-100                  2

Hvordan får jeg gruppen 101-200 år "ned på plads"?
Avatar billede hcthorsen Praktikant
24. september 2009 - 13:57 #8
Hej arne_v!

Jeg skal også lige høre hvordan jeg sætter

WHERE user = '$_SESSION[user]'

ind i søgningen. Det hele skal indgå i et større script hvor jeg via nogle select-bokse vælger subgrupper af mine data. Indtil nu har jeg lavet det via if-sætninger i andre if-sætninger:

if($_GET['a']=='Alle'){
  if($_GET['b']=='Alle'){
      $sql = mysqli_query ($conn, "bla");
  }
  else{
      $sql = mysqli_query ($conn, "bla bla");
  }
}
else{
  if($_GET['b']=='Alle'){
      $sql = mysqli_query ($conn, "bla bla bla");
  }
  else{
      $sql = mysqli_query ($conn, "bla bla bla bla");
  }
}

Det er jo ret kluntet, men det fungerer. Imidlertid skal der indgå flere select-bokse, så det ender med at blive et omfattende script.

Har du en ide til hvordan det kan gøres? Jeg efterlyser ikke en færdig løsning, bare et par ord som inspiration.
Avatar billede arne_v Ekspert
24. september 2009 - 15:14 #9
... ORDER BY agegroup.low

maa kunne fixe sorteringen
Avatar billede arne_v Ekspert
24. september 2009 - 15:18 #10
Der er to muligheder:

1)  appende WHERE betingelser til din SQL streng (saa laenge du ikke appender user provided data er du ikke aaben for SQL injection)

2)  bruger tricket

... WHERE felt=ISNULL(?,felt)

og saa saette parameteren til SQL NULL hvis testet ikke skal bruges.
Avatar billede hcthorsen Praktikant
25. september 2009 - 10:41 #11
Det virker med ORDER BY agegroup.low - det synes jeg at jeg havde prøvet før jeg stillede spørgsmålet, men det havde jeg åbenbart ikke. Jeg kan imidlertid ikke finde ud af at sætte WHERE ind i strengen uden at få fejl. Skal man ikke bare gøre noget ala

SELECT CONCAT(CAST(agegroup.low AS CHAR),'-',CAST(agegroup.high AS CHAR)),COUNT(person.age) AS n FROM person RIGHT JOIN agegroup ON agegroup.low <= person.age AND person.age <= agegroup.high
GROUP BY CONCAT(CAST(agegroup.low AS CHAR),'-',CAST agegroup.high AS CHAR)) WHERE user = '$_SESSION[user]' ORDER BY agegroup.low;
Avatar billede hcthorsen Praktikant
25. september 2009 - 10:52 #12
Glem det. Nu har jeg drukket en kop kaffe og forstået din søgning og indset at min WHERE skal sættes ind lidt tidligere:

SELECT CONCAT(CAST(agegroup.low AS CHAR),'-',CAST(agegroup.high AS CHAR)),COUNT(person.age) AS n FROM person RIGHT JOIN agegroup ON agegroup.low <= person.age AND person.age <= agegroup.high WHERE user = '$_SESSION[user]' GROUP BY CONCAT(CAST(agegroup.low AS CHAR),'-',CAST agegroup.high AS CHAR)) ORDER BY agegroup.low;

Det ender jo med at jeg lærer det her:-)
Avatar billede hcthorsen Praktikant
25. september 2009 - 12:39 #13
Nå, træerne vokser ikke ind i himlen. Jeg synes ikke lige jeg kan få det der med

WHERE felt=ISNULL(?,felt)

til at virke.  Jeg kan se at du har svaret på det samme flere gange tidligere. Jeg har som andre før mig brug for at udelade WHERE forbeholdet når felt="NULL". Har konsulteret mySQL-manualen uden held.
Avatar billede arne_v Ekspert
25. september 2009 - 14:53 #14
Tricket er at:

WHERE felt=ISNULL(NULL,felt)

altid er sand mens at:

WHERE felt=ISNULL(77,felt)

kun er sand hvis felt er 77.

Saa spoergsmaals tegnet skal erstattes af enten en vaerdi eller af NULL afhaengig af om testet skal bruges.

Jeg brugte spoergsmaals tegnet for at antyde brug af prepared statement.
Avatar billede hcthorsen Praktikant
26. september 2009 - 10:19 #15
Det er jeg med på, men jeg kan ikke få det til at fungere i praksis. Jeg er ikke nået til at bruge prepared statements, så jeg undlader at bruge "?". Jeg har prøvet med følgende

SELECT CONCAT( CAST( agegroup.low AS CHAR ) , '-', CAST( agegroup.high AS CHAR ) ) , COUNT( erfaring_anaestesier.alder ) AS antal FROM erfaring_anaestesier RIGHT JOIN agegroup ON agegroup.low <= erfaring_anaestesier.alder
AND erfaring_anaestesier.alder <= agegroup.high
WHERE asa = ISNULL('$_GET[asa]',asa)
GROUP BY CONCAT( CAST( agegroup.low AS CHAR ) , '-', CAST( agegroup.high AS CHAR ) )
ORDER BY agegroup.low

Det virker ikke. Kommer med følgende fejl:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'asa) GROUP BY CONCAT(CAST(agegroup.low AS CHAR),'-',CA' at line 3
Avatar billede arne_v Ekspert
26. september 2009 - 22:19 #16
Prøv med noget a la:

if(isset($_GET[asa])) {
  $asa = mysql_real_escape_string($_GET[asa]);
} else {
  $asa = 'NULL';
}
$sqlstr = "... WHERE asa = IFNULL($asa, asa) ...";
Avatar billede hcthorsen Praktikant
28. september 2009 - 09:12 #17
Det virker delvist. Jeg har et problem med citationstegn som jeg ikke kan få løst. Nedenstående virker hvis jeg har valgt noget:
i min select-box:

if(isset($_GET[asa])) {
  $asa = "'".mysql_real_escape_string($_GET[asa])."'";
}
else {
  $asa= 'NULL';
}


Der bliver også korrekt set bort fra WHERE clausen hvis jeg skifter det hele ud med

$asa= 'NULL';

Imidlertid virker det ikke når NULL kommer fra min $_GET[asa]. Problemet er at der så er '' omkring, og det virker ikke i søgestrengen.

WHERE asa = IFNULL(NULL,asa)      <-- VIRKER

WHERE asa = IFNULL('NULL',asa)    <-- VIRKER IKKE


Jeg ved ikke lige hvordan jeg kommer af med de ''.
Avatar billede hcthorsen Praktikant
28. september 2009 - 09:47 #18
Det virker på denne måde:

if(isset($_GET[asa])) {
  if($_GET[asa]== 'NULL'){
    $asa= 'NULL';
  }
  else{
    $asa= "'".mysql_real_escape_string($_GET[asa])."'";
  }
}
else {
  $asa= 'NULL';
}

men nu er jeg igen endt op med en noget kluntet kode:-)
Avatar billede hcthorsen Praktikant
28. september 2009 - 12:01 #19
Det kan selvfølgelig lige så godt erstattes af

if($_GET[asa]== 'NULL' OR $_GET[asa]== ''){
  $asa= 'NULL';
}
else{
  $asa= "'".mysql_real_escape_string($_GET[asa])."'";
}

Jeg ved ikke hvorfor isset ikke fungerer efter hensigten.
Avatar billede arne_v Ekspert
28. september 2009 - 18:01 #20
Hvis der i en form eksplicit angives NULL vil jeg da mene at det er OK at fortolke det som 'NULL' og dermed ikke finde nogle matches.

NULL betyder ikke-udfyldt. Udfyldt med ikke-udfyldt virker selvmodsigende paa mig.

Men det er din app, saa du ved hvordan den skal fungere.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester