在没有子查询的情况下重写SQL查询(having子句中的子查询)

时间:2012-06-22 14:51:06

标签: sql join subquery relational-algebra

在我的期末考试中,我得到了相当讨厌的SQL,关系代数和关系微积分查询。我收到了这个问题:

查找从“计算机”类别订购所有产品的客户的名称。 (订购计算机类别中每件产品的客户)

这是架构:

客户( Customer_Id ,Cust_First_Name,Cust_Last_Name)

订单( Order_Id ,* Customer_Id *)

Order_items( Order_Item_id ,* Order_Id *,* Product_Id *)

Product_info( Product_Id ,Product_Name,Category)

粗体(主键),斜体(外键)

现在将此查询转换为关系代数我需要使用连接而不是子查询。为了帮助自己,我首先编写SQL然后将SQL查询转换为关系代数。

以下是我的尝试:

尝试1(使用子查询):

select C.Customer_Id
from Customer C
where
(
select count(*)
from product_info
where category = 'Computer'
)=(select count (distinct pi.Product_id)
from orders S, order_items OI, product_info pi
where S.Customer_Id = C.Customer_Id and S.Order_Id = OI.Order_Id and  pi.product_id=OI.product_id and category = 'Computer')

尝试2(在having子句中使用一个子查询):

select C.Customer_Id
from Customer C, Product_info pi, Orders S, Order_Items oi
where C.Customer_Id = S.Customer_Id and S.Order_Id = OI.Order_Id and OI.Product_Id = pi.Product_Id and pi.category = 'Computer'
group by C.Customer_Id
having count (distinct pi.Product_Id) = 
(
select count (*) 
from Product_info
where category = 'Computer'
)

尝试3(from子句中的子查询):

select C.Customer_Id
from Customer C, Product_info pi, Orders S, Order_Items oi,
(
select count (*) num
from Product_info
where category = 'Computer'
) numbr
where C.Customer_Id = S.Customer_Id and S.Order_Id = OI.Order_Id and OI.Product_Id = pi.Product_Id and pi.category = 'Computer'
group by C.Customer_Id, numbr.num
having count (distinct pi.Product_Id) = numbr.num

现在这个查询可以在关系代数中表示,但它效率很低,因为它复制了值。

我的最后一次尝试(不编译并在其中使用子查询):

select *
from Customer C
where not exists
(select *
from (select Order_Id from orders O where O.Customer_Id = C.Customer_Id) S INNER JOIN order_items OI on S.Order_Id = OI.Order_Id
RIGHT OUTER JOIN (select Product_Id from product_info where category ='Computer') PI on PI.Product_Id = OI.Product_Id
where OI.Product_Id = null)

我在某处读过,在这种情况下可以使用LATERAL,但关于LATERAL的信息很少,我无法正确使用。

考试结束了,但我仍对这些解决方案感兴趣。因为这是2小时的考试,其中有6个查询,ER图,ER-To-Relational,归一化到BCNF,3NF,我想到这个查询怎么这么难以解决。我错过了一些关键的东西吗?

以下是一些小样本数据,对我有所帮助:

http://pastebin.com/DkCe0AGm

提前致谢。

2 个答案:

答案 0 :(得分:2)

在关系代数中使用除法运算符非常容易。你应该注意,只是因为你可以在关系代数中编写的任何东西都可以在SQL中编写,这并不意味着你可以在关系代数中编写任何东西,你可以在SQL中以相​​同的方式编写 。 SQL没有简单的等效除法运算符,所以首先尝试在SQL中编写它不会有帮助。

由于我不知道如何在这里做希腊字母,我只想写出一些东西。

  

Sigma - > SELECT
  Pi - >项目
  Rho - > RENAME

PROJECT c.Cust_First_Name, c.Cust_Last_Name, i.Product_ID (SELECT c.customer_id = o.customer_id, o.order_id = i.order_id (RENAME (Customer c) X RENAME (Orders o) X RENAME (Order_items i))) 
DIVIDE PROJECT p.product_id (SELECT p.category = 'Computers' (RENAME (Products p)))

如果你在LaTeX编辑器中输入它,你会看到它的实际形式:

\Pi_{c.cust\_last\_name, c.cust\_first\_name, i.product\_id} (\sigma_{c.customer\_id = o.customer\_id, o.order\_id = i.order\_id}(\rho_{c}(customer) X \rho_{o}(orders) X \rho_{i}(order\_items))) 
\div  \Pi_{p.product\_id}(\sigma_{p.category='computers'}(\rho_{p}(products)))

你可能可能认为这是一个子查询,但我想说这只是两个不同的查询。

答案 1 :(得分:1)

我觉得这个问题含糊不清。此版本仅为从计算机类别订购产品的客户提供:

select c.customer_id, c.Cust_First_Name, c.Cust_Last_Name
from Customer c join
     Orders o
     on c.customer_id = o.customer_id join
     Order_Item oi
     on o.order_Id = oi.order_id join
     Product_Info pi
     on oi.Product_id = pi.product_id
group by c.customer_id, c.Cust_First_Name, c.Cust_Last_Name
having min(case when pi.category = 'Computer' then 1 else 0 end) = 1

在这种情况下,我只是计算客户是否有任何未在该类别中购买的产品。

另一种解释是“订购计算机类别中每件产品的客户”:

select c.customer_id, c.Cust_First_Name, c.Cust_Last_Name
from Customer c join
     Orders o
     on c.customer_id = o.customer_id join
     Order_Item oi
     on o.order_Id = oi.order_id join
     Product_Info pi
     on pi.Product_id = oi.Product_id cross join
     (select count(distinct product_id) as cnt
      from Product_info pi
      where category = 'Computer'
     ) comps
where pi.Category = 'Computer'
group by c.customer_id, c.Cust_First_Name, c.Cust_Last_Name
having count(distinct product_id) = comps.cnt

在这种情况下,我们的想法是计算不同产品的数量,并查看计数是否匹配。

我不确定将这些转换为关系代数实际上是否有助于形成一个好的查询。