Ver Mensaje Individual
  #4 (permalink)  
Antiguo 12/03/2013, 10:06
leonardo_josue
Colaborador
 
Fecha de Ingreso: enero-2007
Ubicación: México
Mensajes: 2.097
Antigüedad: 17 años, 10 meses
Puntos: 447
Respuesta: rango por ventas y por zona

Hola de nuevo gerardo_goh:

Lamentablemente MySQL no cuenta con funciones RANK o ROW_COUNT que poseen otros motores como ORACLE o SQL Server, y que son las indicadas para hacer lo que necesitas, sin embargo hay varias técnicas que puedes utilizar para simular estas funciones. Checa esta liga:

RANK:
http://www.artfulsoftware.com/infotr...tip.php?id=460

ROW_NUMBER:
http://www.artfulsoftware.com/infotr...ip.php?id=1098


Como podrás observar la consulta no es tan trivial, pero en realidad no es tan complicada llevarla a la práctica. Me voy a enfocar sólo en lo que te falta que es el RANK de ventas... sería más o menos así, basándonos en los siguientes datos:

Código MySQL:
Ver original
  1. mysql> SELECT id_trab, nombre, zona, ventas FROM tblrango;
  2. +---------+-----------+------+--------+
  3. | id_trab | nombre    | zona | ventas |
  4. +---------+-----------+------+--------+
  5. | 00013   | armando   | 0015 |     25 |
  6. | 00156   | ricardo   | 0015 |     30 |
  7. | 04566   | gerardo   | 0015 |     20 |
  8. | 01756   | francisco | 0120 |     30 |
  9. | 02546   | jose      | 0120 |     48 |
  10. | 05630   | julian    | 3000 |     40 |
  11. | 09000   | pablo     | 3000 |     30 |
  12. | 12222   | ulises    | 3000 |     31 |
  13. | 12300   | jonathan  | 3000 |     30 |
  14. | 15460   | pedro     | 3000 |     41 |
  15. +---------+-----------+------+--------+
  16. 10 rows in set (0.00 sec)


La idea de la función RANK es hacer una subconsulta para cada registro donde cuentes cuantos registros existen con ventas mayores o iguales a la que se está analizando. Sería más o menos así:

Código MySQL:
Ver original
  1. mysql> SELECT v1.id_trab, v1.nombre, v1.zona,
  2.     -> v1.ventas, COUNT(v2.ventas) AS Rank
  3.     -> FROM tblrango v1
  4.     -> INNER JOIN tblrango v2 ON
  5.     ->   v1.zona = v2.zona AND
  6.     ->   v1.ventas < v2.ventas OR
  7.     ->   (v1.ventas = v2.ventas AND v1.zona = v2.zona AND
  8.     ->    v1.id_trab = v2.id_trab)
  9.     -> GROUP BY v1.id_trab, v1.zona, v1.ventas
  10.     -> ORDER BY v1.zona, v1.ventas DESC, v1.id_trab;
  11. +---------+-----------+------+--------+------+
  12. | id_trab | nombre    | zona | ventas | Rank |
  13. +---------+-----------+------+--------+------+
  14. | 00156   | ricardo   | 0015 |     30 |    1 |
  15. | 00013   | armando   | 0015 |     25 |    2 |
  16. | 04566   | gerardo   | 0015 |     20 |    3 |
  17. | 02546   | jose      | 0120 |     48 |    1 |
  18. | 01756   | francisco | 0120 |     30 |    2 |
  19. | 15460   | pedro     | 3000 |     41 |    1 |
  20. | 05630   | julian    | 3000 |     40 |    2 |
  21. | 12222   | ulises    | 3000 |     31 |    3 |
  22. | 09000   | pablo     | 3000 |     30 |    4 |
  23. | 12300   | jonathan  | 3000 |     30 |    4 |
  24. +---------+-----------+------+--------+------+
  25. 10 rows in set (0.00 sec)

También podrías hacerlo con la función ROW_NUMBER, la idea aquí es en primer lugar ordenar los registros por zona y por ventas, utilizar una variable temporal para almacenar la zona y un contador para la posición. Mientras se analice la misma zona, se va incrementando el contador para poner la posición, cuando se detecta un cambio de zona entonces se inicializa el contador a 1... sería más o menos así:

