【问题标题】:What is happening when using DISTINCT?使用 DISTINCT 时会发生什么?
【发布时间】:2012-04-22 17:57:11
【问题描述】:

这是我的表格和其中包含的数据:

Table: first

+----------+------+
| first_id | data |
+----------+------+
|        1 |    5 |
|        2 |    6 |
|        3 |    7 |
|        4 |    6 |
|        5 |    7 |
|        6 |    5 |
|        7 |    7 |
|        8 |    6 |
|        9 |    5 |
|       10 |    7 |
+----------+------+

Table: second
+-----------+----------+----------+
| second_id | first_id | third_id |
+-----------+----------+----------+
|         1 |        1 |        2 |
|         2 |        2 |        3 |
|         3 |        3 |        4 |
|         4 |        4 |        2 |
|         5 |        5 |        3 |
|         6 |        6 |        4 |
|         7 |        7 |        2 |
|         8 |        8 |        2 |
|         9 |        9 |        4 |
|        10 |       10 |        4 |
+-----------+----------+----------+

我的目的是获取由data 字段排序的third_ids 列表。现在,我为此运行了以下查询。

SELECT
    third_id, data
FROM 
    first f JOIN second s ON ( s.first_id = f.first_id )
ORDER BY 
    data ASC;

我按预期得到以下结果。

+----------+------+
| third_id | data |
+----------+------+
|        4 |    5 |
|        2 |    5 |
|        4 |    5 |
|        2 |    6 |
|        3 |    6 |
|        2 |    6 |
|        2 |    7 |
|        4 |    7 |
|        4 |    7 |
|        3 |    7 |
+----------+------+

以下查询也按预期工作。

SELECT 
    third_id
FROM 
    first f JOIN second s ON ( s.first_id = f.first_id )
ORDER BY 
    data ASC;

有输出

+----------+
| third_id |
+----------+
|        4 |
|        2 |
|        4 |
|        2 |
|        3 |
|        2 |
|        2 |
|        4 |
|        4 |
|        3 |
+----------+

然后我运行了以下内容。

SELECT DISTINCT
    third_id
FROM 
    first f JOIN second s ON ( s.first_id = f.first_id )
ORDER BY 
    data ASC;

但是,在这里我得到了一个意想不到的结果:

+----------+
| third_id |
+----------+
|        2 |
|        3 |
|        4 |
+----------+

这里,3 必须在 24 之后,因为我在 data 字段上订购。我究竟做错了什么?还是我必须采取不同的策略。

注意: 这种情况发生在我的项目中。此处提供的表不属于原始数据库。它是由我创建来解释问题的。原始表包含数千行。 如果您想试验数据,我将插入数据库转储:

--
-- Table structure for table `first`
--

