2010-07-06 1 views
4

У меня есть запрос, который работает на MySQL, но не работает на Oracle, и я пытаюсь преобразовать. Это мой стол:«group by» работает на MySQL, но не на Oracle

unique_row_id http_session_id page_name page_hit_timestamp 
---------------------------------------------------------------- 
0    123456789  index.html 2010-01-20 15:00:00 
1    123456789  info.html 2010-01-20 15:00:05 
2    123456789  faq.html 2010-01-20 15:00:15 
3    987654321  index.html 2010-01-20 16:00:00 
4    987654321  faq.html 2010-01-20 16:00:05 
5    987654321  info.html 2010-01-20 16:00:15 
6    111111111  index.html 2010-01-20 16:01:00 
7    111111111  faq.html 2010-01-20 16:01:05 
8    111111111  info.html 2010-01-20 16:01:15 

SQL, является

select http_session_id, unique_row_id, page_name, page_hit_timestamp 
from page_hits 
group by http_session_id; 

В MySQL, это вернет 3 строки (по одному для каждого уникального http_session_id).

В Oracle я получаю сообщение «ORA-00979: не выражение GROUP BY». Я тоже пробовал играть с отличным, но я не могу заставить его работать.

Просто, чтобы быть ясным - мне нужен ResultSet, содержащий одну строку на уникальный http_session_id. Предпочтительно, чтобы unique_row_id был максимальным (например, 2 для http_session_id == 123456789), но это не имеет значения.

Я нахожусь на грани разбивки на несколько отдельных операторов sql (один «выберите отдельный http_session_id», а другой - итерацию по всем этим и выберите max (unique_row_id). Любые указатели будут с благодарностью приняты - I хотел бы избежать этого!

Rgds, Кевин.

ответ

2

эта работа:

select max(unique_row_id), http_session_id 
from page_hits 
group by http_session_id 

Кстати; что мой sql возвращает в вашем наборе результатов для columsn, которые включены в набор результатов, но не в предложение group by? (page_name, page_hit_timestamp)

+0

Hi - да, это делает трюк. В полном объеме: выберите http_session_id, max (unique_row_id), max (page_name), max (page_hit_timestamp) из группы page_hits по http_session_id; – Kevin

+0

И чтобы ответить на ваш вопрос о том, что делает MySQL: - Кажется, он возвращает столбцы из строки, связанной с первым сопоставлением http_session_id. Я не могу быть уверенным, потому что я не испытывал слишком много - он вполне мог вернуться последним в разных условиях. – Kevin

+0

yep, я перейду к первому (page_name). – Kevin

0

Я думаю, что GROUP BY требует переменной, были использованы в выражении WHERE или агрегации функции в стандарте SQL?

Попробуйте использовать SELECT MAX(unique_row_id) GROUP BY http_session_id .

10

Причина, по которой вы столкнулись с ошибкой ORA, заключается в том, что MySQL поддерживает нестандартные предложения GROUP BY, называя это «функцией». Это documented here.

Стандарта SQL-предложения GROUP BY должна включать ВСЕХ столбцов, указанных в ЗЕЬЕСТЕ, которые не обернутых в совокупности функций (например, COUNT, MAX/MIN, и т.д.), необходимо указать в GROUP BY пункта ,

Если вы хотите один, уникальный ряд на http_session_id значения - посмотреть на использование ROW_NUMBER:

SELECT x.* 
    FROM (select http_session_id, unique_row_id, page_name, page_hit_timestamp, 
       ROW_NUMBER() OVER (PARTITION BY http_session_id 
             ORDER BY http_session_id) AS rank 
      FROM page_hits) x 
WHERE x.rank = 1 
+0

Вы можете добавить ORDER BY в ROW_NUMBER, если хотите изменить, какая строка возвращается. MySQL не имеет аналитических/оконных/ранговых функций, поэтому вы не можете перенести запрос обратно в MySQL. Я боюсь :( –

+0

Спасибо за всесторонний ответ - полезно понять, что MySQL Group By не является стандартным. BTW - Я получил ошибку ORA-30485, выполняющую указанное предложение select. – Kevin

+0

Я считаю, что выбор - синтаксис SQL Server. –

0

В стандартном SQL, если у вас есть предложения GROUP BY, все столбцы, которые не являются частью его должен быть в совокупности. В MySQL это правило было смягчено дизайном.

Например, это разрешено в MySQL, но не в стандартном SQL:

SELECT customer_id, country, SUM(amount) FROM records GROUP BY customer_id 

Там в один нюанс: MySQL предполагает, что вы знаете, что вы делаете. Если у одного и того же клиента есть записи в нескольких странах, запрос просто захватит первую страну в таблице, не обращая внимания на все остальные. Кроме того, поскольку порядок строк не определен, и нет ORDER BY, вы можете получать разные результаты при каждом запуске запроса.

В стандартном SQL, у вас есть два варианта:

SELECT customer_id, country, SUM(amount) FROM records GROUP BY customer_id, country 

или

SELECT customer_id, MIN(country), SUM(amount) FROM records GROUP BY customer_id 
0

Другой вариант в Oracle, если вы хотите:

select DISTINCT 
     FIRST_VALUE(unique_row_id) 
     OVER (PARTITION BY http_session_id 
      ORDER BY unique_row_id DESC) unique_row_id, 
     http_session_id, 
     FIRST_VALUE(page_name) 
     OVER (PARTITION BY http_session_id 
      ORDER BY unique_row_id DESC) page_name, 
     FIRST_VALUE(page_hit_timestamp) 
     OVER (PARTITION BY http_session_id 
      ORDER BY unique_row_id DESC) page_hit_timestamp 
from page_hits; 

Это позволит получить определенный набор от http_session_id, и для каждого возвращает unique_row_id, page_name и page_hit_timestamp из строки с наибольшим unique_row_id для этого http_session_id и т.д .:

unique_row_id http_session_id page_name page_hit_timestamp 
---------------------------------------------------------------- 
2    123456789  faq.html 2010-01-20 15:00:15 
5    987654321  info.html 2010-01-20 16:00:15 
8    111111111  info.html 2010-01-20 16:01:15