Мой SQL-запрос к оракулу преобразования запросов

0

У меня ниже структуры базы данных

CREATE TABLE CUSTOMERS (
 custid char(4) constraint cust_pk primary key,
 firstname varchar(20),
 lastname varchar(25),
 city varchar(20),
 country varchar(20),
 creditlimit number(8,2)
);

CREATE TABLE PRODUCTS (
 prodID char(4) constraint prod_pk primary key,
 pname varchar(20),
 description varchar(50),
 category varchar(7), -- product category
 listprice numeric(5,2), -- list price
 weight numeric(4,1) -- weight 
);

CREATE TABLE SALES (
 saleno char(5) constraint sales_pk PRIMARY KEY,
 sdate date,
 paymentmethod varchar(20),
 custid char(4),
 constraint sales_fk_cust FOREIGN KEY (custid) references CUSTOMERS
);


CREATE TABLE SALESLINES (
 saleno char(5),
 prodid char(4),
 qty numeric(5),
 unitprice numeric(5,2),
 constraint sales_lines_pk PRIMARY KEY (saleno, prodid),
 constraint saleslines_fk_sale FOREIGN KEY (saleno) references SALES,
 constraint saleslines_fk_prod FOREIGN KEY (prodid) references PRODUCTS
);



INSERT INTO CUSTOMERS VALUES('C002', 'Ruby', 'Ringer','Springfield', 'Canada',125000);
INSERT INTO CUSTOMERS VALUES('C003', 'Bob', 'Bennett','Tucson','USA',50000);
INSERT INTO CUSTOMERS VALUES('C004', 'Pat', 'Rowling','Ottowa','Canada', 129000);
INSERT INTO CUSTOMERS VALUES('C905', 'Sue', 'Smith','Riverside','USA', 125000);
INSERT INTO CUSTOMERS VALUES('C005', 'Jim', 'Jason','New York', 'USA',25000);
INSERT INTO CUSTOMERS VALUES('C101', 'Darcy', 'Doe','Tucson','USA', 14500);
INSERT INTO CUSTOMERS VALUES('C104', 'Dan', 'Doe','Hermosillo','Mexico',10100);
INSERT INTO CUSTOMERS VALUES('C505', 'Sue', 'Smith','Tucson','USA', 19500);
INSERT INTO CUSTOMERS VALUES('C125', 'Bill', 'Jackson','Vancouver','Canada', 75000);




INSERT INTO PRODUCTS VALUES ('P051', '19" Monitor', 'Widescreen, black', 'Display', 114.95, 17.5);
INSERT INTO PRODUCTS VALUES ('P055', '27" Monitor', 'Widescreen, LCD ultra-sharp', 'Display', null, 50);
INSERT INTO PRODUCTS VALUES ('P012', 'Keyboard', 'Black, full size keys', 'Input', 14.75, 2);
INSERT INTO PRODUCTS VALUES ('P011', 'Keyboard', 'Ergonomic, soft touch keys', 'Input', 45.25, 2.5);
INSERT INTO PRODUCTS VALUES ('P074', 'Optical Mouse', '2-button mouse, basic', 'Input', 9.99, 1);
INSERT INTO PRODUCTS VALUES ('P075', 'Optical Mouse', 'Compact notebook optical mouse', 'Input', 24.99, 0.5);
INSERT INTO PRODUCTS VALUES ('P208', 'Microphone', 'USB microphone, desktop', 'Audio', 22.95, 2.5);
INSERT INTO PRODUCTS VALUES ('P210', 'Speakers', '2-speaker, stereo, 10W', 'Audio', 39.99, 7.5);
INSERT INTO PRODUCTS VALUES ('P010', 'Classic Keyboard', 'Black, spill resistant design', 'Input', 21.50, null);
INSERT INTO PRODUCTS VALUES ('P302', 'Inkjet Printer', 'Color and B/W modes, wireless support', 'Print', 89.99, null);
INSERT INTO PRODUCTS VALUES ('P304', 'Laser Printer', 'Color heavy-duty printer', 'Print', 119.50, 25);
INSERT INTO PRODUCTS VALUES ('P312', 'Letter Paper', 'Multipurpose 20lb, 500 sheets', 'Print', 7.50, 5);
INSERT INTO PRODUCTS VALUES ('P046', 'Screen cover', 'Dust protection unit', 'Display', 12.50, null);
INSERT INTO PRODUCTS VALUES ('P215', 'Speakers', 'Mono output, 5W', 'Audio', null, 5.5);
INSERT INTO PRODUCTS VALUES ('P235', 'Audio Pak', 'Speakers and Microphone', 'Audio', 35.95, 10);
INSERT INTO PRODUCTS VALUES ('P322', 'Printer Ink', 'Replacement Cartridges', 'Print', 30, 4);