CREATE TABLE IF NOT EXISTS `first` (
  `first_id` int(11) NOT NULL AUTO_INCREMENT,
  `data` int(11) NOT NULL,
  PRIMARY KEY (`first_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;

--
-- Dumping data for table `first`
--

INSERT INTO `first` (`first_id`, `data`) VALUES
(1, 5),
(2, 6),
(3, 7),
(4, 6),
(5, 7),
(6, 5),
(7, 7),
(8, 6),
(9, 5),
(10, 7);
--
-- Table structure for table `second`
--

CREATE TABLE IF NOT EXISTS `second` (
  `second_id` int(11) NOT NULL AUTO_INCREMENT,
  `first_id` int(11) NOT NULL,
  `third_id` int(11) NOT NULL,
  PRIMARY KEY (`second_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;

--
-- Dumping data for table `second`
--

INSERT INTO `second` (`second_id`, `first_id`, `third_id`) VALUES
(1, 1, 2),
(2, 2, 3),
(3, 3, 4),
(4, 4, 2),
(5, 5, 3),
(6, 6, 4),
(7, 7, 2),
(8, 8, 2),
(9, 9, 4),
(10, 10, 4);

【问题讨论】:

  • “但是,我得到了一个意想不到的结果:” - 这并不意外。
  • 如果我是 sql,我会拒绝这个 ORDER BY 子句,但是 mysql 是出了名的容忍它。您想通过哪个data 订购?
  • @MitchWheat 问题的作者没有预料到,所以从这个意义上说是出乎意料的。他按隐藏列排序,并想知道为什么最终查询中没有保留该顺序。
  • 澄清一下,您期望 4,2,3,根据数据顺序选择不同的值?这里不是积极的,但我认为不同的选择会根据不同的字段自动对字段进行排序,否则查询的效率会低得多。
  • 如果你想要按数据字段排序的 third_ids 列表,为什么还要使用 distinct 呢?为什么你在查询中有那个 JOIN ? JOIN 似乎未使用,因为 first_id 和数据都在第一个表中。

标签: mysql sql select distinct


【解决方案1】:

我以前也遇到过这个问题。我终于想出了一个简单的解决方案,似乎太简单了。您需要使用子查询作为选择查询的列。在该子查询中,您将按日期进行排序。当您在一个查询中使用 ORDER BY 完成所有操作时,会发生在 JOIN 之前。您想先订购,所以使用子查询。 http://nathansnoggin.blogspot.com/2009/04/select-distinct-with-order-by.html

【讨论】:

    【解决方案2】:

    您可以使用子查询 -

    SELECT DISTINCT third_id FROM (
      SELECT
        third_id
      FROM 
        first f JOIN second s ON ( s.first_id = f.first_id )
      ORDER BY 
        data ASC
    ) t;
    

    这将有助于首先选择和排序所有数据,然后选择不同的值。

    【讨论】:

      【解决方案3】:

      执行SELECT DISTINCT 要求数据库对列中的值进行排序,因为这是查找不同值的最有效方法。据我所知,ORDER BY 不包含在查询中输出的列的子句不会得到兑现(SQL SERVER 不接受查询),因为不清楚按以下内容排序意味着什么没有参加。

      【讨论】:

      • 我认为没有理由忽略 ORDER BY 只是因为它没有被选中。这里的问题是模棱两可。
      • 在 mysql 中,SELECT DISTINCT 不会对值进行排序,如here
      • 这是 MySQL 的一个怪癖,它允许您编写该查询,因为它没有任何意义。在SELECT DISTINCT 中,您完全无视与data 相关的所有信息。查询引擎应该告诉你,你问的不是一个明智的问题,然后就炸了。相反,它选择迷惑人们。
      • @user317290 该页面根本没有这样说。执行SELECT DISTINCT 不会显式对值进行排序(即不能保证它们会被排序),但实际上它通常会对它们进行排序,因为这是从列表中删除重复项的最有效方法(它可能会发现如果它找到正确的索引,这是一个更好的方法)。
      • @TheMouthofaCow 它说,“DISTINCT 和 GROUP BY 之间的区别在于 DISTINCT 不会导致行排序。在 MySQL 中,GROUP BY 会导致排序。”如果你运行 Devart 的查询,它确实得到了“4,2,3”的结果,这意味着这里 MySQL 没有使用排序方法来删除重复项。
      【解决方案4】:

      你可能想做类似的事情

      SELECT third_id
      FROM first JOIN second USING (first_id)
      GROUP BY third_id
      ORDER BY aggregatesomething(data)
      

      min(data)max(data) 或其他。

      【讨论】:

      • 使用min(data) 完成了这项工作。虽然,@Devart 的答案也确实有效,但我接受了这个答案,因为它看起来更自然和更简单的解决方案。
      • 刚刚查了一下。猜猜两者都应该起作用,尽管我会说@Devart's 有点脆弱。从理论上讲,如果您没有 ORDER BY,您的输出是无序的,即使该理论通常与实践有所不同。
      猜你喜欢
      • 2014-09-06
      • 2020-08-14
      • 1970-01-01
      • 1970-01-01
      • 2010-09-26
      • 2010-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多