Question

Structure de la table simplifiée:

CREATE TABLE IF NOT EXISTS `hpa` (
  `id` bigint(15) NOT NULL auto_increment,
  `core` varchar(50) NOT NULL,
  `hostname` varchar(50) NOT NULL,
  `status` varchar(255) NOT NULL,
  `entered_date` int(11) NOT NULL,
  `active_date` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `hostname` (`hostname`),
  KEY `status` (`status`),
  KEY `entered_date` (`entered_date`),
  KEY `core` (`core`),
  KEY `active_date` (`active_date`)
)

Pour cela, j'ai la requête SQL suivante qui totalise simplement tous les enregistrements avec le statut défini.

SELECT core,COUNT(hostname) AS hostname_count, MAX(active_date) AS last_active
          FROM `hpa`
          WHERE 
          status != 'OK' AND status != 'Repaired'
          GROUP BY core
          ORDER BY core

Cette requête a été simplifiée pour supprimer INNER JOINS des données non liées et des colonnes supplémentaires qui ne devraient pas affecter la question.

MAX (date_actif) est identique pour tous les enregistrements d'un jour particulier et doit toujours sélectionner le jour le plus récent ou autoriser un décalage à partir de NOW (). (c'est un champ UNIXTIME)

Je veux le nombre de: (status! = 'OK' AND status! = 'Réparé')

ET l'inverse ... compte de: (status = 'OK' OU status = 'Réparé')

ET la première réponse divisée par la seconde, pour 'pourcentage_dead' (probablement aussi rapide à faire en post-traitement)

POUR le jour le plus récent ou un décalage (- 86400 pour hier, etc.)

La table contient environ 500 000 enregistrements et s’agrandit d’environ 5 000 personnes par jour. Par conséquent, une requête SQL unique, par opposition à la mise en boucle, serait très agréable.

J'imagine que des créatifs pourraient le faire. Votre expertise est appréciée.

EDIT: je suis prêt à utiliser une requête SQL différente pour les données actuelles ou les données d'un décalage.

EDIT: la requête fonctionne, est assez rapide, mais je ne peux actuellement pas laisser les utilisateurs trier sur la colonne de pourcentage (celle qui est dérivée de comptes bons et mauvais). Ce n'est pas un spectacle, mais je leur permet de trier tout le reste. L'ordre par ceci:

SELECT h1.core, MAX(h1.entered_date) AS last_active, 
SUM(CASE WHEN h1.status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS good_host_count,  
SUM(CASE WHEN h1.status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS bad_host_count 
FROM `hpa` h1 
LEFT OUTER JOIN `hpa` h2 ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date) 
WHERE h2.hostname IS NULL 
GROUP BY h1.core 
ORDER BY ( bad_host_count / ( bad_host_count + good_host_count ) ) DESC,h1.core

me donne:     N ° 1247 - Référence 'bad_host_count' non prise en charge (référence à la fonction group)

EDIT: résolu pour une section différente. Ce qui suit fonctionne et me permet de ORDER BY pourcentage_dead

SELECT c.core, c.last_active, 
SUM(CASE WHEN d.dead = 1 THEN 0 ELSE 1 END) AS good_host_count,  
SUM(CASE WHEN d.dead = 1 THEN 1 ELSE 0 END) AS bad_host_count,
( SUM(CASE WHEN d.dead = 1 THEN 1 ELSE 0 END) * 100/
( (SUM(CASE WHEN d.dead = 1 THEN 0 ELSE 1 END) )+(SUM(CASE WHEN d.dead = 1 THEN 1 ELSE 0 END) ) ) ) AS percentage_dead
FROM `agent_cores` c 
LEFT JOIN `dead_agents` d ON c.core = d.core
WHERE d.active = 1
GROUP BY c.core
ORDER BY percentage_dead
Était-ce utile?

La solution

Si je comprends bien, vous souhaitez obtenir le nombre de noms d’hôte OK par rapport aux noms d’hôtes non OK, à la date de la dernière activité. Droite? Et puis cela devrait être groupé par noyau.

SELECT core, MAX(active_date)
  SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS OK_host_count,
  SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS broken_host_count
FROM `hpa` h1 LEFT OUTER JOIN `hpa` h2 
  ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date)
WHERE h2.hostname IS NULL
GROUP BY core
ORDER BY core;

Ceci est une variante du "plus grand-n-groupe". problème que je vois beaucoup dans les questions SQL sur StackOverflow.

Tout d’abord, voulez choisir uniquement les lignes qui ont la dernière date d’activité par nom d’hôte, ce que nous pouvons faire en créant une jointure externe pour les lignes ayant le même nom d’hôte et une date active supérieure. Si nous ne trouvons aucune correspondance de ce type, nous avons déjà les dernières lignes pour chaque nom d'hôte donné.

Ensuite, regroupez par cœur et comptez les lignes par statut.

C'est la solution pour la date d'aujourd'hui (en supposant qu'aucune ligne n'a une date active dans le futur). Pour limiter le résultat aux lignes d'il y a N jours, vous devez limiter les deux tables.

SELECT core, MAX(active_date)
  SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS OK_host_count,
  SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS broken_host_count
FROM `hpa` h1 LEFT OUTER JOIN `hpa` h2 
  ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date
  AND h2.active_date <= CURDATE() - INTERVAL 1 DAY)
WHERE h1.active_date <= CURDATE() - INTERVAL 1 DAY AND h2.hostname IS NULL
GROUP BY core
ORDER BY core; 

En ce qui concerne le rapport entre OK et les noms d’hôtes cassés, je vous recommande de le calculer dans votre code PHP. SQL ne vous permet pas de faire référence à des alias de colonnes dans d'autres expressions de liste de sélection; vous devez donc envelopper la requête ci-dessus comme une sous-requête, ce qui est plus complexe que cela ne vaut la peine dans ce cas.

J'ai oublié que vous utilisiez un horodatage UNIX. Faites quelque chose comme ça:

SELECT core, MAX(active_date)
  SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS OK_host_count,
  SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS broken_host_count
FROM `hpa` h1 LEFT OUTER JOIN `hpa` h2 
  ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date
  AND h2.active_date <= UNIX_TIMESTAMP() - 86400)
WHERE h1.active_date <= UNIX_TIMESTAMP() - 86400 AND h2.hostname IS NULL
GROUP BY core
ORDER BY core; 
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top