Слишком много результатов запроса

#sql #postgresql

#sql #postgresql

Вопрос:

Я пытаюсь одновременно понять следующий запрос,

 SELECT s.LAST_NAME||', '||s.FIRST_NAME||' '||COALESCE(s.MIDDLE_NAME,' ') AS FULL_NAME,
s.LAST_NAME,
s.FIRST_NAME,
s.MIDDLE_NAME,
s.STUDENT_ID,
ssm.SCHOOL_ID,
ssm.SCHOOL_ID AS LIST_SCHOOL_ID,
ssm.GRADE_ID ,
sg1.BENCHMARK_ID,
sg1.GRADE_TITLE,
sg1.COMMENT AS COMMENT_TITLE,
ssm.STUDENT_ID,
sg1.MARKING_PERIOD_ID,
sg1.LONGER_COURSE_COMMENTS,
sp.SORT_ORDER,
sched.COURSE_PERIOD_ID 
FROM STUDENTS s,
STUDENT_ENROLLMENT ssm ,
SCHEDULE sched 
LEFT OUTER JOIN STUDENT_REPORT_CARD_BENCHMARKS sg1 ON (
sg1.STUDENT_ID=sched.STUDENT_ID 
AND sched.COURSE_PERIOD_ID=sg1.COURSE_PERIOD_ID 
AND sg1.MARKING_PERIOD_ID IN ('0','442','445','450') 
AND sg1.SYEAR=sched.SYEAR) 
LEFT OUTER JOIN COURSE_PERIODS rc_cp ON (
rc_cp.COURSE_PERIOD_ID=sg1.COURSE_PERIOD_ID 
AND rc_cp.DOES_GRADES='Y') 
LEFT OUTER JOIN SCHOOL_PERIODS sp ON (sp.PERIOD_ID=rc_cp.PERIOD_ID) 
WHERE ssm.STUDENT_ID=s.STUDENT_ID  
AND ssm.SCHOOL_ID='1'  
AND ssm.SYEAR='2010' 
AND ('22-APR-11' BETWEEN ssm.START_DATE AND ssm.END_DATE OR (ssm.END_DATE IS NULL))  
AND (LOWER(s.LAST_NAME) LIKE 'la''porsha%' OR LOWER(s.FIRST_NAME) LIKE 'la''porsha%' ) 
AND sched.STUDENT_ID=ssm.STUDENT_ID AND sched.MARKING_PERIOD_ID IN ('0','444','446','447','445','448','450','443','449') 
AND ('22-APR-11' BETWEEN sched.START_DATE AND sched.END_DATE OR (sched.END_DATE IS NULL AND '22-APR-11'>=sched.START_DATE))     
ORDER BY s.LAST_NAME,s.FIRST_NAME
  

и измените его, чтобы возвращать правильные результаты — возвращать только одного отдельного пользователя. При поиске какого-либо конкретного пользователя возвращается несколько результатов, потому что из schedule.course_period_id возвращаются уникальные значения. Поскольку в course_period_id поле есть несколько внешних соединений слева, но в разных таблицах, я не знаю, где изменить запрос.

Комментарии:

1. Боже правый, по крайней мере, попробуй отформатировать код. Ни у кого нет надежды понять, что происходит в его нынешнем состоянии.

2. Первое, что я бы исправил, это использование подразумеваемых и явных объединений в одном запросе. Это может привести к ошибкам, и этого никогда не следует делать. На самом деле нет оправдания для использования подразумеваемого синтаксиса.

3. Вы также смешиваете стили соединений. Это может быть сделано намеренно, но это также затрудняет чтение для людей. Почему оба «из tablex, tabley, tablez», а также «внутренняя таблица jion с левым внешним соединением tableb» и так далее?

Ответ №1:

