使用min,max和condition从SQL获取结果

时间:2017-07-06 00:48:03

标签: mysql

我正在尝试学习一些(提前或更复杂的)SQL 假设我有一张车牌表,上面有每辆车的信息 然后我有另一张桌子,有车出售,有些是新的,有些是用的。

我希望用户能够查看汽车,例如本田civic 2016,并查看汽车信息。
但也希望用户看到所有本田思域2016款车型,包括该特定年份/车型的最高价和最低价,由新车和二手车组织。

检索所有信息的最有效方法是什么 - 汽车信息以及要在页面上显示的销售信息!

这些是我的表格。

class MyClass {
    lazy var callback:()->() = {
        [unowned self] in
        self.foo()
    }

    func foo() {
        print("bar")
    }
}

let c = MyClass()
c.callback()

对我来说这看起来多余,随着桌子越来越大,注定会变慢。如果有人向我展示更好的方式,我将不胜感激。

CREATE TABLE Users(
    id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(16) NOT NULL,
    last VARCHAR(16) NOT NULL,
    email VARCHAR(128) NOT NULL,
    phone CHAR(10) NOT NULL,
    joined DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE Cars(
    id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    make VARCHAR(32) NOT NULL,
    model VARCHAR(32) NOT NULL,
    year INT(4) NOT NULL,
    trim VARCHAR(16) NOT NULL
);

CREATE TABLE Market(
    id BIGINT(20) NOT NULL AUTO_INCREMENT,
    user_id BIGINT(20) NOT NULL,
    car_id BIGINT(20) NOT NULL,
    condition VARCHAR(5) NOT NULL,
    notes VARCHAR(1024) NOT NULL,
    PRIMARY KEY(id),

    CONSTRAINT cfk FOREIGN KEY (car_id) REFERENCES cars(id) ON DELETE CASCADE ON UPDATE CASCADE,
    CONSTRAINT ufk FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
);

我最终希望使用PHP获得如下内容:

/* Get car information*/
SELECT *
FROM Cars 
WHERE make = 'Honda' 
  AND model = 'Civic' 
  AND year = '2017'   
  AND trim = 'EX'; 

/* I also would like to get the min and max price for this particular car*/
/* ?? How ?? */

/* Get (new) cars being sold and sellers */
SELECT M.*, U.* 
FROM Market M 
INNER JOIN Users ON M.user_id = U.id 
WHERE make = 'Honda' 
  AND model = 'Civic' 
  AND year = '2017' 
  AND color = 'white' 
  AND trim = 'EX' 
  AND condition = 'NEW';

/* Get (used) cars being sold and sellers */
SELECT M.*, U.* 
FROM Market M 
INNER JOIN Users ON M.user_id = U.id 
WHERE make = 'Honda' 
  AND model = 'Civic' 
  AND year = '2017' 
  AND color = 'white' 
  AND trim = 'EX' 
  AND condition = 'USED';

一旦我检索到信息,我就可以使用这种格式。另外,我必须通过数据库进行分页。

基本上我有兴趣了解做亚马逊的最佳方式。物品可以从不同的供应商处以不同的价格出售。亚马逊提供有关待售物品的信息;它的条件,价格,卖方等。此外,亚马逊为您提供最低,最高价格和一般项目的信息。什么是最好的方法?

3 个答案:

答案 0 :(得分:6)

四个查询应该没问题:

  • 获取有关Car类型的一般信息的一个查询
  • 按条件获取最低/最高价格的另一个查询
  • 然后查询每个以获取新的和使用过的可用汽车的市场列表。您可以懒洋洋地执行这两个查询 - 首先向您的购物者显示基本车辆信息和最小/最大新/使用价格,然后当您的购物者点击使用过的号码(如亚马逊)时,获取二手车的市场报价

对于最小/最大销售额,您需要执行聚合,因此GROUP BY是您的朋友。试试这个:

SELECT `condition`, MIN(price) min_price, MAX(price) max_price
FROM Cars
JOIN Market ON (Cars.id = Market.car_id)
WHERE make = 'Honda'
  AND model = 'Civic'
  AND year = '2017'
  AND trim = 'EX'
GROUP BY `condition`; 

您的其他疑问看起来不错。随着表格的增长以及您希望快速保持查询,索引将有所帮助。基本规则是作为WHERE谓词一部分的字段很适合编制索引。表之间的任何JOIN键通常都可以编入索引。尝试Cars(make, model, year, trim)上的索引。

此外,condition是MySQL 5.7中的保留字,这就是我使用反引号转义的原因。请考虑使用cond,如果您只有几个条件{" new","使用"},请考虑使用ENUM数据类型。注意MINMAX也是保留的db字。

答案 1 :(得分:2)

您可以使用两个查询检索所需的信息。 例如 - 您可以使用SELECT子句中的相关子查询在一个查询中获得新车和二手车的最低价格以及汽车信息:

SELECT c.*, 
    (SELECT MIN(m.price) FROM Market m WHERE m.car_id = c.id and m.condition = 'NEW')  as new_min_price,
    (SELECT MIN(m.price) FROM Market m WHERE m.car_id = c.id and m.condition = 'USED') as used_min_price
FROM Cars c
WHERE c.make = 'Honda' 
  AND c.model = 'Civic' 
  AND c.year = '2017'   
  AND c.trim = 'EX'

为了获得最佳性能,我将创建复合索引Cars(make, model, year, trim)Market(car_id, condition, price)。 第一个索引中列的顺序并不重要,您可以更改它。 优化程序可以根据您定义的顺序调整执行计划。 但是,第二个索引的顺序必须以这种方式才能最有效地获得最低价格。 如果您在Market(car_id)上有一个索引(可能是由FOREIGN KEY定义创建的),您可以删除它。 可以使用新的复合索引。

请注意,我没有包含最高价,因为我认为没有人关心。 但是,通过使用MAX()代替MIN(),您可以获得与获得最低价格相同的方式。

还有另一种方法可以使用“条件聚合”来获取相同的数据:

SELECT c.*,
    MIN(CASE m.condition = 'NEW' THEN m.price END)  as new_min_price,
    MIN(CASE m.condition = 'USED' THEN m.price END) as used_min_price
FROM Cars c
JOIN Market m ON m.car_id = c.id
WHERE c.make = 'Honda' 
  AND c.model = 'Civic' 
  AND c.year = '2017'   
  AND c.trim = 'EX'
GROUP BY c.id

但是这个查询不能以最佳方式使用索引,因为引擎需要循环遍历所有商品才能找到最低价格。

现在要获取Market表中的所有商品,您不需要执行两个查询(每个条件一个)。 您可以使用一个查询获取所有查询,并将结果按应用程序语言中的condition字段进行分组。 此外,由于您已经知道第一个查询中的car_id,因此您可以将其用作搜索条件,因此您无需再次触摸cars表。 (请注意,如果没有与cars表的JOIN,您的最后两个查询将无效,因为市场表没有列makemodelyeartrim。)

SELECT
    m.condition
    m.id as market_id,
    m.user_id,
    u.name,
    u.last
FROM Market m
INNER JOIN Users u ON m.user_id = u.id
WHERE m.car_id = ?
ORDER BY price

请注意,如果您使用SELECT m*, u*,则id字段将不明确,因为它在两个表中都已定义。 因此,您应列出要获取的所有字段,并为m.id as market_id等不明确的列使用别名。

您没有提及您使用的语言 - 因此我无法确切地告诉您如何按condition字段对结果进行分组。 例如,使用PHP PDO,您可以使用PDO::FETCH_GROUP模式。 但是,如果您的语言不支持此类功能,则可以在简单的循环中对结果进行分组/拆分。

答案 2 :(得分:0)

很多人可能不喜欢这个,但我已经使用MS Access解决了一些最复杂的SQL语句。首先,只需使用MS访问来设计表和关系。然后使用查询构建器来设计查询。然后将查询构建器更改为SQL视图以查看SQL语句。要在其他数据库引擎上使用此SQL代码,需要进行细微更改。

SQL编码国王讨厌MS Access,但实际上,它是开始构建任何数据库时最好的开发工具。它允许轻松快速的更改,并且在单用户模式下是最快的数据库。

如果您计划构建大量数据库并希望通过不成为SQL编码王来节省时间,那么我们将MS Access作为开发工具!