2012-04-10 12 views
5

Aquí está mi mesa y los datos contenidos en ella:¿Qué está pasando al usar DISTINCT?

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 | 
+-----------+----------+----------+ 

Mi intención es conseguir que la lista de third_id s ordenados por data campo. Ahora, ejecuté la siguiente consulta para eso.

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

Y obtengo el siguiente resultado como se esperaba.

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

La siguiente consulta también funciona como se esperaba.

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

con la salida

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

Entonces me encontré con lo siguiente.

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

Pero, aquí me sale un resultado inesperado:

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

Aquí, 3 debe ser posterior 2 y 4, ya que estoy pidiendo en el campo data. ¿Qué estoy haciendo mal? O tengo que ir por una estrategia diferente.

Nota: Este escenario ocurre en mi proyecto. Las tablas proporcionadas aquí no pertenecen a la base de datos original. Fue creado por mí para explicar el problema. Las tablas originales contienen miles de filas. Estoy insertando volcado de base de datos si desea experimentar con los datos:

-- 
-- 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); 
+4

"Pero, aquí recibo un resultado inesperado:" - Eso no es inesperado. –

+0

@MitchWheat ¿Pero cómo? – Jomoos

+1

Si fuera sql, rechazaría esta cláusula 'ORDER BY', pero' mysql' es notoriamente tolerante. ¿Con qué 'datos' quieres ordenar? –

Respuesta

3

Es posible que desee hacer algo como

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

que es min(data) o max(data) o lo que sea.

+0

Usando 'min (data)' hizo el trabajo. Aunque la respuesta de @Devart también funcionó, acepto esta respuesta porque parece una solución más natural y más simple. – Jomoos

+1

Acabo de buscarlo. Supongo que ambos deberían funcionar, aunque diría que @ Devart es un poco frágil. Teóricamente, si no tienes 'ORDER BY 'tu salida no está ordenada, aunque esta teoría a menudo difiere de la práctica. –

2

Hacer un SELECT DISTINCT requiere que la base de datos ordene los valores en la (s) columna (s), ya que es la manera más eficiente de encontrar los distintos valores. Por lo que sé ORDER BY las cláusulas que no contienen columnas que se generan en la consulta no se cumplen (SQL SERVER no aceptará la consulta) ya que no está claro lo que significa ordenar por algo que no lo hizo participar.

+0

No veo ninguna razón para ignorar 'ORDER BY' solo porque no está seleccionado. El problema aquí es la ambigüedad. –

+0

En mysql, SELECCIONAR DISTINCT no ordena los valores, dice [aquí] (http://www.mysqlfaqs.net/mysql-faqs/SQL-Statements/Select-Statement/How-does-DISTINCT-work-in- MySQL) – fqsxr

+0

Es una peculiaridad de MySQL que te permite escribir esa consulta porque no tiene sentido. En 'SELECT DISTINCT' ignoras por completo toda la información relacionada con 'datos'. El motor de consulta debería decirle que no le está haciendo una pregunta sensata y no está bombardeando. Por el contrario, elige confundir a las personas. – briantyler

2

Usted puede utilizar una subconsulta -

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; 

Esto ayudará a seleccionar y ordenar todos los datos en primer lugar, a continuación, para seleccionar valores distintos.

1

Tuve este problema exacto antes. Finalmente se me ocurrió una solución simple, casi parece demasiado simple. Debe usar una subconsulta como columna de la consulta de selección. En esa subconsulta es donde hará el pedido por fecha. Cuando lo haces todo en una sola consulta con ORDER BY sucede antes de JOIN. Primero quiere pedir, así que vaya con la subconsulta. http://nathansnoggin.blogspot.com/2009/04/select-distinct-with-order-by.html

Cuestiones relacionadas