Моя попытка помочь людям ответить, отформатировав ваш запрос и избавившись от смешанного синтаксиса. На самом деле это не ответ, но слишком длинный для комментария:

     SELECT s.LAST_NAME || ', ' || s.FIRST_NAME || ' ' || COALESCE(s.MIDDLE_NAME,' ') 
      AS FULL_NAME,
    s.LAST_NAME, s.FIRST_NAME, s.MIDDLE_NAME, s.STUDENT_ID, 
    ssm.SCHOOL_ID, ssm.SCHOOL_ID AS LIST_SCHOOL_ID, ssm.GRADE_ID ,
    sg1.BENCHMARK_ID, sg1.GRADE_TITLE, sg1.COMMENT AS COMMENT_TITLE,
    ssm.STUDENT_ID, sg1.MARKING_PERIOD_ID, sg1.LONGER_COURSE_COMMENTS,
    sp.SORT_ORDER, sched.COURSE_PERIOD_ID 
    FROM STUDENTS s
      INNER JOIN STUDENT_ENROLLMENT ssm
        ON ssm.STUDENT_ID=s.STUDENT_ID   -- moved from WHERE to here
      INNER JOIN SCHEDULE sched 
        ON sched.STUDENT_ID=ssm.STUDENT_ID -- moved from WHERE to here
      LEFT OUTER JOIN STUDENT_REPORT_CARD_BENCHMARKS sg1 
        ON (    sg1.STUDENT_ID=sched.STUDENT_ID 
            AND sched.COURSE_PERIOD_ID=sg1.COURSE_PERIOD_ID 
            AND sg1.MARKING_PERIOD_ID IN ('0','442','445','450') 
            AND sg1.SYEAR=sched.SYEAR) 
      LEFT OUTER JOIN COURSE_PERIODS rc_cp 
        ON (    rc_cp.COURSE_PERIOD_ID=sg1.COURSE_PERIOD_ID 
            AND rc_cp.DOES_GRADES='Y') 
      LEFT OUTER JOIN SCHOOL_PERIODS sp 
        ON (sp.PERIOD_ID=rc_cp.PERIOD_ID) 
    WHERE ssm.SCHOOL_ID='1'  
      AND ssm.SYEAR='2010' 
      AND ('22-APR-11' BETWEEN ssm.START_DATE AND ssm.END_DATE 
           OR (ssm.END_DATE IS NULL))  
      AND (  LOWER(s.LAST_NAME) LIKE 'la''porsha%' 
           OR LOWER(s.FIRST_NAME) LIKE 'la''porsha%' ) 
    AND sched.MARKING_PERIOD_ID 
         IN  ('0','444','446','447','445','448','450','443','449') 
    AND (   '22-APR-11' BETWEEN sched.START_DATE AND sched.END_DATE 
         OR (     sched.END_DATE IS NULL
             AND '22-APR-11' >= sched.START_DATE))     
ORDER BY s.LAST_NAME, s.FIRST_NAME
  

Надеюсь, это поможет.

Ответ №2:

Ну, конечно, у вас есть несколько записей, если дочерние таблицы объединены, чтобы иметь несколько записей для одного и того же пользователя. Это ожидаемое и правильное поведение.

Если вам нужна только одна запись на пользователя, то вы должны изменить запрос, чтобы указать ему, какую из множества дочерних записей вы хотите, чтобы он выбрал. Но почему бы вам не захотеть просмотреть все запланированные курсы для этого человека, а не только один?

Если необходимо, вы могли бы использовать group by, а затем поместить агрегат (например, min или max) в поля, которые приводят к появлению нескольких записей. Однако вам все равно нужно знать, нужны ли вам только записи первого периода или записи последнего периода, или как бы вы решили из шести записей для пользователя, какую из них вы хотите увидеть?

Комментарии:

1. Спасибо… оказалось, что это был правильный запрос, но он был помещен не в то место : (переместив его на более поздний этап, я получил результаты, которые мне были нужны.

Ответ №3:

Посмотрите на group by предложение.