2017-10-19 23 views
0

J'essaie de trouver le bon SQL pour accomplir quelque chose de semi-complexe. J'utilise postgres dans ce scénario particulier, mais une instruction sql qui pourrait fonctionner pour d'autres plates-formes serait également appréciée.SQL - Obtenir le compte de groupe par colonne, mais aussi sélectionner le premier élément du groupe

J'ai des tables appelées utilisateurs et réponses. Un utilisateur effectuera des activités et pour chaque tentative d'activité, nous suivons une réponse de l'utilisateur et si cette réponse a entraîné une note de passage pour l'activité.

tables et colonnes pertinentes:

utilisateurs: id (int), nom d'utilisateur (varchar), classroom_id (int), le type (varchar)

Réponses: id (int), activity_id (int), user_id (int), is_passing_score (bool)

Activités: id (int), le type (varchar), nom (varchar)

ce que je voudrais être en mesure de tirer de ces tables est le activity_id , nombre de tentatives pour chaque activité, et si l'activité a été transmise.

select activity_id, count(activity_id) 
from (
    select * 
    from responses R 
    inner join users U on U.id = R.user_id 
    where U.classroom_id = '114' AND U.type = 'Student' 
    group by R.activity_id, R.id, U.id 
    order by activity_id, is_passing_score DESC 
) as foo 
group by activity_id 
order by activity_id 

La requête ci-dessus me obtenir le activity_id et le nombre de tentatives, mais je me bats pour obtenir aussi si des réponses ont donné lieu à une activité passée (via la colonne de is_passing_score). Ce serait vrai si l'une des réponses avait la valeur is_passing_score à true.

J'ai aussi essayé quelque chose comme ça qui pourrait me donner la valeur vrai/faux que je cherche si l'activité a été réussie ou non.

select rn, * 
from (
    select row_number() OVER(PARTITION BY activity_id ORDER BY is_passing_score DESC) AS rn, * 
    from responses R 
    inner join users U on U.id = R.user_id 
    where U.classroom_id = '114' AND U.type = 'Student' 
    group by R.activity_id, R.id, U.id 
    order by activity_id, is_passing_score DESC 
) as foo 
WHERE rn = '1' 
order by activity_id 

Je pense que la requête ordonnera la sous-requête par le is_passing_score puis prenez juste du haut, qui, si son vrai serait que, d'autre si son faux juste que ce soit. Mon gros problème, si cette deuxième requête est en fait correcte, est d'obtenir à la fois le compte et cette valeur vrai/faux. Je me sens comme si je suis proche, c'est juste une question de pouvoir faire la ligne sélectionner et aussi obtenir un compte dans une requête.

Je veux que mon résultat final soit une liste de activity_id, user_id, nombre de tentatives, et a été passé.

  • activity_id, user_id, passé, les tentatives
  • 17, 3069, t, 2
  • 18, 3069, t, 3
  • 151,3069, t, 1
  • 152,3069, t, 4
+0

Les exemples de données et les résultats souhaités seraient vraiment utiles. –

+0

Je peux essayer de fournir plus de données d'échantillon si nécessaire, mais je ne suis pas sûr de la meilleure façon d'y parvenir. –

Répondre

2

Je pense que vous voulez quelque chose comme ceci:

SELECT r.activity_id, count(*) AS num_attempts, 
     CAST(MAX(CAST(is_passing_score AS INT)) AS BOOL) AS has_passed 
FROM responses r INNER JOIN 
    users u 
    ON u.id = r.user_id 
WHERE u.classroom_id = 114 AND u.type = 'Student' 
GROUP BY r.activity_id; 
+0

J'ai essayé cela, mais le max (is_passing_score) échoue car is_passing_score est un booléen. L'erreur exacte: "la fonction max (boolean) n'existe pas" –

+0

En fait, si je lance le is_passing_score à un int qui pourrait fonctionner –