2015-05-22 40 views
5

Załóżmy, że próbuję zbudować aplikację do ankiety, dzięki której mogę utworzyć szablon ankiety, udzielić jej wielu sekcji/pytań, przypisać wiele osób do różnych kopii danego pytania, stworzyć różne miary (zadowolenie, sukces, zieleń) i przypisać różne pytania różne wagi, które mają zastosowanie do wszystkich tych środków.grupy przez nie zgrupowanie agregacji?

Coś tak:

CREATE TABLE users (
    id SERIAL NOT NULL PRIMARY KEY 
); 

CREATE TABLE opinion_poll_templates (
    id SERIAL NOT NULL PRIMARY KEY 
); 

CREATE TABLE opinion_poll_instances (
    id SERIAL NOT NULL PRIMARY KEY, 
    template_id INTEGER NOT NULL REFERENCES opinion_poll_templates(id) 
); 

CREATE TABLE section_templates (
    id SERIAL NOT NULL PRIMARY KEY, 
    opinion_poll_id INTEGER NOT NULL REFERENCES opinion_poll_templates(id) 
); 

CREATE TABLE section_instances (
    id SERIAL NOT NULL PRIMARY KEY, 
    opinion_poll_id INTEGER NOT NULL REFERENCES opinion_poll_instances(id), 
    template_id INTEGER NOT NULL REFERENCES section_templates(id) 
); 

CREATE TABLE question_templates (
    id SERIAL NOT NULL PRIMARY KEY, 
    section_id INTEGER NOT NULL REFERENCES section_templates(id) 
); 

CREATE TABLE measure_templates (
    id SERIAL NOT NULL PRIMARY KEY, 
    opinion_poll_id INTEGER NOT NULL REFERENCES opinion_poll_templates(id) 
); 

CREATE TABLE answer_options (
    id SERIAL NOT NULL PRIMARY KEY, 
    question_template_id INTEGER NOT NULL REFERENCES question_templates(id), 
    weight FLOAT8 
); 

CREATE TABLE question_instances (
    id SERIAL NOT NULL PRIMARY KEY, 
    template_id INTEGER NOT NULL REFERENCES question_templates(id), 
    opinion_poll_id INTEGER NOT NULL REFERENCES opinion_poll_instances(id), 
    section_id INTEGER NOT NULL REFERENCES section_instances(id), 
    answer_option_id INTEGER NOT NULL REFERENCES answer_options(id), 
    contributor_id INTEGER 
); 

CREATE TABLE measure_instances (
    id SERIAL NOT NULL PRIMARY KEY, 
    opinion_poll_id INTEGER NOT NULL REFERENCES opinion_poll_instances(id), 
    template_id INTEGER NOT NULL REFERENCES measure_templates(id), 
    total_score INTEGER 
); 

CREATE TABLE scores (
    id SERIAL NOT NULL PRIMARY KEY, 
    question_template_id INTEGER NOT NULL REFERENCES question_templates(id), 
    measure_template_id INTEGER NOT NULL REFERENCES measure_templates(id), 
    score INTEGER NOT NULL 
); 

Teraz powiedzmy, że jestem zainteresowana za measureInstance (jednej miary przypisanej do sondażu) przekroju poprzecznym pytanie przeciętnego użytkownika?

Wydaje się nie tylko nie zgrupować zgodnie z oczekiwaniami, ale wygenerować nieprawidłowe wyniki.

Dlaczego wynik jest liczbą całkowitą, a nie zmienną? Dlaczego wynik nie jest grupowany przez instancję miar, a zamiast tego jest identyczny we wszystkich? I dlaczego wynik jest niepoprawny dla żadnego z nich?

Demonstracja: http://sqlfiddle.com/#!15/dcce8/1

EDIT: W pracy poprzez wyjaśniając dokładnie to, co chciałem, ja sobie sprawę, że źródłem mojego problemu było to, że był po prostu dodanie wartości procentowe, a następnie normalizację w poprzek pytania w procentach.

Moja nowa i ulepszona sql jest:

