Paras tapa tehdä monivalintakysely käyttäen tietokantaa.

Viestiketju alueella 'Ohjelmointi, pelikehitys ja muu sovelluskehitys' , aloittaja Jean_Sipulius, 11.02.2019.

  1. Jean_Sipulius

    Jean_Sipulius

    Viestejä:
    315
    Rekisteröitynyt:
    17.10.2016
    Olen miettinyt pääni puhki ja en oikein hoksaa mikä olisi paras tapa edetä. Tilanne on tämä:

    -Käyttäjä voi klikata objektia X.
    -Aukeaa valikko, josta käyttäjä voi valita kolme aihepiiriä, josta äänestää. Aihepiirit ovat aina kiinteitä ja samoja.
    -Aihepiiriä klikatessa aukeaa uusi valikko, jossa on useita eri vaihtoehtoja liittyen klikattuun aihepiiriin. Nämä vaihtoehdot voivat vaihtua ja lukumäärää ei ole vakio.
    -Käyttäjä voi valita mieluisen vaihtoehdon ja klikata äänestä nappia jolloin tieto lähtisi tietokantaan.

    Nyt minun pitäisi saada otettua talteen äänestetty data ja tehdä yhteenveto. Ongelmia minulle tulee siinä kun äänestettävien lukumäärä vaihtelee ja en oikein tiedä miten tietokanta pitäisi luoda. Onko se validi ratkaisu, että kun äänestys tehdään, kyseiselle äänestykselle luodaan oma taulu, joilloin voidaan specifioida columnien lukumäärä? Tällöin tauluja tulisi todella paljon ajan mittaan. Jos tuolla tavalla tekee niin mikä olisi sitten paras keino saada nuo datat irti, jotta voi näyttää ne esim. pylväsdiagrammina?

    Data olisi periaatteessa tälläistä. Aihe X:n äänestys. Valinta 1: 2 ääntä, Valinta 2: 5 ääntä, Valinta 3: 4 ääntä jne.

    Huomioitavaa:
    Äänestäjät on yksilöity.
    Objekti X on yksilöity ja objektin äänestyksellä on uniikki nimi myös(ehkä tätä voisi hyödyntää?)
     
    Tomppa95 tykkää tästä.
  2. Zigh

    Zigh

    Viestejä:
    1 067
    Rekisteröitynyt:
    17.10.2016
    Eikö tuohon riitä kaksi (kolme) taulua?
    - Aiheet
    - Valinnat
    (- Äänet)

    e: äänet unohtui
     
    Viimeksi muokattu: 11.02.2019
  3. Tuxi

    Tuxi

    Viestejä:
    248
    Rekisteröitynyt:
    19.10.2016
    Ei missään nimessä dynaamisia tauluja. Aihealue (1) - Kysymys (*), Kysymys (1) - Valinta (*), jossa siis molemmat ovat yksi moneen suhteella. MySQL WorkBench tai muu vastaava schema editori auki ja alat sinne hahmottelemaan.
     
  4. ©©©

    ©©©

    Viestejä:
    281
    Rekisteröitynyt:
    16.10.2016
    Jotenkin näin tekisin:
    Koodi:
    users
    id, name
    
    topics
    id, name
    
    selections
    id, name, topic_id(fk)
    
    votes
    id, user_id(fk), selection_id(fk)
    
     
  5. Jean_Sipulius

    Jean_Sipulius

    Viestejä:
    315
    Rekisteröitynyt:
    17.10.2016
    Kiitos avusta. Täytyy alkaa keskiviikkona hahmotella asiaa. Luultavasti palaan triidiin loppuviikosta jos ei onnistu :).
     
  6. Jean_Sipulius

    Jean_Sipulius

    Viestejä:
    315
    Rekisteröitynyt:
    17.10.2016
    Dodii. Oon luonut tietokannat ja siihen pisteeseen jo päässyt, että tietystä asiasta haluttu äänestys menee tietokantaan. Ongelma tuli viimeisessä vaiheessa, eli siinä kun asiakas painaa äänestä ja hänen tieto pitäisi laittaa äänestystauluun. Tässä tapauksessa käytin ©©© mallia
    id, user_id(fk), selection_id(fk).

    Ongelma on siinä, että user_id:n saadakseni minun pitää ensin tehdä esim. seuraavanlainen kysely:
    select ID from users where username = 'simppa'

    sen jälkeen jos haluan selection_id:n, niin olen ottanut sen äänestyksen nimen perusteella. Eli saan sen esim. tällä tavalla:
    select ID from TopicSelections where Name = 'Hallin 2B sohvan sijainti'

    Nuo kaksi tietoa tietysti tulevat suoraan ohjelmasta, tässä tapauksessa vain kovakoodasin ne. Ongelma on se, että kuinka saan otettua nuo ID:t ja samassa lauseessa vielä tehtyä INSERT lauseen, joka asettaa tuonne Votes tauluun kyseisen äänestyksen?

    Onko tietokannan paluuarvoja mahdollista tallentaa itse SQL kyselyyn ja käyttää niitä sieltä? Onko mahdollista querata noita kolmea eri lausetta ja käyttää edellisten queryjen paluuarvoja niissä?

    Onko tämä lähetymistapa edes hyvä?
     
  7. Zigh

    Zigh

    Viestejä:
    1 067
    Rekisteröitynyt:
    17.10.2016
    Lyhyesti: ei ole.

    Sinullahan pitäisi olla jo käyttäjä (id) ja topic (id) jossain tallessa siinä vaiheessa kun käyttäjä valitsee mille valinnalle antaa äänensä. Ei tuollaisia selectejä pitäisi tarvita mihinkään. Muutenkin täysin nurinkurista hakea id:tä jonkun nimen perusteella.
     
    ©©© tykkää tästä.
  8. Jean_Sipulius

    Jean_Sipulius

    Viestejä:
    315
    Rekisteröitynyt:
    17.10.2016
    Näin arvelinkin. Yritän nyt kirjoittaa mahdollisimman selkeästi mitä olen yrittänyt tehdä. Ihan alkuun minun tietokannan taulut näyttää tältä.

    [​IMG]

    ID on automaattisesti nouseva. TOPICS_ID on TopicSelections taulussa olevan nimen FK. Eli käytännössä kertoo on kyseessä minkälainen äänestys. Sitten olen ottanut mukaan muutaman muun tiedon, jotka äänestyksen laatija voi määritellä ohjelmassa. UNIQUEGAMEID on uniikki ID joka generoidaan jokaiselle esineelle, jossa äänestys on.

    Tässä on lauseke, jolla em. tauluun on lisätty tieto. Lause generoituu äänestyksen laatijan syöttämien tietojen mukaan. Tässä tapauksessa kolme riviä luodaan.

    INSERT INTO TopicSelections(Name, Topics_ID, LevelName, Headline, UniqueGameID) VALUES ('Lounaskulmassa', 2, 'CameraTestMap', 'Hallin 2B Pöydän sijainti','214135940'),('Nykyisellä sijainnilla', 2, 'CameraTestMap', 'Hallin 2B Pöydän sijainti','214135940'),('Eteläpäässä', 2, 'CameraTestMap', 'Hallin 2B Pöydän sijainti','214135940')

    Nyt en oikein osaa hahmottaa, että mitä tietoa tuolla TopicVotes taulukossa pitäisi olla. Ilmiselvästi SelectionID pitäisi viitata siihen ID:n kohtaan, jossa on sille määritetty äänestys. Tässä tapauksessa uniquegameid ei auta mitään, koska jokaisella sijainnilla se on sama. En kuitenkaan esimerkiksi ohjelmassa saa suoraan viitattua tuohon ID kohtaan, koska minun pitäisi saada se takaisin heti kun lisään äänestyksen tietokantaan. Yritin ottaa resultista dataa, jolla saisin ID:n ohjelmaan:

    result.insertId;

    Mutta ilmeisesti resultista(tietokannan palauttamista tiedoista) ei saa otettua dataa, koska niitä lisätään useampi rivi kerrallaan. Yksittäin homma näyttäisi toimivan. Huomiona voisin sanoa, että ohjelma saa otettua ja purettua objekteja joita esim. response.send() komennolla annetaan takaisin.

    Tässä todella pelkistetty UI ilman grafiikkaa
    [​IMG]

    Tässä kohtaa ollaan siinä pisteessä, että on valittu sijaintiäänestys ja nyt käyttäjä voi valita sijainnin (kolme valkoista neliöä). Kun yksi neliöistä on valittu (näihin voi laittaa dataa tarpeen mukaan) ja käyttäjä painaa äänestä niin silloin lähtisi INSERT kutsu tietokantaan. Eli mitä tässä insertissä nyt sitten pitäisi käytännössä olla.

    Kiitos paljon.
     
  9. yksvaan

    yksvaan

    Viestejä:
    75
    Rekisteröitynyt:
    26.11.2018
    Mkset vaan laita tietoja siihen requestiin tyyliin
    action: addVote,
    userid: 1234,
    questionID : 1234,
    valittu option id : 123

    Sit validoit userid, kysymyksen tilan jne, ääni sinne votes-tauluun ja vaihtoehtoisin +1
     
  10. Jean_Sipulius

    Jean_Sipulius

    Viestejä:
    315
    Rekisteröitynyt:
    17.10.2016
    En nyt ihan hoksaa mitä tarkoitat. Sain kuitenkin homman toimimaan taas eteenpäin seuraavasti:

    Hylkäsin kokonaan tuo auto_increment ID:n. Kullekin äänestysvaihtoehdolle generoidaan oma ID kun äänestysvaihtoehto luodaan ja tätä ID:tä käytetään kun insertoidaan tietokantaan uusi äänestystietue. Nyt kun käyttäjä haluaa äänestää ja klikkaa äänestysnappulaa, niin Votes taulukkoon voidaan huoletta ottaa aiemmin generoitu ID, ja nyt se tietenkin vastaa äänestyksen ID:tä ja taulut voidaan yhdistää.

    UserID:n jätin pois, koska käyttäjillä ei ole käytännössä ID-numeroa, mutta kaikilla on uniikki käyttäjänimi. Eli taulukossa on ID,UserName ja Selection. Nyt pystyn poimimaan erilliset äänet ID:n perusteella. Ainakin hyvä alku ja vaikuttaisin oikealta.
     
  11. pimpBot5000

    pimpBot5000

    Viestejä:
    1
    Rekisteröitynyt:
    21.02.2019
    Tee äänestyksestä vaihtoehtoineen JSON ja laita se tauluun. Tyylipisteitä ei heru mutta toimii.
     
  12. yksvaan

    yksvaan

    Viestejä:
    75
    Rekisteröitynyt:
    26.11.2018
    IMO melkein aina primary key olis hyvä olla integer. Usernamea nyt tollasessa tarvii lähinnä kun kirjautuu sisään.

    Toinen juttu on sitten jos tarvii vaihtaa usernamea, riittää yhden taulun kentän päivitys ja mikään muu ei hajoa. Jos esim. 2 käyttäjää vaihtaa usernamea keskenään, pieni GDPR-kuumotus voi iskeä jos haet usernamella...
     
  13. Jean_Sipulius

    Jean_Sipulius

    Viestejä:
    315
    Rekisteröitynyt:
    17.10.2016
    [​IMG]

    Nyt mulla on tämmöinen patentti. Ylempi on Topics, jossa Topics_ID vastaa äänestyksen tyyppiä (3 = Ulkonäkö, 2 = sijainti, 1 = rakennusmateriaali)

    Käyttäjien äänissä ID on auto_increment ja SelectionID vastaa Topicsin ID:tä. Käyttäjänimi on käyttäjän nimi. Ohjelma tarkastaa automaattisesti, jotta päällekkäisiä käyttäjän ääniä ei voi tulla vaan ne korvataan.

    Milläs tavalla tästä nyt kannattaisi lähteä rakentamaan semmoista, että jos haluan tietää esim. kuinka monta ääntä Hallin 2B Nurkkapöydän "Eteisalueella" (ID 22110960) on saanut verrattuna vaikkapa "Sisäänkäynnin vieressä"(ID 22110961) kohtaan.

    Kiitoksia.

    aania.png
     
    Viimeksi muokattu: 28.02.2019
  14. Zigh

    Zigh

    Viestejä:
    1 067
    Rekisteröitynyt:
    17.10.2016
    SELECT COUNT
    SQL COUNT(), AVG() and SUM() Functions
     
  15. Jean_Sipulius

    Jean_Sipulius

    Viestejä:
    315
    Rekisteröitynyt:
    17.10.2016
    Joo, COUNT oon käytänyt muutaman kerran, mutta mulla on vähän epäselvää, että kuinka saan Countilla laskettua ja sitten palautettua useamman arvon. Jos vaikka Eteisalueella summaksi tulee 4 ja sitten Sisäänkäynnin vieressä summaksi tulee 9. Mikä on paras tyyli palauttaa nämä molemmat arvot, jotta niitä voi vertailla sitten koodissa. Pitääkö tässä vain tehdä kaksi tai useampia sql kyselyä erikseen?
     
  16. brm

    brm

    Viestejä:
    9
    Rekisteröitynyt:
    11.01.2019
    GROUP BY lause auttanee tuohon
     
  17. Zigh

    Zigh

    Viestejä:
    1 067
    Rekisteröitynyt:
    17.10.2016
    Yleisin tapa varmaan hakea jokaisen vaihtoehdon tulokset erikseen. Toki yhdelläkin kyselyllä onnistuu How to get multiple counts with one SQL query?
     
  18. ississ

    ississ

    Viestejä:
    338
    Rekisteröitynyt:
    17.01.2018
    Käytännössä muutama vaihtoehto:
    1. haet jokaisen topicin äänten lukumäärän ja vertailet koodissa eri rivien lukumäärä- arvoa.
    - helppo kysely ja todennäköisesti nopea suorittaa kannassa
    - eri topiccien määrät eri riveillä, 1 rivi / topic
    2. tee sql joka hakee eri topiccien määrät rinnakkain.
    - hankala kysely johon pitää kovakoodata eri topicit tai luoda sql dynaamisesti jolloin pitää vastaavasti tietää montako saraketta tulokseen tulee.
    - ei hyvä jos topicceja on paljon
    - todennäköisesti hitaampi kuin 1.
    3. loopilla/vastaavalla haet jokaiselle topicille näänimäärän erikseen
    - helpoin yksittäinen kysely mutta niitä pitää tehdä kantaan yhtä monta kuin on topicceja. Lopputulos on suunnilleen sama kuin 1. koska tulokset saadaan peräkkäin.
    - kannasta riippuen tämä on yleensä hitaampi tapa hakea kuin 1.

    Jokaisessa tapauksessa vastaustaulussa on syytä olla indeksi selectionid- kentässä, muuten hidastuu traagisesti rivimäärän kasvaessa.

    Jokaisessa on omat hyvät ja huonot puolensa vähän riippuen rivimääristä ja käytetystä kannasta. Ja siitä miten tuloksia käsitellään.
     
  19. yksvaan

    yksvaan

    Viestejä:
    75
    Rekisteröitynyt:
    26.11.2018
    IMO ainoa järkevä tapa on hakea topicit kysymyksen IDellä alikyselynä ja sitten niiden äänien summat.

    Nämä tiedot täytyy kuitenkin hakea joten fiksumpaa antaa tietokantapalvelimen hoitaa se.
     
  20. nnaku

    nnaku I'm object-oriented! Tukijäsen

    Viestejä:
    721
    Rekisteröitynyt:
    28.11.2016
    Koodi:
    SELECT DISTINCT tableAlias.key, (
      SELECT COUNT(*) as "Count Of Key" FROM table WHERE key=tableAlias.key
    ) FROM table as tableAlias
    Eli ulompi kysely hakee kaikki uniikit avaimet, ja sisempi kysely hakee ko. rivin avaimelle lukumäärän.
     
  21. ississ

    ississ

    Viestejä:
    338
    Rekisteröitynyt:
    17.01.2018
    Miksi hakea kahdella kyselyllä kun yhdelläkin pärjää?

    select key, count(*) as countofkey from table group by key;

    => ei joinia, kanta käy taulun läpi vain kerran, ei temp- tulosta alikyselystä edes muistiin.

    Tässä count(*) tilalla voi käyttää myös sum(1).
    Vuosien työkokemuksella uskallan ehdottaa että vältä alikyselyjä niin pitkälle kuin mahdollista.
    Kannattaa myös opetella välttämään heti aluksi välejä ja skandeja taulujen ja sarakkeiden nimissä, pääsee lopulta helpommalla.

    Muutamalla rivillä ajoajan eroa ei huomaa mutta se voi yllättää jos rivejä tulee paljon enemmän.
     
    Zerby tykkää tästä.