INSERT INTO SALES VALUES('AX014','01-Mar-2017','Check',  'C002');
INSERT INTO SALES VALUES('CQ951','03-Oct-2016','Cash',   'C005');
INSERT INTO SALES VALUES('BC001','18-Feb-2017','Credit', 'C003');
INSERT INTO SALES VALUES('CB714','21-Sep-2014','PayPal', 'C101');
INSERT INTO SALES VALUES('BM701','04-Mar-2017','GWallet','C002');
INSERT INTO SALES VALUES('LC294','04-Apr-2015','Credit', 'C005');
INSERT INTO SALES VALUES('MB720','04-Oct-2015','PayPal', 'C104');

INSERT INTO SALESLINES VALUES ('AX014','P010',3,19.35);
INSERT INTO SALESLINES VALUES ('AX014','P012',2,14.75);
INSERT INTO SALESLINES VALUES ('AX014','P312',2,7.5);
INSERT INTO SALESLINES VALUES ('AX014','P011',10,40);
INSERT INTO SALESLINES VALUES ('CQ951','P011',4,54.3);
INSERT INTO SALESLINES VALUES ('CQ951','P046',50,11.25);
INSERT INTO SALESLINES VALUES ('BC001','P011',4,40.73);
INSERT INTO SALESLINES VALUES ('BC001','P074',4,8.99);
INSERT INTO SALESLINES VALUES ('BC001','P046',3,12.5);
INSERT INTO SALESLINES VALUES ('BC001','P322',5,30);
INSERT INTO SALESLINES VALUES ('CB714','P011',5,45.25);
INSERT INTO SALESLINES VALUES ('CB714','P302',3,89.99);
INSERT INTO SALESLINES VALUES ('MB720','P011',5,45);
INSERT INTO SALESLINES VALUES ('MB720','P302',3,90);
INSERT INTO SALESLINES VALUES ('BM701','P208',3,32.13);
INSERT INTO SALESLINES VALUES ('LC294','P051',1,103.46);
INSERT INTO SALESLINES VALUES ('LC294','P302',3,89.99);
INSERT INTO SALESLINES VALUES ('LC294','P235',5,43.14);
INSERT INTO SALESLINES VALUES ('LC294','P322',2,33);
INSERT INTO SALESLINES VALUES ('LC294','P312',4,6.75);
INSERT INTO SALESLINES VALUES ('LC294','P010',3,23.65);
INSERT INTO SALESLINES VALUES ('LC294','P074',4,13.99);



commit;

Для продуктов с не менее чем двумя заказами (в целом, независимо от способов оплаты) отображать идентификатор продукта, название продукта, количество заказов на продажу, оплаченное наличными (заголовок: Num Cash Sales), количество заказов на продажу в целом (заголовок: Num Общие продажи)

Я написал ниже запрос

select sl.prodid, p.pName, a.NumCashSales,count(sl.prodid) as NumOverallSales 
from 
(select count(saleno) as  NumCashSales, saleno as salesno 
    from sales where paymentmethod = 'Cash'
) a 
    Right Outer join saleslines sl 
    Join PRODUCTS p
on sl.prodid = p.prodid 
on sl.saleno= a.salesno

group by sl.prodid 
having count(sl.prodid) >=2; 

он работает на mysql, но на oracle он дает ошибку, как

ORA-00979: не выражение GROUP BY 00979. 00000 - "не выражение GROUP BY" * Причина: * Действие: Ошибка в строке: 1 Колонка: 19

Кто-нибудь может помочь.