WITH per_question_percentage AS ( 
    SELECT SUM(answer_options.weight)/COUNT(question_instances.id) percentage, question_templates.id qid, opinion_poll_instances.id oid 
    FROM question_instances 
    INNER JOIN answer_options ON question_instances.answer_option_id = answer_options.id 
    INNER JOIN question_templates ON question_templates.id = question_instances.template_id 
    INNER JOIN opinion_poll_instances ON opinion_poll_instances.id = question_instances.opinion_poll_id 
    GROUP BY question_templates.id, opinion_poll_instances.id 
), max_per_measure AS (
    SELECT SUM(scores.score), measure_instances.id mid, measure_instances.opinion_poll_id oid 
    FROM measure_instances 
    INNER JOIN scores ON scores.measure_template_id=measure_instances.template_id 
    GROUP BY measure_instances.id, measure_instances.opinion_poll_id 
), per_measure_per_opinion_poll AS (
    SELECT per_question_percentage.percentage * scores.score score, measure_instances.id mid, measure_instances.opinion_poll_id oid 
    FROM question_instances 
    INNER JOIN scores ON question_instances.template_id = scores.question_template_id 
    INNER JOIN measure_instances ON measure_instances.template_id = scores.measure_template_id 
    INNER JOIN max_per_measure ON measure_instances.id = max_per_measure.mid 
    INNER JOIN per_question_percentage ON per_question_percentage.qid = question_instances.template_id 
    WHERE measure_instances.opinion_poll_id = question_instances.opinion_poll_id AND question_instances.opinion_poll_id = per_question_percentage.oid 
    GROUP BY measure_instances.id, measure_instances.opinion_poll_id, per_question_percentage.percentage, scores.score 
) 
UPDATE measure_instances 
SET total_score = subquery.result*100 
FROM (SELECT SUM(per_measure_per_opinion_poll.score)/max_per_measure.sum result, per_measure_per_opinion_poll.mid, per_measure_per_opinion_poll.oid 
     FROM max_per_measure, per_measure_per_opinion_poll 
     WHERE per_measure_per_opinion_poll.mid = max_per_measure.mid 
     AND per_measure_per_opinion_poll.oid = max_per_measure.oid 
     GROUP BY max_per_measure.sum, per_measure_per_opinion_poll.mid, per_measure_per_opinion_poll.oid) 
     AS subquery(result, mid, oid) 
WHERE measure_instances.id = subquery.mid 
AND measure_instances.opinion_poll_id = subquery.oid 
RETURNING total_score; 

Czy to kanoniczny sql? Czy jest coś, o czym powinienem być świadomy przy tego rodzaju łańcuchach CTE (lub w inny sposób)? Czy istnieje skuteczniejszy sposób na osiągnięcie tego samego?

+0

Q1: 'measure_instances.TotalScore'jest zdefiniowany jako' INTEGER'. Q2: It ** jest ** poprawnie pogrupowane według 'measure_instances.id'. P3: Ponieważ robisz coś złego w swoich połączeniach? Uruchom 'SELECT' w standardzie CTE, usuń' AVG'/'GROUP BY' i sprawdź wiersze szczegółów. – dnoeth

Odpowiedz

1

To trochę za długi komentarz.

Nie rozumiem pytań.

Dlaczego wynik jest liczbą całkowitą, a nie zmienną?

Ponieważ measure_instances.total_score jest liczbą całkowitą i to właśnie powraca klauzula returning.

Dlaczego wynik nie jest zgrupowany według miary instancji, a zamiast tego jest identyczny we wszystkich?

Po uruchomieniu CTE niezależnie, wartości wynoszą 0,45. Dane i logika dyktują te same wartości.

I dlaczego wynik jest niepoprawny dla żadnego z nich?

Myślę, że masz na myśli "dla wszystkich". W każdym razie wyniki wydają mi się prawidłowe.

1

Po uruchomieniu tej kwerendy przeciwko danych w Demo:

SELECT 
    answer_options.weight, measure_instances.id 
FROM 
    question_instances 
INNER JOIN 
    answer_options ON question_instances.template_id = answer_options.question_template_id 
INNER JOIN 
    scores ON question_instances.template_id = scores.question_template_id 
INNER JOIN 
    measure_instances ON measure_instances.template_id=scores.measure_template_id 
WHERE 
    measure_instances.opinion_poll_id = question_instances.opinion_poll_id 
ORDER BY 
    2; 

Dostaniesz:

| weight | id | 
|--------|----| 
| 0.5 | 1 | 
| 0.25 | 1 | 
| 0.25 | 1 | 
| 0.75 | 1 | 
| 0.5 | 1 | 
| 0.75 | 2 | 
| 0.5 | 2 | 
| 0.25 | 2 | 
| 0.5 | 2 | 
| 0.25 | 2 | 

Jeśli obliczyć średnie ręcznie, dostaniesz:

Dla id = 1 ==> 0,5 + 0,25 + 0,25 + 0,75 + 0,5 = 2,25 ==> 2,25/5 = 0,45
id = 2 ==> + 0,5 + 0,75 + 0,5 0,25 + 0,25 = 2,25 ==> 2,25/5 = 0,45

Wydaje mi, że zapytanie działa doskonale.

Proszę wyjaśnić, dlaczego te wyniki są dla Ciebie błędne i czego oczekujesz od powyższych danych i zapytania?

+0

Dziękuję za próbę nakłonienia mnie do wyjaśnienia tego. Czyniąc to, doszedłem do tego, co jest właściwie rozwiązaniem. Mój problem polegał na tym, że nie normalizowałem moich wyników w odniesieniu do wszystkich środków. Zobacz moje pytanie o aktualizację (w edycji). –