查询只返回一个值,它应该返回2

时间:2014-06-27 20:01:50

标签: mysql sql

我有以下表格。

CREATE TABLE `Customer` (
`CID` varchar(10) CHARACTER SET latin1 NOT NULL DEFAULT '',
`Name` varchar(40) CHARACTER SET latin1 NOT NULL DEFAULT '',
`City` varchar(40) CHARACTER SET latin1 NOT NULL DEFAULT '',
`State` varchar(40) CHARACTER SET latin1 NOT NULL DEFAULT '',
 PRIMARY KEY (`CID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;

CREATE TABLE `LineItem` (
`LID` varchar(10) NOT NULL DEFAULT '',
`OID` varchar(10) NOT NULL DEFAULT '',
`PID` varchar(110) NOT NULL DEFAULT '',
`Number` int(11) DEFAULT NULL,
`TotalPrice` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`LID`),
KEY `Order ID` (`OID`),
CONSTRAINT `Order ID` FOREIGN KEY (`OID`) REFERENCES `OrderItem` (`OID`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `OrderItem` (
`OID` varchar(10) NOT NULL DEFAULT '',
`CID` varchar(10) NOT NULL DEFAULT '',
PRIMARY KEY (`OID`),
KEY `CID` (`CID`),
CONSTRAINT `CID` FOREIGN KEY (`CID`) REFERENCES `Customer` (`CID`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `Product` (
`PID` varchar(10) NOT NULL DEFAULT '',
`ProductName` varchar(40) DEFAULT '',
`Price` decimal(10,2) DEFAULT NULL,
 PRIMARY KEY (`PID`)
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

我在查询中尝试做的是运行它,以便我可以成功地执行以下操作:

  1. 列出纽瓦克所有客户购买的产品

  2. 列出仅由纽瓦克客户订购的产品

  3. 对于#5,我尝试了这个查询:

    Select product.productname
    From Customer as c INNER JOIN OrderItem as o
    ON c.CID = o.CID
    INNER JOIN LineItem line
    ON o.OID = line.OID
    Inner Join Product product
    ON line.PID = product.PID
    Where C.City = 'Newark'
    Having Count(product.productname) > 1;
    

    但它只返回一个值,它应该返回2(除非我没有正确使用它)。

    对于#6我理解这个概念,但我不知道如何减去表格"在SQL中。

    第一个问题的目标是列出纽瓦克所有人购买的普通物品。因此,如果A人购买了物品X,Y和Z,而B人购买了W,V和Y,则查询将返回"物品Y"。

3 个答案:

答案 0 :(得分:2)

我想我的评论是一个答案。

Having Count(product.productname) > 1;

要求group by正常运行,因为它是聚合的过滤器,聚合需要group by。 90%的数据库引擎会返回一个错误明确声明它需要一个组...但MySQL更喜欢做错事而不是向你返回错误(这就是为什么你有一行... MySQL不管它感觉如何都做了一组。添加一个分组(我假设产品名称与你在这里有的东西),它应该有效。

答案 1 :(得分:1)

您需要添加GROUP BY。试试这个:

   Select product.productname
   From Customer as c 
   INNER JOIN OrderItem as o ON c.CID = o.CID
   INNER JOIN LineItem line ON o.OID = line.OID
   Inner Join Product product ON line.PID = product.PID
   Where C.City = 'Newark'
   Group by product.productname
   Having Count(*) > 1;

答案 2 :(得分:0)

另外两个答案指出,如果你想要HAVING那么你需要一个GROUP BY。但是你的问题实际上并没有提出问题或解释你的查询应该返回什么。 (你没有在你的问题或评论中清楚地解释。)你写了一条评论,“我有两个来自纽瓦克的人,并试图展示他们两人购买的物品[产品?]。”但是,如果您的查询仅通过分组“更正”,则会计算错误的计数。

问题是你应该返回PID(也许是ProductName)。您需要列出产品。作为密钥的PID可能是产品的1:1,但ProductName不是密钥,因此产品名称与产品不是1:1。 ProductName甚至可以为NULL。因此,选择ProductName并不能获得所有相关产品。 (同样在LineItem中,PID应该是一个FOREIGN KEY。)

另一个问题是你应该使用PID到GROUP BY产品。 ProductName不是Product的关键。因此两个产品可以具有相同的名称。因此,您将获得每个产品名称的计数,而不是每个产品的计数。 Plus ProductName可以为NULL。 (即使您只返回名称而不是具有这些计数的产品的PID,您也需要按PID进行分组。)

另一个问题是计数错误。按PID分组可以通过组合产品的Newark Customer行,OrderItem行和LineItem行来生成行。这些组合行按COUNT(PID)计数。但是你想要在那些行中消除纽瓦克客户的数量。你可以通过一个子选择来做到这一点,但恰好有一个更短的方式。

SELECT p.PID, p.ProductName
FROM Customer c
JOIN OrderItem AS o ON c.CID = o.CID
JOIN LineItem l ON o.OID = l.OID
JOIN Product p ON l.PID = p.PID
WHERE c.City = 'Newark'
GROUP BY (p.PID)
HAVING COUNT(DISTINCT c.CID) > 1;

在部分条件发生变化后,您会收到目标1的查询。

HAVING COUNT(DISTINCT c.CID)
    = (SELECT COUNT(*) FROM Customer WHERE City='Newark')

关系代数MINUS / DIFFERENCE对应于SQL标准中的EXCEPT。但MySQL没有它。您可以使用LEFT JOIN, NOT IN or NOT EXISTS代替。