Я не понимаю, почему моя группа терпит неудачу - PullRequest
0 голосов
/ 15 декабря 2018
SELECT ENAME, MAX(SAL), STORES.CITY 
FROM EMPLOYEES 
INNER JOIN STORES ON EMPLOYEES.STORE_ID = STORES.STORE_ID
GROUP BY EMPLOYEES.STORE_ID, STORES.CITY

DDL для STORES:

CREATE TABLE  "STORES" 
(   
    "STORE_ID" NUMBER NOT NULL ENABLE, 
    "CITY" VARCHAR2(50), 
     PRIMARY KEY ("STORE_ID")
     USING INDEX  ENABLE
)
/

DDL для EMPLOYEES:

CREATE TABLE  "EMPLOYEES" 
(   
    "EMPNO" NUMBER(4,0), 
    "ENAME" VARCHAR2(10), 
    "JOB" VARCHAR2(9), 
    "HIREDATE" DATE, 
    "SAL" NUMBER(7,2), 
    "COMM" NUMBER(7,2), 
    "STORE_ID" NUMBER
)
/

CREATE INDEX  "EMP_NAME_IDEX" ON  "EMPLOYEES" ("ENAME")
/

CREATE INDEX  "EMP_NAME_JOB_DATE_IDX" ON  "EMPLOYEES" ("ENAME", "JOB", "HIREDATE")
/

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

Желаемый результат:

  • Отображение ТОП-сотрудника, оплачиваемого в каждом магазине
  • STORE_ID - 1 не имеет сотрудников, поэтому нетнет в отчете

Примерно так:

ENAME   JOB      STORE_ID   MAX(SAL)    CITY
------------------------------------------------------
ALLEN   SALESMAN    2        1600       New York City
KING    PRESIDENT   3        5000       Chicago
SCOTT   ANALYST     4        3000       Philadelphia

Токовый выход:

ENAME   JOB     STORE_ID    MAX(SAL)    CITY
------------------------------------------------------------
ALLEN   SALESMAN    2       1600    New York City
TURNER  SALESMAN    2       1500    New York City
WARD    SALESMAN    2       1250    New York City
MARTIN  SALESMAN    2       1250    New York City
KING    PRESIDENT   3       5000    Chicago
BLAKE   MANAGER     3       2850    Chicago
CLARK   MANAGER     3       2450    Chicago
SCOTT   ANALYST     4       3000    Philadelphia
FORD    ANALYST     4       3000    Philadelphia
JONES   MANAGER     4       2975    Philadelphia
MILLER  CLERK       4       1300    Philadelphia
ADAMS   CLERK       4       1100    Philadelphia
JAMES   CLERK       4        950    Philadelphia
SMITH   CLERK       4        800    Philadelphia

Ответы [ 5 ]

0 голосов
/ 16 декабря 2018

Как уже объяснили другие: «Вы не можете съесть свой пирог и съесть его».
Вы либо группируете по что-то, и можете вернуть его как есть, либо что-то собрать.В вашем случае вы хотите группировать по магазинам, то есть иметь отдельную строку результатов для магазина (которая соответствует критериям внутреннего объединения), но не по сотруднику.В этом случае должны быть агрегированы данные сотрудника, которые включают имя.
Классическая агрегация берет все записи в группе, поэтому вы должны использовать все имена сотрудников в агрегации, а это не то, что вам нужно, а простосотрудник с максимальной зарплатой.

К счастью, в Oracle DB есть что-то для таких случаев (хотя, возможно, не для всех), и это модификатор агрегатных функций KEEP с его DENSE_RANK иLAST / FIRST.
Эта конструкция позволяет выполнять агрегирование на подмножестве строк в группе, где то, что вы KEEP в агрегации, составляет FIRST или LAST вназначенный рейтинг (на основе заданных критериев заказа).В вашем случае вам нужно будет заказать сотрудников в группе (сотрудников магазина) на основе критерия заработной платы, и таким образом агрегация будет ограничена наиболее высокооплачиваемыми сотрудниками.Предполагая, что зарплаты являются уникальными значениями (которые они обычно не являются), это даст вам подгруппу из одного сотрудника, так что вы можете применить любую агрегацию, которую вы хотите (часто MAX или MIN), и все же получить этоодно имяЕсли предположить, что значения заработной платы не являются уникальными, то может быть более одного сотрудника с максимальной зарплатой - на первом месте есть связь.В этом случае вы либо вводите тай-брейк в порядок ранжирования (например, второстепенные критерии после зарплаты могут быть именем работы), либо решаете проблему на уровне агрегации (например, выбирая сотрудника MAX или MINимя).