Теги:
aggregate-functions

3 ответа

1

Внедрение Oracle Group by является стандартным:

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

Чтобы запрос был законным, столбец имен должен быть опущен из списка выбора или назван в предложении GROUP BY.

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

Так что это должно работать

select sl.prodid, p.pName, a.NumCashSales,count(sl.prodid) as 
  NumOverallSales 
from 
  (select count(saleno) as  NumCashSales, saleno as salesno 
     from sales where paymentmethod = 'Cash'
  ) a 
  Right Outer join saleslines sl 
     on sl.saleno= a.salesno
  Join PRODUCTS p  
     on sl.prodid = p.prodid 

 group by sl.prodid,p.pName, a.NumCashSales 
 having count(sl.prodid) >=2; 
  • 0
    сгруппировать по sl.prodid, p.pName, a.NumCashSales * и вывести их как ERROR в строке 11: ORA-00905: пропущено ключевое слово
  • 0
    убирайся, как указано выше. Недостающий ключ
Показать ещё 4 комментария
0

Вы считаете, что ваша проблема заключается в том, что сбой запроса от MySQL к Oracle. Вы неправы. Ваша проблема в том, что ваш запрос испорчен (и Oracle в основном говорит вам об этом, что MySQL должен был сделать в первую очередь). Ну, по общему признанию, есть некоторые проблемы, которые СУБД не может вам сказать, например, количество заказанных штук - это не количество строк в заказе.

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

select
  p.prodid,
  p.pname,
  sum(sl.qty) as num_overall_sales,
  sum(case when s.paymentmethod = 'Cash' then sl.qty end) as num_cash_sales
from sales s 
join saleslines sl on sl.saleno = s.saleno
join products p on p.prodid = sl.prodid 
group by p.prodid, p.pname
having count(distinct s.saleno) >= 2;

Этот запрос является стандартным SQL и должен работать в каждой СУБД. Он работает в MySQL и работает в Oracle.

Как упоминалось в моем другом ответе, GROUP BY p.pname находится только в запросе для Oracle sake; он не требуется ни MySQL, ни стандартом SQL.

0

Вы группируете по идентификатору продукта и хотите показать название продукта. Это работает в MySQL и определяется таким образом в стандарте SQL. Имя produt уникально идентифицируется идентификатором продукта, поэтому в этом нет ничего. Однако Oracle требует, чтобы вы также группировались по названию продукта. Это, вероятно, так, потому что в некоторых ситуациях (не здесь) трудно определить функциональную зависимость между атрибутами.

Ваш первый подзапрос недействителен. Вы выбираете одну строку с подсчетом записи (которая должна count(*) не count(saleno) для читаемости), но также и select salesno. Однако может быть несколько salesno, поэтому вы произвольно выбираете один. Это возможно в MySQL, но на самом деле это недостаток. В последних версиях MySQL вам нужно будет использовать ANY_VALUE(saleno) если вы хотите это сделать. В Oracle это недопустимо, так как это должно соответствовать стандарту SQL. Oracle не использует ANY_VALUE, но ANY_VALUE этого вы можете использовать MIN(saleno) или MAX(saleno). Может быть, однако, вы скорее хотите сгруппировать салено вместо того, чтобы получить ряд за салено?

С одной только a записи, Oracle снова потребует вы положили NumCashSales Into GROUP BY. С одной рекорда за a saleno вы даже применить некоторые агрегации, например, SUM(a.NumCashSales) для каждого продукта.

Тогда ваши соединения неверны. За ними немедленно следует предложение ON, что не соответствует вашему запросу. MySQL позволяет этому промаху незаметно и нарушает стандарт SQL здесь.

Поэтому сначала получите свой первоначальный запрос. Затем добавьте pName в GROUP BY чтобы подчиниться ограничению Oracle, и все готово.

  • 0
    Спасибо! Можете ли вы поделиться запросом.
  • 0
    Попробуйте сначала :-) Ваша главная проблема заключается в том, что ваш текущий запрос учитывает все продажи за наличный расчет, но произвольно занимает одно кассовое сало и его продукты. Вы действительно этого хотите? Если нет, что вы хотите вместо этого?
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню