我的sql查询到oracle查询转换

时间:2017-12-15 12:26:55

标签: mysql sql oracle aggregate-functions

我有以下数据库结构

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;

对于至少有两个订单的产品(总体而言,不论付款方式如何),显示产品ID,产品名称,现金支付的销售订单数量(标题:Num现金销售额),总销售订单数量(标题: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

任何人都可以帮忙。

3 个答案:

答案 0 :(得分:1)

Group by的Oracle实施是标准的:

  

在标准SQL中,包含GROUP BY子句的查询无法引用   选择列表中未分配的非聚合列   GROUP BY子句。例如,此查询在标准SQL中是非法的   因为选择列表中的名称列不会出现在   GROUP BY:

     

要使查询合法,必须从中省略name列   选择列表或在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; 

答案 1 :(得分:0)

您按产品ID分组,并希望同时显示产品名称。这适用于MySQL,因此在SQL标准中定义。产品名称由产品ID唯一标识,因此对此没有任何意见。但是,Oracle要求您按产品名称进行分组。情况可能就是这样,因为在某些情况下(不是这里)很难确定属性之间的功能依赖性。

您的第一个子查询无效。您为记录计数选择了一行(为了便于阅读,应该count(*)而不是count(saleno)),但也请选择salesno。但是,可以有多个salesno,因此您可以随意选择一个。这在MySQL中是可行的,但它实际上是一个缺陷。在最近的MySQL版本中,如果要执行此操作,则必须使用ANY_VALUE(saleno)。在Oracle中,这是无效的,因为它应该符合SQL标准。 Oracle不支持ANY_VALUE,但您可以使用MIN(saleno)MAX(saleno)。但是,您可能希望按照saleno进行分组,以便每次销售一行?

只有一个a记录,Oracle会再次要求您将NumCashSales放入GROUP BY。每asaleno条记录,您甚至必须应用一些汇总,例如每个产品SUM(a.NumCashSales)

然后您的联接不正确。它们必须立即跟随ON子句,这在您的查询中不是这种情况。 MySQL让我们忽略了这一点并违反了SQL标准。

首先直接获取原始查询。然后将pName添加到GROUP BY以遵守Oracle的限制,您就完成了。

答案 2 :(得分:0)

您认为您的问题是从MySQL到Oracle的查询转换失败。你错了。您的问题是您的查询存在缺陷(Oracle主要告诉您,MySQL应该首先执行此操作)。嗯,诚然,DBMS无法告诉您一些问题,例如订购的订单数量不是订单中的行数。

这是查询。这很简单。您加入所有表并聚合。只是,为了获得现金销售,您需要有条件的汇总。无需外部连接。不需要子查询。

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,应该适用于每个RDBMS。它适用于MySQL,适用于Oracle。

正如我在其他答案中所提到的,GROUP BY p.pname仅出现在Oracle的查询中;它既不是MySQL也不是SQL标准所必需的。