J'ai le cas suivant (l'exemple que je montre est sur un domaine factice parce que pour des raisons NDA etc.).

J'ai accès à une base de données de production contenant les données des étudiants sous la forme suivante:

Student_ID  Course_Name Total_Average_Grade
1           Maths       19,1
1           Physics     0
1           Biology     0
2           Physics     18,5
2           Chemistry   0
3           Maths       19,4
3           Literature  0
3           Physics     0

Je veux récupérer, disons, les 10 étudiants avec la note moyenne totale la plus élevée, et pour ces 10, récupérer la liste complète des cours qu'ils ont suivis. Je souhaite exécuter cette requête sur une base mensuelle.

Par exemple, dans le tableau ci-dessus, si je voulais sélectionner les 2 meilleurs étudiants, le résultat serait:

Student_ID  Course_Name Total_Average_Grade
3           Maths       19,4
3           Physics     0
3           Biology     0
1           Maths       19,1
1           Literature  0
1           Physics     0

Notez que je n'ai pas le droit de créer des vues ou des procédures stockées sur cette base de données, ce qui serait un moyen facile de surmonter la limitation de ne pas pouvoir effectuer de sous-requêtes sur une sélection (sélectionnez n supérieur / limite n) (par exemple, Je serais en mesure de créer automatiquement une vue mensuelle que j'utiliserais pour joindre une sélection simple des 10 meilleures moyennes, etc.).

Existe-t-il une solution élégante à cette tâche?

Pour mémoire, j'utilise Sybase 15.4 comme client pour accéder à la base de données de production Sybase IQ.

1
rpd 16 janv. 2017 à 11:40

2 réponses

Meilleure réponse

Je pense que vous pouvez utiliser une requête comme celle-ci:

select *
from (
    select *,
        row_number() over (partition by Course_Name order by Total_Average_Grade desc) as rn
    from yourTable) t
where t < 11;
1
shA.t 16 janv. 2017 à 09:21

Vérifiez la requête ci-dessous qui s'exécute avec succès sur SQL Server.

        DECLARE @student TABLE(
                Student_ID INT,        
                Course_Name VARCHAR(100),
                Total_Average_Grade VARCHAR(100)
        )

        INSERT INTO @student 
        select 1, 'Maths  '     ,'19.1' union
        select 1, 'Physics'     ,'0'union
        select 1, 'Biology'     ,'0'union
        select 2, 'Physics'     ,'18.5'union
        select 2, 'Chemistry'   ,'0'union
        select 3, 'Maths'       ,'19.4'union
        select 3, 'Literature'  ,'0'union
        select 3, 'Physics'     ,'0'


        ;WITH ValList AS(
                SELECT  Student_ID,Course_Name, Case when Total_Average_Grade like '%,%' then

                        CAST(LEFT(Total_Average_Grade,PATINDEX('%,%', Total_Average_Grade) - 1) AS float) 
                        else Total_Average_Grade end as
                        Total_Average_Grade,
                        RIGHT(Total_Average_Grade,LEN(Total_Average_Grade) - PATINDEX('%,%', Total_Average_Grade)) Remainder

                FROM    @student
                UNION ALL
                SELECT  Student_ID,Course_Name,
                        CAST(LEFT(Remainder,CASE WHEN PATINDEX('%,%', Remainder) = 0 THEN LEN(Remainder) ELSE PATINDEX('%,%', Remainder) - 1 END) AS float) Total_Average_Grade,
                        RIGHT(Remainder,CASE WHEN PATINDEX('%,%', Remainder) = 0 THEN 0 ELSE LEN(Remainder) - PATINDEX('%,%', Remainder) END) Remainder
                FROM    ValList
                WHERE   LEN(Remainder) > 0

        )


        select SS.* from @student SS  
        join 
        (
        SELECT  top 2 v.Student_ID  --  use TOP 10 for 10 records
        --,s.Course_Name,s.Total_Average_Grade,SUM(v.Total_Average_Grade) as Avg,
        ,row_number() over( order by SUM(v.Total_Average_Grade) desc) rnk
        FROM    ValList V
        join @student S on s.Student_ID=V.Student_ID and s.Course_Name=V.Course_Name
        GROUP BY v.Student_ID
        )AA on AA.Student_ID=SS.Student_ID
        order by rnk asc,Total_Average_Grade desc

Production :

enter image description here

1
Mr. Bhosale 16 janv. 2017 à 10:23