В целом мы получаем что-то вроде этого:

SELECT MAX(e.ename)
         KEEP (DENSE_RANK FIRST ORDER BY e.sal DESC NULLS LAST, e.job) AS name,
       MIN(e.job)
         KEEP (DENSE_RANK FIRST ORDER BY e.sal DESC NULLS LAST, e.job) AS job,
       e.store_id,
       MAX(e.sal) AS salary,
       s.city
  FROM employees e
 INNER JOIN stores s ON e.store_id = s.store_id
 GROUP BY e.store_id, s.sity
0 голосов
/ 15 декабря 2018

Таким образом, хотя существует много ответов, которые содержат исправления в вашем коде, ни один из них не отвечает на вопрос о том, почему происходит сбой в GROUP BY.

Ответ таков: предложение GROUP BY может использоваться толькона столбцы, которые явно указаны в запросе после предложения SELECT.Таким образом, вы выбираете столбцы, которые вы хотите вернуть, а затем группируете их по одному или нескольким из этих выбранных столбцов.Если GROUP BY содержит столбцы, которые не выбраны в SELECT, то у них нет этих столбцов для группировки данных.Распространенным заблуждением является убеждение, что запрос будет обрабатывать всю базу данных как данные, которые присутствуют во всех предложениях оператора SQL.Реальность такова, что GROUP BY действует только на результат SELECT.

Следующие работы, потому что все столбцы, используемые в GROUP BY, запрашиваются SELECT:

SELECT COL1, COL2, COL3 FROM MYTABLE GROUP BY COL2, COL3

но следующее не работает, потому что COL4 в GROUP BY не запрашивается SELECT:

SELECT COL1, COL2, COL3 FROM MYTABLE GROUP BY COL2, COL4

0 голосов
/ 15 декабря 2018

В группе по номеру списка выбора необходимо поместить в группу по пункту

SELECT ENAME, MAX(SAL), STORES.CITY FROM EMPLOYEES 
INNER JOIN STORES 
ON EMPLOYEES.STORE_ID = STORES.STORE_ID
GROUP BY EMPLOYEES.STORE_ID,ENAME,STORES.CITY

Когда вы выбираете ENAME, но не включаете его в группу, в результате выдается ошибка

Когда вы меняете вывод, то ниже будет работать ваш вывод на изменение

  with cte as
       ( select e.ENAME,SAL,CITY
       , row_number() over(partition by e.STORE_ID order by e.sal desc) rn
       FROM EMPLOYEES e
        INNER JOIN STORES  s  ON e.STORE_ID = s.STORE_ID
      ) select ENAME,SAL,CITY from cte where rn=1
0 голосов
/ 15 декабря 2018

Вы можете преобразовать его в:

SELECT ENAME, MAX(SAL), STORES.CITY FROM EMPLOYEES 
INNER JOIN STORES 
ON EMPLOYEES.STORE_ID = STORES.STORE_ID
GROUP BY ENAME, STORES.CITY

или

SELECT EMPLOYEES.STORE_ID, MAX(SAL), STORES.CITY FROM EMPLOYEES 
INNER JOIN STORES 
ON EMPLOYEES.STORE_ID = STORES.STORE_ID
GROUP BY EMPLOYEES.STORE_ID, STORES.CITY

, поскольку в вашем случае оператор SQL Select имеет несгруппированные и неагрегированные столбцы в selectсписок, это нарушение правил.А для вашей цели может предпочесть следующее:

SELECT ENAME, MAX(SAL), STORES.STORE_ID, STORES.CITY FROM EMPLOYEES 
INNER JOIN STORES 
ON EMPLOYEES.STORE_ID = STORES.STORE_ID
GROUP BY ENAME, STORES.STORE_ID, STORES.CITY
0 голосов
/ 15 декабря 2018

Вам необходимо удалить ENAME или добавить ENAME к GROUP BY

SELECT MAX(SAL), STORES.CITY FROM EMPLOYEES 
INNER JOIN STORES 
ON EMPLOYEES.STORE_ID = STORES.STORE_ID
GROUP BY EMPLOYEES.STORE_ID, STORES.CITY

или

SELECT ENAME, MAX(SAL), STORES.CITY FROM EMPLOYEES 
INNER JOIN STORES 
ON EMPLOYEES.STORE_ID = STORES.STORE_ID
GROUP BY EMPLOYEES.STORE_ID,ENAME, STORES.CITY
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...