2010-10-07 5 views
0

Je veux obtenir la dernière MainNumber, série, Bartype et Notes pour un MainNumber donné, si elles existent. Notez que BarType est stocké dans une table de recherche et référencé avec BarID.MySQL Obtenir dernier enregistrement par date de mutiple tables avec des valeurs de tables de consultation

Déraison est venu avec ceci:

SELECT @MainNumber, COALESCE(n.Notes, 'None') 
FROM numbers 
    LEFT JOIN notes n ON numbers.MainNumber = n.MainNumber 
    LEFT JOIN notes n2 ON n.MainNumber = n2.MainNumber AND n.Date < n2.Date 
WHERE n2.Date IS NULL AND numbers.MainNumber = @MainNumber 

Cela est bien si les billets est NULL ou non, mais maintenant je besoin de la série et le Bartype. Un numéro principal peut avoir été affecté à plusieurs périodiques pendant sa durée de vie, mais je ne veux que le dernier numéro de série. (Je dois faire cela avec environ 15 autres champs dans d'autres tables, donc une réponse performante serait appréciée si possible)

Tables

Nombres Tableau:

CREATE TABLE `numbers` (
    `ID` int(10) unsigned NOT NULL auto_increment, 
    `MainNumber` varchar(11) NOT NULL, 
    `Serial` varchar(20) NOT NULL, 
    `Date` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, 
    PRIMARY KEY (`ID`), 
    UNIQUE KEY `Serial` (`Serial`) 
) ENGINE=MyISAM AUTO_INCREMENT=460 DEFAULT CHARSET=latin1 

Remarques Table :

CREATE TABLE `notes` (
    `ID` int(10) unsigned NOT NULL auto_increment, 
    `MainNumber` varchar(11) NOT NULL, 
    `Notes` longtext NOT NULL, 
    `Date` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, 
    PRIMARY KEY (`ID`), 
    KEY `MainNumber` (`MainNumber`) 
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC 

ref_bars Table:

CREATE TABLE `ref_bars` (
    `BarID` varchar(6) NOT NULL, 
    `BarType` varchar(30) NOT NULL, 
    PRIMARY KEY USING BTREE (`BarID`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 
tableau

bars:

CREATE TABLE `bars` (
    `ID` int(10) unsigned NOT NULL auto_increment, 
    `MainNumber` varchar(11) NOT NULL, 
    `BarID` varchar(6) NOT NULL, 
    `Date` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, 
    PRIMARY KEY (`ID`), 
    KEY `MainNumber` (`MainNumber`) 
) ENGINE=MyISAM AUTO_INCREMENT=212 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC 

Données-échantillon

SELECT * FROM notes:

'ID','MainNumber','Notes','Date' 
'1','1','repaired','2009-03-23 12:00:00' 
'2','1','replaced','2009-08-15 19:20:05' 

Note: deux lignes pour MainNumber = 1, mais pas de rangée pour une MainNumber de deux. Les identifiants sont simplement techniques et ne sont jamais utilisés.

SELECT * FROM numbers:

'ID','MainNumber','Serial','Date' 
'1','1','4642785154854','2008-08-15 12:30:00' 
'2','1','4642315642316','2009-08-15 12:50:00' 
'3','2','5412558456223','2010-08-15 11:30:00' 

SELECT * FROM bars:

'ID','MainNumber','BarID','Date' 
'1','1',1,'2008-08-15 12:30:00' 
'2','1',2,'2009-08-15 12:50:00' 
'3','2',2,'2010-08-15 11:30:00' 

SELECT * FROM ref_bars:

'BarID','BarType' 
'1','Banned' 
'2','Payment required' 

Sortie prévue

MainNumber = 1

MainNumber,Notes,Banned,Unpaid 
'1','replaced','Yes','Yes' 

MainNumber = 2

MainNumber,Notes,Banned,Unpaid 
'2','None','No','Yes' 

Edit: fixe et testé, tout en rendant les choses plus claires (espérons-le). On m'a précipité pour faire d'autres choses plus tôt aujourd'hui, désolé de gaspiller le temps des gens avec une question mal écrite et incomplète.

Mise à jour pour clarifier les exigences plus complexes

+3

pourriez-vous fournir quelques exemples de données?(avec résultat attendu) –

+0

Comme l'écrit mastoj, vous obtiendrez * beaucoup * de meilleures réponses si vous postez un cas de test reproductible: Toutes les définitions de table (ou au moins assez pour exécuter le SQL), plus la requête complète que vous utilisez, plus données de test, plus le résultat attendu. – sleske

+0

Vous pouvez simplement publier les données de test en tant que données CSV; cela devrait survivre à la mise en forme de stackoverflow, et est facile à importer. – sleske

Répondre

0

Je l'ai finalement élaboré. C'est en fait beaucoup plus simple que je ne le pensais. C'est plus proche de la requête originale que j'écrivais aussi.

SELECT 
    s.MainNumber, 
    n.Notes 
FROM numbers s 
JOIN (
    SELECT 
     MAX(Date) AS Date, 
     MainNumber 
    FROM numbers 
    WHERE MainNumber = 2 
) AS sx 
    ON s.MainNumber = sx.MainNumber AND s.Date = sx.Date 

LEFT JOIN notes n 
    ON s.MainNumber = n.MainNumber 
LEFT JOIN (
    SELECT 
      MAX(Date) AS Date, 
      COALESCE(MainNumber,0) AS MainNumber 
    FROM notes 
    WHERE MainNumber = 2 
) AS nx 
    ON n.MainNumber = nx.MainNumber AND n.Date = nx.Date 
0

Peut-être que quelque chose comme ça?

LEFT JOIN (select notes n 
JOIN (
    SELECT 
     MAX(Date) AS Date, 
     MainNumber 
    FROM notes 
    GROUP BY MainNumber 
) AS nx 
    ON n.MainNumber = nx.MainNumber AND n.Date = nx.Date) n 
ON notes.MainNumber = main.MainNumber 

J'ai supprimé la clause where puisque vous ne décrivez pas pourquoi vous l'avez. Si vous en avez besoin, vous pouvez simplement l'insérer à nouveau.

EDIT: La requête est mise à jour, mais il est encore difficile de comprendre exactement ce que vous voulez. Quand j'ai écrit des exemples de données, je voulais dire 2-3 lignes pour chaque table avec la sortie attendue, et si vous pouviez simplifier l'exemple, ce serait encore mieux. J'espère que cela aide.

1

Le choix d'ignorer vos requêtes initiales car ils ne se reproduisent pas votre problème, je vous regarde la sortie attendue Je suppose que vous essayez d'atteindre les objectifs suivants:

Étant donné MainNumber look pour le dossier dans Tabel notes et retourner la ligne avec la date maximum, s'il n'y a pas des documents dans les notes du tableau pour une donnée MainNumber puis retour constant 'None'

(cela pourrait ne pas être ce qui est demandé, donc s'il vous plaît corriger la sortie attendue si elle est pas)

Ceci peut être facilement atteint, par exemple

SELECT @MainNumber, n.Notes 
FROM notes n 
    LEFT JOIN notes n2 ON n.MainNumber = n2.MainNumber AND n.Date < n2.Date 
WHERE n2.Date IS NULL AND n.MainNumber = @MainNumber 

qui retournera la dernière ligne de Remarques. Maintenant, du côté de l'application, si elle ne renvoie aucune ligne, il suffit d'imprimer @MainNumber, 'None' et c'est ...

Si vous recherchez du SQL pur (et en supposant que vous avez besoin d'autres colonnes de la numéros tableau), vous pouvez faire:

SELECT @MainNumber, COALESCE(n.Notes, 'None') 
FROM numbers 
    LEFT JOIN notes n ON numbers.MainNumber = n.MainNumber 
    LEFT JOIN notes n2 ON n.MainNumber = n2.MainNumber AND n.Date < n2.Date 
WHERE n2.Date IS NULL AND numbers.MainNumber = @MainNumber 

EDIT: la première requête est testée

mysql> SET @MainNumber = 1;              Query OK, 0 rows affected (0.00 sec) 

mysql> SELECT @MainNumber, n.Notes FROM notes n  LEFT JOIN notes n2 ON n.MainNumber = n2.MainNumber AND n.Date < n2.Date WHERE n2.Date IS NULL AND n.MainNumber = @MainNumber; 
+-------------+----------+ 
| @MainNumber | Notes | 
+-------------+----------+ 
|   1 | replaced | 
+-------------+----------+ 
1 row in set (0.00 sec) 

la deuxième requête a retourné initialement plusieurs lignes en cas de plusieurs entrées dans la table des nombres, DISTINCTS correctifs

mysql> SET @MainNumber = 1;              Query OK, 0 rows affected (0.00 sec) 

mysql> SELECT DISTINCT @MainNumber, COALESCE(n.Notes, 'None') 
    -> FROM numbers 
    ->  LEFT JOIN notes n ON numbers.MainNumber = n.MainNumber 
    ->  LEFT JOIN notes n2 ON n.MainNumber = n2.MainNumber AND n.Date < n2.Date 
    -> WHERE n2.Date IS NULL AND numbers.MainNumber = @MainNumber 
    -> ; 
+-------------+---------------------------+ 
| @MainNumber | COALESCE(n.Notes, 'None') | 
+-------------+---------------------------+ 
|   1 | replaced     | 
+-------------+---------------------------+ 
1 row in set (0.00 sec) 

mysql> SET @MainNumber = 2; 
Query OK, 0 rows affected (0.00 sec) 

mysql> SELECT DISTINCT @MainNumber, COALESCE(n.Notes, 'None') 
    -> FROM numbers 
    ->  LEFT JOIN notes n ON numbers.MainNumber = n.MainNumber 
    ->  LEFT JOIN notes n2 ON n.MainNumber = n2.MainNumber AND n.Date < n2.Date 
    -> WHERE n2.Date IS NULL AND numbers.MainNumber = @MainNumber 
    -> ; 
+-------------+---------------------------+ 
| @MainNumber | COALESCE(n.Notes, 'None') | 
+-------------+---------------------------+ 
|   2 | None      | 
+-------------+---------------------------+ 
1 row in set (0.00 sec) 
+0

Merci de persévérer avec moi Vous avez compris ce que je voulais, mais je ne sais pas trop comment utiliser vos requêtes J'ai regardé la documentation MySQL sur les variables, puis j'ai essayé de faire précéder la requête avec 'SET @MainNumber = 1;', mais je n'obtiens pas de resultset, j'ai essayé avec '2','''' et ''2'' aussi. number' car il n'y aura pas de ligne dans 'notes' quand MainNumber = 2. Je mettrai à jour la question à nouveau: –

+0

@Alan, mettra à jour le répondre, avoir une erreur dans le second – Unreason

+0

Votre deuxième requête a un attraper: Il retournera deux lignes pour MainNumber = 1 (bien qu'ils soient identiques). Autant que je puisse voir, il retournera toujours autant de lignes qu'il y a de lignes pour le MainNumber donné dans "numbers". Pas de problème si vous l'exécutez tel quel et utilisez simplement la première ligne de résultats, mais en l'utilisant, par exemple. dans une sous-requête, vous pourriez avoir un problème. – sleske

1

Vous pouvez le faire avec un JOIN, comme suggéré par Unreason.

Une autre façon serait une sous-requête:

select distinct s.MainNumber, 
COALESCE(
    (select n.notes from notes n where n.MainNumber=s.MainNumber order by n.Date desc limit 1), 
    'None') as LastNote 
from numbers s 
WHERE s.MainNumber=? 

Notez que la solution en utilisant JOIN ou non de meilleurs résultats, vous devrez essayer.

Notez également que "LIMIT" est spécifique à MySQL (pas ANSI SQL), donc faites attention si vous avez l'intention de migrer vers un autre SGBD.

+0

@Alan, cette réponse fonctionne aussi (renvoie les données demandées). Je l'ai testé. – Unreason

0
SELECT MainNumber, 
     COALESCE(Notes,"None") as Notes, 
     if(BarID=1,"Yes","No") as Banned, 
     if(BarID=2,"Yes","No") as Unpaid, 
     COALESCE(notes.Date,CURRENT_TIMESTAMP) as Date 
FROM numbers LEFT JOIN notes USING (MainNumber) 
    LEFT JOIN bars USING (MainNumber) 
GROUP BY MainNumber,Date 
HAVING Date=COALESCE(MAX(notes.Date),CURRENT_TIMESTAMP) 
+0

Cela ne fonctionne pas. J'ai essayé de le réparer (en changeant les BarTypes, le bar_ref en ref_bars, en ajoutant un 'LEFT JOIN' aux barres et en ajoutant des notes.Date à la clause' SELECT') mais ensuite ça ne donne aucun résultat. Pourriez-vous y travailler un peu? –

+0

bricolé et a témoigné – tobyodavies

Questions connexes