Primero inicializamos las variables temprales que vamos a utilizar:

Código MySQL:
Ver original
  1. mysql> SET @zonaPrev=0, @ventasPrev=0, @ordPrev=0;
  2. Query OK, 0 rows affected (0.00 sec)
  3.  
  4. mysql> SELECT id_trab, nombre, zona, ventas, row_number
  5.     -> FROM (
  6.     ->   SELECT
  7.     ->     ventas, id_trab, nombre,
  8.     ->     @ordPrev := IF(@zonaPrev = zona,
  9.     ->                    IF(ventas != @ventasPrev, @ordPrev+1, @ordPrev),
  10.     ->                    1) AS row_number,
  11.     ->     @zonaPrev := zona AS zona,
  12.     ->     @ventasPrev := ventas AS ventasPrev
  13.     ->   FROM tblrango
  14.     ->   ORDER BY zona, ventas DESC, id_trab, nombre
  15.     -> ) tmp;
  16. +---------+-----------+------+--------+------------+
  17. | id_trab | nombre    | zona | ventas | row_number |
  18. +---------+-----------+------+--------+------------+
  19. | 00156   | ricardo   | 0015 |     30 |          1 |
  20. | 00013   | armando   | 0015 |     25 |          2 |
  21. | 04566   | gerardo   | 0015 |     20 |          3 |
  22. | 02546   | jose      | 0120 |     48 |          1 |
  23. | 01756   | francisco | 0120 |     30 |          2 |
  24. | 15460   | pedro     | 3000 |     41 |          1 |
  25. | 05630   | julian    | 3000 |     40 |          2 |
  26. | 12222   | ulises    | 3000 |     31 |          3 |
  27. | 09000   | pablo     | 3000 |     30 |          4 |
  28. | 12300   | jonathan  | 3000 |     30 |          4 |
  29. +---------+-----------+------+--------+------------+
  30. 10 rows in set (0.00 sec)

Si comparas este ejercicio con el que te pongo en la liga, observarás que yo utilizo una segunda variable ventasTemp, esto es para evitar que cuando se trate de ventas iguales te ponga un orden distinto, como en los últimos dos registros, si lo hago como aparece en el ejemplo sería así:

Código MySQL:
Ver original
  1. mysql> SET @zonaPrev=0, @ordPrev=0;
  2. Query OK, 0 rows affected (0.00 sec)
  3.  
  4. mysql> SELECT id_trab, nombre, zona, ventas, row_number
  5.     -> FROM (
  6.     ->   SELECT
  7.     ->     ventas, id_trab, nombre,
  8.     ->     @ordPrev := IF(@zonaPrev = zona, @ordPrev+1, 1) AS row_number,
  9.     ->     @zonaPrev := zona AS zona
  10.     ->   FROM tblrango
  11.     ->   ORDER BY zona, ventas DESC, id_trab, nombre
  12.     -> ) tmp;
  13. +---------+-----------+------+--------+------------+
  14. | id_trab | nombre    | zona | ventas | row_number |
  15. +---------+-----------+------+--------+------------+
  16. | 00156   | ricardo   | 0015 |     30 |          1 |
  17. | 00013   | armando   | 0015 |     25 |          2 |
  18. | 04566   | gerardo   | 0015 |     20 |          3 |
  19. | 02546   | jose      | 0120 |     48 |          1 |
  20. | 01756   | francisco | 0120 |     30 |          2 |
  21. | 15460   | pedro     | 3000 |     41 |          1 |
  22. | 05630   | julian    | 3000 |     40 |          2 |
  23. | 12222   | ulises    | 3000 |     31 |          3 |
  24. | 09000   | pablo     | 3000 |     30 |          4 |
  25. | 12300   | jonathan  | 3000 |     30 |          5 |
  26. +---------+-----------+------+--------+------------+
  27. 10 rows in set (0.00 sec)

Observa que en los últimos dos registros les asigna rangos diferentes (4, 5).

Trata de analizar las consultas pero sobre todo trata de entenderlas, practica algunas otras consultas, estoy seguro que este tipo de consultas te servirán en un futuro.

Saludos.