2017-09-06 1 views
3

Ma question est peut-être semblable à ces questions:groupe MySQL par avec ordre et la priorité de plusieurs colonnes avec sélection multiple règles

Tableau Exemple:

source zip  phone street    city  created_at 
================================================================== 
a  11111 11111 Flatlands   null  2015-01-01 
b  11111 11111 Flatlands Avenue New York 2015-01-01 
c  11111 11111 Ave Flatlands  New York 2015-01-01 
a  22222 22222 Favory    New York 2015-01-01 
b  22222 22222 Favory Avenue  New York 2017-12-12 
c  22222 22222 Ave Favory   New York 2015-01-01 
b  33333 33333 Sixteenth   Washington 2015-01-01 
c  33333 33333 st. 16th   null  2015-01-01 
c  44444 44444 st. West Land  null  2015-01-01 

Disons que j'ai une table avec des informations sur les lieux dans différentes villes. Les informations proviennent de 3 sources différentes: a, b et c.

zip et phone les champs identifient de façon unique l'emplacement, de sorte que les lignes de la base de données peuvent être regroupées par ces champs.

J'ai besoin de fusionner des informations sur divers emplacements à partir de diverses sources en sélectionnant la meilleure valeur en fonction de l'ensemble des règles pour les colonnes street et city.

Les règles sont les suivantes:

  1. Pour chaque groupe des valeurs non vides prioriser des street et city sur les valeurs nulles.
  2. Dans chaque groupe, les valeurs de prioriser street et city colonnes de a et b sources sur c source (poids (a) = poids (b)> poids (c)) si ces colonnes ne sont pas vides.
  3. Pour les sources a et b, donnez la priorité aux valeurs de colonne des lignes dont la date et l'heure sont created_at.

Voici le résultat que je souhaite recevoir:

zip  phone street   city 
==================================== 
11111 11111 Flatlands  New York 
22222 22222 Favory Avenue New York 
33333 33333 Sixteenth  Washington 
44444 44444 st. West Land null 

Here is a DB Fiddle to play with.

Je ne suis pas sûr que cela soit possible avec SQL et peut-être que ma meilleure option est de passer à la tâche de traitement de base de données NoSQL DB +. Ou utilisez simplement un outil pour extraire des informations de la base de données et ensuite les traiter.

P.S. Ceci est un exemple simplifié.

+1

Les premier et deuxième critères peuvent être vérifiés dans une requête GROUP BY, mais le troisième ne le peut pas. Vous ** ne pouvez pas ** sélectionner des lignes en utilisant 'GROUP BY'. 'GROUP BY' calcule de nouvelles lignes en utilisant les données de chaque groupe. Vous ** ne pouvez pas ** sélectionner des lignes en utilisant 'GROUP BY'. 'GROUP BY' calcule de nouvelles lignes en utilisant les données de chaque groupe. Jetez un coup d'oeil à [cette réponse] (https://stackoverflow.com/a/28090544/4265352) sur une [question similaire (mais beaucoup plus simple)] (https://stackoverflow.com/q/12102200/4265352). – axiac

+1

Je ne voudrais pas écrire une requête monstre (avec ou sans GROUP BY) pour exécuter chaque fois que j'ai besoin d'obtenir des valeurs de la table. Je traiterais cela comme une table de brouillon et je créerais une autre table pour stocker une rangée pour chaque paire ('zip',' phone') avec les autres champs organisés en utilisant tous les critères dont vous avez besoin. Les scripts qui ont besoin des données liront depuis la table "clean"; un autre script utiliserait la table "draft" pour calculer les enregistrements "clean". Celui-ci peut s'exécuter périodiquement (et traiter toutes les lignes) ou seulement lorsque de nouvelles lignes sont ajoutées au "draft" (et recalculer uniquement les enregistrements "clean" affectés). – axiac

+0

Dans un autre SGBD, vous utiliseriez simplement ROW_NUMBER avec une partition et un ordre de tri appropriés pour classer les enregistrements. Comme MySQL manque de 'ROW_NUMBER', cherchez comment émuler' ROW_NUMBER' dans MySQL avec des variables. –

Répondre

0

Vous pouvez utiliser la requête suivante pour mettre en œuvre les règles de priorité pour street:

SELECT zip, phone, street 
FROM test 
ORDER BY zip, phone, 
     -- prioritize non empty values over null values 
     CASE 
      WHEN (street IS NOT NULL) OR (street = '') THEN 0 
      ELSE 1 
     END, 
     -- prioritize a, b over c 
     CASE 
      WHEN source IN ('a', 'b') THEN 0 
      ELSE 1 
     END, 
     -- prioritize rows which have the latest created_at 
     created_at DESC 

Une requête similaire peut être utilisé pour city champ.

Ensuite, vous pouvez émuler ROW_NUMBER, malheureusement pas disponible dans MySQL, en utilisant des variables:

SELECT zip, phone, street, 
     @seq := IF(@id = CONCAT(zip,phone), @seq + 1, 
        IF(@id := CONCAT(zip,phone), 1, 1)) AS seq 
FROM test 
CROSS JOIN (SELECT @seq := 0, @id = '') AS v 
ORDER BY zip, phone, 
     -- prioritize non empty values over null values 
     CASE 
      WHEN (street IS NOT NULL) OR (street = '') THEN 0 
      ELSE 1 
     END, 
     -- prioritize a, b over c 
     CASE 
      WHEN source IN ('a', 'b') THEN 0 
      ELSE 1 
     END, 
     -- prioritize rows which have the latest created_at 
     created_at DESC 

Encore une fois, une requête similaire peut être utilisé pour city champ.

Le résultat souhaité est obtenu en joignant les tables dérivées ci-dessus sur zip, street et seq = 1.