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

Liittynyt
17.10.2016
Viestejä
486
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ää?)
 
Eikö tuohon riitä kaksi (kolme) taulua?
- Aiheet
- Valinnat
(- Äänet)

e: äänet unohtui
 
Viimeksi muokattu:
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.
 
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)
 
Kiitos avusta. Täytyy alkaa keskiviikkona hahmotella asiaa. Luultavasti palaan triidiin loppuviikosta jos ei onnistu :).
 
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ä?
 
Onko tämä lähetymistapa edes hyvä?
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.
 
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.
Näin arvelinkin. Yritän nyt kirjoittaa mahdollisimman selkeästi mitä olen yrittänyt tehdä. Ihan alkuun minun tietokannan taulut näyttää tältä.

x8bzKCx.png


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
7L9yRev.png


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.
 
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
 
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
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.
 
Tee äänestyksestä vaihtoehtoineen JSON ja laita se tauluun. Tyylipisteitä ei heru mutta toimii.
 
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...
 
pw65g05.png


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:
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?
 
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?
Yleisin tapa varmaan hakea jokaisen vaihtoehdon tulokset erikseen. Toki yhdelläkin kyselyllä onnistuu How to get multiple counts with one SQL query?
 
pw65g05.png


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

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.
 
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.
 
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.
 
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.

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.
 

Uusimmat viestit

Statistiikka

Viestiketjuista
261 839
Viestejä
4 548 799
Jäsenet
74 851
Uusin jäsen
hieunguyen

Hinta.fi

Back
Ylös Bottom