Kenttien lisääminen samaan hakuun MySQL:ssä

SQL

pitäisi joukkueen pistepörssihaku saada tehtyä.
on kaksi taulua (esim. p ja m)
p (kentät id, etunimi, sukunimi):

id|etunimi|sukunimi |
---------------------
1|erkki |esimerkki|
2|pekka |pelimies |


m (kentät aika, tekijä, syöttäjä)

aika|tekijä|syöttäjä|
---------------------
1.00| 1| 2|
2.23| 2| 1|
5.32| 1| 3|

pitäsi saada aikaiseksi haku, jossa on kentät

id|etunimi|sukunimi-|maalit|syötöt|
-----------------------------------
1| erkki|esimerkki| 2| 1|
2| pekka|pelimies | 1| 1|

Tällaisella haulla saan tehtyä hakutuloksen, jossa on muut yllä mainituista paitsi syötöt-sarake:

"SELECT p.id AS id, p.etunimi AS etunimi, p.sukunimi AS sukunimi, COUNT(*) AS maalit FROM p, m WHERE m.tekijä = p.id GROUP BY p.id"

mutta miten samaan hakuun saisi lisättyä muitakin sarakkeita countia käyttäen, esim. tässä tapauksessa tuon syötöt. Miten siis toisen sarakkeen voisi yhdistää tuohon siten, että count-funktion käytössä uudelleen rajaus olisikin "WHERE m.syöttäjä = p.id"

Ja nyt siis nimenomaan tarkoitus olisi saada tehtyä tuo yhdellä haulla enkä halua yhdistellä tietoja jälkeenpäin

14

