1. Dec 04

    I dag har jeg tenkt å gå litt på det banale, men som jeg ser mange er usikre på. Det er rett og slett kopiert direkte fra manualen til MySQL, men det er ikke sikkert alle som finner den eller er klare over det.

    For enkelte er det kanskje ikke greit å vite hvilken INT-type man skal ha til tider. Er det TINYINT jeg vil ha? Eler er det kanskje SMALLINT? Hvor går grensen, hvor store verdier?

    I manuelen finner vi denne tabellen, som er en temmelig grei oversikt over hvor store verdier du kan ha på de forskjellige INT-typene

    Type Bytes Minimum Value Maximum Value
    (Signed/Unsigned) (Signed/Unsigned)
    TINYINT 1 -128 127
    0 255
    SMALLINT 2 -32768 32767
    0 65535
    MEDIUMINT 3 -8388608 8388607
    0 16777215
    INT 4 -2147483648 2147483647
    0 4294967295
    BIGINT 8 -9223372036854775808 9223372036854775807
    0 18446744073709551615

    Dette gir en pekepinne på hvilken type man skal bruke på de forskjellige feltene når du lager en tabell. Det er ikke alt for mye optimalisering å hente på å sette feltene til lavest mulig, men som man sier: «Mange bekker små, gjør en stor å».

    \\ emneord: , , ,

  2. Dec 04

    For litt siden kom noen til meg over MSN og lurte på hvordan de kunne bruke GROUP_CONCAT() men bare implodere de 3 nyeste (høyest ID). Og dette ville han da gjøre uten noen loop som helst. Jeg sier til han at han burde bruke PHPs implode()-funksjon, men det ville han visst ikke. MySQL skal vel egentlig ikke brukes til å manipulere date, men heller til å håndtere/deligere/lagre innhold (data).

    Uansett tenkte jeg at løsningen måtte være å bruke en subquery, hvor man sjekket at id var i id-ene som ble plukket ut av subqueriet. Nyere versjoner støtter ikke å bruke IN/ALL/ANY/SOME til subqueries i WHERE-clause, så da er løsningen ganske selvsigende.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    SELECT
       GROUP_CONCAT(
          a.id
          ORDER BY a.id DESC
          SEPARATOR ', '
       ) as imploded_idfield
    FROM myField a
    INNER JOIN
       (
          SELECT id
          FROM myField
          ORDER BY id DESC
          -- [WHERE ... ]
          LIMIT 3
       ) b
    ON a.id = b.id

    Da har vi alle de imploderte verdiene i imploded_idfield, og kan se ut noe som

    “300, 299, 298″

    \\ emneord: , ,

  3. Dec 04

    I sammenhengen med en DVD-liste jeg lagde en gang i tiden, la jeg til noe statistikk for moro skyld. Der fant jeg ut at jeg ville finne ut hvilken sjanger jeg ser mest av, og eier mest av. Derfor måtte jeg finne den verdien som forekommer oftest i et felt.

    Jeg tenkte det kunne være litt kjekt å fått denne servert i fanget, da den kan komme til nyttighet for noen senere. Dette er nesten samme som da jeg skulle finne motsatte av destinkte verdier.

    Så den jeg lagde, ble noe slik som den her:

    1
    2
    3
    4
    5
    6
    
    SELECT 
       COUNT( id ) AS quantity, field_name
    FROM table
    GROUP BY field_name
    ORDER BY quantity DESC
    LIMIT 1

    Så her er FIELD feltet som du teller opp i, og id er unike id til tabellen. Her vil du få noe resultat som dette:

    quantity  - field
    1233      - value

    Håper dere finner den nyttig.

    PS/Tips: Om dere vil ha full statistikk over forskjellige verdier og hvor mange det forekommer av de. Kan være kjekt for statistikk-applikasjoner for å telle forskjellige besøk av forskjellige IP-adresser.

    \\ emneord: , ,

  4. Dec 04

    Satt å vridde hodet litt på denne oppgaven fra NWF i dag. Der målet var å printe alle brukernavn med lik IP adresse i en tabell i MySQL. Trodde jeg hadde full orden på det når jeg skrev denne spørringen:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    SELECT user
    FROM users
    WHERE ip
       IN (
            SELECT ip
            FROM users
            GROUP BY ip
            HAVING COUNT(ip) > 1
           )
    ORDER BY user

    Den spørringen der skulle etter all min logiske sans fungere ypperlig. Noe som den egentlig gjør. Det hadde jeg funnet ut, om jeg ikke tabbet meg fullstendig ut på PHP fronten.

    Vell, tenkte jeg skulle dele dette med dere. Om dere kommer over samme oppgave. Slik er det altså dere finner motsatte av distinct i MySQL.

    Er det av ønske å komplisere spørringen litt, så fant jeg også ut av denne, under prosessen:

    1
    2
    3
    4
    5
    6
    7
    8
    
    SELECT u.user
    FROM users u
       INNER JOIN (SELECT ip
                          FROM users
                          GROUP BY ip
                          HAVING COUNT(ip) > 1) d
       ON u.ip = d.ip
    ORDER BY user

    \\ emneord: , ,

  5. May 04

    Topp notis: FULLTEXT-metoden som er brukt i denne artikkelen støttes ikke av database-typen InnoDB, men MyISAM.

    Det er flere metoder du kan bruke når du skal søke i en MySQL database. De vanligste metodene er å bruke LIKE() eller MATCH(). Her vil jeg forklare en bruk av MATCH, og så vidt nevne LIKE/RLIKE. MATCH bruker vi i noe som kalles FULLTEXT search. Det betyr at du må ha en FULLTEXT-index i tabellen din.

    Dette kan du gjøre eks via CREATE eller ALTER. Når du lager en ny tabell kan du f.eks gjøre slik:

    CREATE TABLE table (
       news_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
       my_title VARCHAR(200),
       my_text TEXT,
       FULLTEXT (my_title, my_text)
    );

    FULLTEXT skal asignes til de feltene som du vil MATCH skal fungere på.

    Så hvordan søker vi?

    Si at jeg har mye innhold i tabellen ovenfor som handler om elefanter og blåbær.

    Så skal jeg plukke ut de artiklene som inneholder nettopp ordene “elefant” og “blåbær”. Da gjør jeg slik:

    SELECT id, my_title,
       MATCH(my_title, my_text)
       AGAINST('elefant blåbær') as relevance
    FROM table
      WHERE
         MATCH(my_title, my_text)
         AGAINST('elefant blåbær')
    ORDER BY relevance DESC

    Her rekner du ut rel som relevanse over hvor mye det stemmer, og vi sorterer etter mest relevante søk, fra størst til minst. Vi velger ut ID, tittel og relevanse.

    Det blir ingen videre utgreing av dette, det er selvforklarende.

    Kjapt om LIKE()

    Her kommer det også litt kjapt om hvordan du kan bruke LIKE. Her er det essensielt med wildcardet % for å matche mot resultat.

    Her er det korrekt med eksempelet ovenfor:

    SELECT id, my_title
    FROM table
    WHERE my_text LIKE ('%elefant%blåbær%')
    AND my_text RLIKE '[[:< :]]elefant[[:>:]].*[[:< :]]blåbær[[:>:]]'

    … Eventuelt utvide med å søke i my_title også!

    Redigert – 06.07.07 02:38:

    Ser jeg har mangel på forklaring av hva RLIKE gjør, som kan forvirre litt. RLIKE fungerer på samme måte som LIKE gjør, bare at det er med regulære uttrykk. På den måten får du mye større muligheter til hva du skal hente ut, og ikke bare benytte deg av wildcard.

    \\ emneord: , , , , , , ,