Les champs supplémentaires avec SQL MIN () et GROUP BY
-
05-09-2019 - |
Question
En utilisant la fonction SQL MIN (), avec GROUP BY, aura des colonnes supplémentaires (non la colonne MIN, ou l'un des groupes de colonnes) correspondent aux données de la rangée correspondant à MIN?
Par exemple, donné une table avec les noms des ministères, les noms des employés et le salaire:
SELECT MIN(e.salary), e.* FROM employee e GROUP BY department
Il est évident que je vais obtenir deux bonnes colonnes, le salaire minimum et le ministère. Est-ce que le nom de l'employé (et tous les autres domaines des employés) être de la même ligne? A savoir la ligne avec le MIN (salaire)?
Je sais qu'il pourrait très probablement être deux employés avec le même (et le plus bas) salaire, mais tout ce que je suis préoccupé par (maintenant) est d'obtenir toutes les informations sur le (ou un ) employé moins cher.
Ne serait-ce choisir le moins cher vendeur?
SELECT min(salary), e.* FROM employee e WHERE department = 'sales'
Pour l'essentiel, puis-je être sûr que les données renvoyées avec la fonction MIN () correspond à la volonté (ou un ) record avec cette valeur minimale?
Si les questions de base de données, je travaille avec MySql.
La solution
Si vous voulez obtenir l'employé « moins cher » dans chaque département que vous avez deux choix du haut de ma tête:
SELECT
E.* -- Don't actually use *, list out all of your columns
FROM
Employees E
INNER JOIN
(
SELECT
department,
MIN(salary) AS min_salary
FROM
Employees
GROUP BY
department
) AS SQ ON
SQ.department = E.department AND
SQ.min_salary = E.salary
Ou vous pouvez utiliser:
SELECT
E.*
FROM
Employees E1
LEFT OUTER JOIN Employees E2 ON
E2.department = E1.department AND
E2.salary < E1.salary
WHERE
E2.employee_id IS NULL -- You can use any NOT NULL column here
La deuxième déclaration fonctionne en disant efficace, montrez-moi tous les employés où vous ne pouvez pas trouver un autre employé dans le même département avec un salaire inférieur.
Dans les deux cas, si deux ou plusieurs employés ont des salaires égaux qui sont le minimum que vous les obtiendrez les deux (tout).
Autres conseils
SELECT e.*
FROM employee e
WHERE e.id =
(
SELECT id
FROM employee ei
WHERE ei.department = 'sales'
ORDER BY
e.salary
LIMIT 1
)
Pour obtenir des valeurs pour chaque service, utilisez:
SELECT e.*
FROM department d
LEFT JOIN
employee e
ON e.id =
(
SELECT id
FROM employee ei
WHERE ei.department = d.id
ORDER BY
e.salary
LIMIT 1
)
Pour obtenir des valeurs que pour les départements qui ont des employés, utilisez:
SELECT e.*
FROM (
SELECT DISTINCT eo.department
FROM employee eo
) d
JOIN
employee e
ON e.id =
(
SELECT id
FROM employee ei
WHERE ei.department = d.department
ORDER BY
e.salary
LIMIT 1
)
Bien sûr, avoir un indice sur (department, salary)
améliorera considérablement les trois requêtes.
La solution la plus rapide:
SET @dep := '';
SELECT * FROM (
SELECT * FROM `employee` ORDER BY `department`, `salary`
) AS t WHERE IF ( @dep = t.`department`, FALSE, ( @dep := t.`department` ) OR TRUE );
Une autre approche peut être d'utiliser les fonctions analytiques. Voici la requête en utilisant des fonctions d'analyse et de no_lig
select first_name, de traitement (select first_name, salaire, ROW_NUMBER () plus (PARTITION PAR COMMANDE PAR DEPARTMENT_ID traitement ASC) en tant row_count des employés) où row_count = 1;