1432

    Vastaukset

    Anonyymi (Kirjaudu / Rekisteröidy)
    5000
    • taulunimi

      en ole mysql:llä tehnyt paljon mitään.
      Mutta jotenkin tällä tapaa...
      select p.id, p.etunimi,p.sukunimi,
      count(em.*) as maalit, count (er.*) as syötöt
      from p, m as em, m as er
      where
      p.id = em.tekija
      and
      p.id = er.syottaja
      group by p.id;

      Huom! en tiedä toimiiko mutta aika lähellä kumminkin. Tarkista tulos jos syöttäjä tiedot puuttuvat, jos ei ole pakollinen tieto. left outer join ehkä mukaan tms.
      Jos et saa tehtyä nii tee näkymät joita vertailet keskenään.

      • Female

        Mikset mene rakennenäkymään, hae näitä kahta taulua sinne ja kaksoiklikkaa niitä tetueita sinne jotka haluat taulukkonäkymään?


    • I.Proqatlis

      Ei tässä tarvita group by –rakennetta ollenkaan.

      Pitää vain tietää, että selectissä voidaan käyttää alikyselyä tähän tapaan:

      select
      p.id,
      p.etunimi,
      p.sukunimi,
      (select count(*) from maalit m where p.id = m.tekija) as tehdyt,
      (select count(*) from maalit m where p.id = m.syottaja) as syötetyt
      from
      pelaajat p;

      Tämä antaa sinulle vastauksen kysymykseesi ! Yksinkertaista :-)

      • SQL

        Tuohan kuulostaa jo todella helpolta.

        Ei ainakaan suoraan näin toiminut, eikä myöskään näin (lisätty AS -sanat):

        select
        p.id,
        p.etunimi,
        p.sukunimi,
        (select count(*) from maalit AS m where p.id = m.tekija) as tehdyt,
        (select count(*) from maalit AS m where p.id = m.syottaja) as syötetyt
        from
        pelaajat AS p


        Virheeksi tulee molemmilla seuraava:

        #1064 - 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 'select count(*) from maalit m where p.id = m.tekija) as tehdy


      • I.Proqatlis
        SQL kirjoitti:

        Tuohan kuulostaa jo todella helpolta.

        Ei ainakaan suoraan näin toiminut, eikä myöskään näin (lisätty AS -sanat):

        select
        p.id,
        p.etunimi,
        p.sukunimi,
        (select count(*) from maalit AS m where p.id = m.tekija) as tehdyt,
        (select count(*) from maalit AS m where p.id = m.syottaja) as syötetyt
        from
        pelaajat AS p


        Virheeksi tulee molemmilla seuraava:

        #1064 - 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 'select count(*) from maalit m where p.id = m.tekija) as tehdy

        Hmm. Olen kyllä aivan varma, että tuo kysely toimii MySQL 5.0-versiossa. Minä nimittäin loin kuvaamasi taulut tietokantaan sekä hieman testiaineistoa, ja tulos oli erinomainen.

        Nytkin jos copypastean viestistäni tuon SQL-operaation MySQL Query Browserin kyselyikkunaan, niin se toimii edelleenkin.

        Minulla on myös Aqua Data Studio -käyttöliittymä, ja tätäkin kautta annettuna kysely toimii.

        Saamasi virheilmoitus viittaa siihen, että sinulla käytössä oleva MySQL-versio ei tajua tällaisia alikyselyitä. Itselläni ei ole vanhempia versioita, mutta olen lukenut, että niistä puuttuu koko joukko ominaisuuksia, jotka ovat uusimmassa.

        Tarkista, mikä MySQL-versio sinulla on käytössä ja jos mahdollista, niin päivitä uudempaan.


      • ------
        SQL kirjoitti:

        Tuohan kuulostaa jo todella helpolta.

        Ei ainakaan suoraan näin toiminut, eikä myöskään näin (lisätty AS -sanat):

        select
        p.id,
        p.etunimi,
        p.sukunimi,
        (select count(*) from maalit AS m where p.id = m.tekija) as tehdyt,
        (select count(*) from maalit AS m where p.id = m.syottaja) as syötetyt
        from
        pelaajat AS p


        Virheeksi tulee molemmilla seuraava:

        #1064 - 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 'select count(*) from maalit m where p.id = m.tekija) as tehdy

        Mikäs MySQL?
        MySQL 5 tukee vasta alikyselyitä, joten MySQL 4.x tuo ei toimine ja taitaa ilmaista asian juuri tuommosella virheilmoituksella. Toki tuon saa toimimaan myös MySQL 4 kunhan vain hajottaa alikyselyt, mut silloin joudut tekemään muutaman kyselyn ja yhdistää tiedot.

        AS ei ole pakollinen joskin sitä kannattaa käyttää selkeyttää, ja yleensä kaik tietokanta käskyt kirjoitetaan isolla näin ne erottaa helpost muista.


        Vaik tuo kysely kuulostaakin helpolta niin SELECT lauseessa olevat alikyselyt ovat aina raskaita ja niitä kannattaa välttää mahdollisuuksien mukaan.


      • ------
        I.Proqatlis kirjoitti:

        Hmm. Olen kyllä aivan varma, että tuo kysely toimii MySQL 5.0-versiossa. Minä nimittäin loin kuvaamasi taulut tietokantaan sekä hieman testiaineistoa, ja tulos oli erinomainen.

        Nytkin jos copypastean viestistäni tuon SQL-operaation MySQL Query Browserin kyselyikkunaan, niin se toimii edelleenkin.

        Minulla on myös Aqua Data Studio -käyttöliittymä, ja tätäkin kautta annettuna kysely toimii.

        Saamasi virheilmoitus viittaa siihen, että sinulla käytössä oleva MySQL-versio ei tajua tällaisia alikyselyitä. Itselläni ei ole vanhempia versioita, mutta olen lukenut, että niistä puuttuu koko joukko ominaisuuksia, jotka ovat uusimmassa.

        Tarkista, mikä MySQL-versio sinulla on käytössä ja jos mahdollista, niin päivitä uudempaan.

        Pyh olit nopeempa :(

        Juu MySQL 4.x puuttu vaik mitä ominaisuuksia kuten alikyselyt, triggerit jne... joiden puuttumisen takia joutu kikkailee vaik miten.

        Version saa selville SELECT VERSION(); kyselyllä.


      • SQL
        ------ kirjoitti:

        Pyh olit nopeempa :(

        Juu MySQL 4.x puuttu vaik mitä ominaisuuksia kuten alikyselyt, triggerit jne... joiden puuttumisen takia joutu kikkailee vaik miten.

        Version saa selville SELECT VERSION(); kyselyllä.

        Jeps. Kiitos kaikille avusta, versio on tosiaankin vain nelonen:

        4.0.27-standard-log

        Täytyypä alkaa pommittaa palveluntarjoajaa, jotta päivittäisi uudempaan...

        Ei kikkailu niin kiinnosta.


      • ------
        SQL kirjoitti:

        Jeps. Kiitos kaikille avusta, versio on tosiaankin vain nelonen:

        4.0.27-standard-log

        Täytyypä alkaa pommittaa palveluntarjoajaa, jotta päivittäisi uudempaan...

        Ei kikkailu niin kiinnosta.

        Leikitkös PHP5:den kanssa?
        Jos niin tällöin on mahollista käyttää SQLiteä, joka taitaa nuo alikyselytkin jne...

        Katsos http://fi.php.net/manual/en/ref.pdo.php ja http://fi.php.net/manual/en/ref.sqlite.php jos mahollista niin PDO kannattaa käyttää tällöin SQLite3 muutoin SQLite 2.84 muistaakseni. Mut molemmat taitaa nuo alikyselyt.

        Vilkaiseppas http://www.personal.fi/ jos ilmainen palveluntarjoaja kiinostaa, siel MySQL5 käytös.


    • I.Proqatlis

      ... systeemin arkkitehtuurista.

      Jos minulla olisi vapaat kädet rakentaa tämä systeemi, niin tekisin näin.

      Lisään pelaajatauluun kentät tehdyt_maalit ja syotetyt_maalit. Nämähän ovat pelaajaan hyvin läheisesti liittyviä tietoja. Aiemmassa versiossa nämä tiedot piti alikyselyillä hakea maalit-taulusta. Jokaisen pelaajan kohdalla kahlattiin maalit-taulu kahdesti läpi etsittäessä tehtyjä ja syötettyjä maaleja. Tässä esittämässäni ratkaisussa nämä tiedot voidaan lukea suoraan pelaajan tiedoista yksinkertaisella selectillä.

      Kuinka saadaan tiedot pelaajataulussa pysymään ajan tasalla? Luon triggerin, joka reagoi uuden rivin lisäämiseen maalit-tauluun. Triggeri päivittää maalin tehneen ja syöttäneen (jos syöttäjä on olemassa) pelaajan tiedot.

      Meillä on siis seuraavat taulut:

      Pelaajat
      ---------
      id
      etunimi
      sukunimi
      tehdyt_maalit
      syotetyt_maalit

      Maalit
      --------
      aika
      tekija
      syottaja


      Triggerin sisältö on tällainen:

      CREATE TRIGGER jengi_teki_maalin AFTER INSERT ON maalit
      FOR EACH ROW
      BEGIN

      UPDATE pelaajat
      SET tehdyt_maalit = tehdyt_maalit 1
      WHERE
      id = NEW.tekija;

      if NEW.syottaja is not null then
      UPDATE pelaajat
      SET syotetyt_maalit = syotetyt_maalit 1
      WHERE
      id = NEW.syottaja;
      end if;

      END


      Mutta kuten aiemmassa viestissä on sanottu, triggerien käyttö vaatii, että MySQL-tietokanta on tasoa 5.

      Pointtini siis on, että arkkitehtuurin suunnittelulla voidaan vaikuttaa paljon siihen, kuinka monimutkaisia ja raskaita SQL-operaatioita systeemissä tarvitaan!

      • tohlo

        > CREATE TRIGGER jengi_teki_maalin
        > AFTER INSERT ON maalit
        > FOR EACH ROW
        > BEGIN
        > UPDATE pelaajat
        > SET tehdyt_maalit = tehdyt_maalit 1
        > ...

        Entä jos maalit-tauluun lisättiin virheellinen rivi, esim. pelaajan id oli virheellinen tai maalia ei hyväksyttykään, vaikka se jo tauluun lisättiin? Laskurisi ei olekaan tällaisten jälkeen enää synkronissa oikean tilanteen kanssa. :)

        Idea kuitenkin sinulla oli se, että tallennetaan koostefunktion (count) tulos tauluunlisäysten yhteydessä, jotta lukumäärää ei aina tarvitse laskea perustietojen avulla uudelleen. Periaatteessa ok idea, mutta tässä täytyy ottaa huomioon kaikki sivuvaikutukset.

        Minä en kovin pienellä datamäärällä lähtisi käyttämään tällaista tallennustapaa. Vasta jos maaleja on tallessa (satoja) miljoonia ja datan määrä oikeasti johtaa siihen, että haut ovat optimoituinakin tehottomia (eikä sovelluskoodin muokkauksella tai taulujen indekseilläkään saada nopeutta), kannattaa alkaa tallennella välituloksia.


      • I.Proqatlis
        tohlo kirjoitti:

        > CREATE TRIGGER jengi_teki_maalin
        > AFTER INSERT ON maalit
        > FOR EACH ROW
        > BEGIN
        > UPDATE pelaajat
        > SET tehdyt_maalit = tehdyt_maalit 1
        > ...

        Entä jos maalit-tauluun lisättiin virheellinen rivi, esim. pelaajan id oli virheellinen tai maalia ei hyväksyttykään, vaikka se jo tauluun lisättiin? Laskurisi ei olekaan tällaisten jälkeen enää synkronissa oikean tilanteen kanssa. :)

        Idea kuitenkin sinulla oli se, että tallennetaan koostefunktion (count) tulos tauluunlisäysten yhteydessä, jotta lukumäärää ei aina tarvitse laskea perustietojen avulla uudelleen. Periaatteessa ok idea, mutta tässä täytyy ottaa huomioon kaikki sivuvaikutukset.

        Minä en kovin pienellä datamäärällä lähtisi käyttämään tällaista tallennustapaa. Vasta jos maaleja on tallessa (satoja) miljoonia ja datan määrä oikeasti johtaa siihen, että haut ovat optimoituinakin tehottomia (eikä sovelluskoodin muokkauksella tai taulujen indekseilläkään saada nopeutta), kannattaa alkaa tallennella välituloksia.

        Kyllä minä olen ottanut huomioon kaikki sivuvaikutukset. Satutko tietämään, että on mahdollista luoda myös sellaisia triggereitä, jotka reagoivat rivillä olevien tietojen päivittämiseen tai koko rivin poistamiseen.

        Jos siis maalin tehnyttä pelaajaa korjataan, niin update-triggeri nuuskii rivillä olleen vanhan ja uuden pelaajan ja suorittaa pelaajatiedoissa olevien laskurien päivitykset.

        Jos koko rivi poistetaan, niin triggeri käy vähentämässä yhden maalin tekijältä ja yhden syöttäjältä (jos sellainen oli).

        Siis triggeritoiminta pitää koko ajan yllä oikeita arvoja pelaajatiedoissa olevissa laskureissa.


      • I.Proqatlis
        tohlo kirjoitti:

        > CREATE TRIGGER jengi_teki_maalin
        > AFTER INSERT ON maalit
        > FOR EACH ROW
        > BEGIN
        > UPDATE pelaajat
        > SET tehdyt_maalit = tehdyt_maalit 1
        > ...

        Entä jos maalit-tauluun lisättiin virheellinen rivi, esim. pelaajan id oli virheellinen tai maalia ei hyväksyttykään, vaikka se jo tauluun lisättiin? Laskurisi ei olekaan tällaisten jälkeen enää synkronissa oikean tilanteen kanssa. :)

        Idea kuitenkin sinulla oli se, että tallennetaan koostefunktion (count) tulos tauluunlisäysten yhteydessä, jotta lukumäärää ei aina tarvitse laskea perustietojen avulla uudelleen. Periaatteessa ok idea, mutta tässä täytyy ottaa huomioon kaikki sivuvaikutukset.

        Minä en kovin pienellä datamäärällä lähtisi käyttämään tällaista tallennustapaa. Vasta jos maaleja on tallessa (satoja) miljoonia ja datan määrä oikeasti johtaa siihen, että haut ovat optimoituinakin tehottomia (eikä sovelluskoodin muokkauksella tai taulujen indekseilläkään saada nopeutta), kannattaa alkaa tallennella välituloksia.

        Sinä epäilit, etten ollut ottanut huomioon kaikkia sivuvaikutuksia. Niinpä esitän kaikki triggerit aivan konkreettisesti MySQL-koodin tasolla. Näet, kuinka triggerit reagoivat kaikkiin muutoksiin.

        Palstan muut lukijat voivat tästä saada ideoita triggerien käyttöön :-)

        1. Se, joka reagoi uuden rivin lisäykseen, on aiemmassa viestissäni.
        2. Triggeri nimeltä hylatty_maali hoitaa päivitykset, jos kirjattu rivi poistetaan.
        3. Triggeri, jonka nimi on tekija_korjaus, käsittelee tapaukset, joissa maalin tekijää tai syöttäjää muutetaan.


        CREATE TRIGGER hylatty_maali AFTER DELETE ON maalit
        FOR EACH ROW

        BEGIN

        UPDATE pelaajat
        SET tehdyt_maalit = tehdyt_maalit - 1
        WHERE id = OLD.tekija;

        if OLD.syottaja is not null then
        UPDATE pelaajat
        SET syotetyt_maalit = syotetyt_maalit - 1
        WHERE id = OLD.syottaja;
        end if;

        END

        * * * * * * * * * * * * * *

        CREATE TRIGGER tekija_korjaus after UPDATE ON maalit
        FOR EACH ROW

        BEGIN

        if NEW.tekija OLD.tekija then
        UPDATE pelaajat
        SET tehdyt_maalit = tehdyt_maalit - 1
        WHERE id = OLD.tekija;

        UPDATE pelaajat
        SET tehdyt_maalit = tehdyt_maalit 1
        WHERE id = NEW.tekija;
        end if;


        if ifnull(NEW.syottaja, 0) ifnull(OLD.syottaja, 0) then

        if OLD.syottaja is not null then
        UPDATE pelaajat
        SET syotetyt_maalit = syotetyt_maalit - 1
        WHERE id = OLD.syottaja;
        end if;

        if NEW.syottaja is not null then
        UPDATE pelaajat
        SET syotetyt_maalit = syotetyt_maalit 1
        WHERE id = NEW.syottaja;
        end if;

        end if;

        END


    • SQL

      Entäs tällainen tilanne:

      kaksi taulua (p ja m)

      p(kentät id, nimi)

      id|nimi |
      -------------
      1|erkki |
      2|pekka |

      m(kentät id, a1, a2)

      id|a1|a2|
      ---------
      1| 2| 2|
      2| 1| 1|
      3| 1| 2|
      4| 2| 3|

      Ja pitäisi saada haku, jossa on seuraavat tiedot:

      id|nimi |a|
      -----------
      1|erkki|2|
      2|pekka|1|

      , jossa siis a sarake on numero 1:sten määrä taulukossa m (erkillä sarakkeessa a1 ja pekalla a2). Kun siis sarakkeessa m.a1 on 2 kappaletta numero 1:stä, niin erkin sarakkeeseen hakutuloksessa tulee 2. Ja pekalla vastaavasti 1.

      Seuraavalla haulla molempien rivien arvoksi tulee 3, joka on siis molemmissa sarakkeissa yhteensä oleva ykkösten määrä. (Mikäli en aivan väärin laskenut)

      SELECT
      p.id AS id,
      p.nimi AS nimi,
      (SELECT count( * ) FROM m WHERE CONCAT('a', p.id) = 1) AS a
      FROM p

      Ymmärrän siis (toivottavasti), mikä tässä on väärin, mutta en osaa kirjoittaa oikeanlaista koodia...

      Ideoita?

    Ketjusta on poistettu 0 sääntöjenvastaista viestiä.

    Luetuimmat keskustelut

    1. Tärkeä kysymys!

      Haluatko sinä, mies, minut?
      Ikävä
      88
      1174
    2. Asiallinen lähestyminen

      Mitä on asiallinen lähestyminen?? Tietääkö tai tajuaako kukaan, varsinkaan miehet??? Eilen NELJÄNNEN kerran jouduin isk
      Sinkut
      151
      1006
    3. Jennika Vikman avoimena - Isosisko Erika Vikman ohjeisti napakasti Tähdet, tähdet -kisaan: "Älä.."

      Jennika ja Erika - niin ovat kuin kaksi marjaa! Ilmeiltään, ääneltään ja eleiltään hyvinkin samanlaiset - toinen on kyll
      Suomalaiset julkkikset
      13
      691
    4. En tiedä..

      Yhtään minkälainen miesmaku sinulla on. itse arvioin sinua moneenkin otteeseen ja joka kerta päädyin samaan lopputulokse
      Ikävä
      48
      687
    5. Vedalainen metafysiikka

      Termi ”metafysiikka” kuuluu Aristoteleelle. Metafysiikka tarkoittaa ”fysiikan jälkeen” eli tietoa siitä, mikä on tavalli
      Hindulaisuus
      287
      685
    6. Mitäs nainen

      Meinaat tehdä viikonloppuna.
      Ikävä
      60
      674
    7. Ai jaa sinä oletkin ahnas

      Ja romanttinen luonne, nyt vasta hiffasin että olet naarastiikeri. Parempi myöhään kuin ei milloinkaan.
      Ikävä
      107
      660
    8. En oikeastaan usko että sinä tai kukaan

      Olisi oikeasti ihastunut tai rakastunut. Se on joku harhakuva joka minusta miehestä syntyi. Ja kun se särkyy, niin "tunt
      Ikävä
      42
      604
    9. Viime yönä mietin paikkoja luonnossa, missä olen kulkenut

      kävellyt ja ikävöinyt, ja ollut niin yksin. Monet kerrat. Ne palauttavat mieleeni sinut ja sen, kuinka kipeää on se kaip
      Ikävä
      57
      602
    10. Milloin viimeksi näit ikäväsi kohteen?

      Oliko helppo tunnistaa hänet? Millaisia tunteita tuo näkeminen herätti sinussa?
      Ikävä
      35
      575
    Aihe