2010-11-26 5 views
1

C'est une chose assez étrange à mettre en mots, mais je veux la ligne quand l'article est passé pour la première fois à un tarif/client. Si un article change de client, la date du commutateur doit être retournée, quelle que soit la différence de tarif. Si un élément change de projet, la date retournée ne doit pas changer, sauf si le tarif du nouveau projet n'est pas le même que l'ancien.Récupère la date à laquelle un champ a été modifié pour la première fois à sa valeur actuelle

Je ne sais pas trop comment je peux le rendre plus clair, mais je suis ouvert aux suggestions.

Ma requête ressemble à ceci:

SET @id = 1; 
SELECT DISTINCT 
    ip.ItemID, 
    ip.ProjectID, 
    p.TariffID, 
    p.CustomerID, 
    cs.Date 
FROM item_project ip 
LEFT JOIN item_project ip1 
    ON ip.ItemID = ip1.ItemID 
    AND ip.Date < ip1.Date 
LEFT JOIN project p 
    ON ip.ProjectID = p.ProjectID 
LEFT JOIN (
    SELECT 
     ip.ItemID, 
     ip.Date 
    FROM item_project ip 
    LEFT JOIN item_project ip1 
     ON ip.ProjectID = ip1.ProjectID 
     AND ip.Date > ip1.Date 
    LEFT JOIN project p 
     ON ip.ProjectID = p.ProjectID 
    WHERE ip.ItemID = @id 
     AND ip1.ItemID IS NULL 
     AND p.CustomerID = (
      SELECT p.CustomerID 
      FROM project p 
      LEFT JOIN item_project ip 
       ON p.ProjectID = ip.ProjectID 
      LEFT JOIN item_project ip1 
       ON ip.ItemID = ip1.ItemID 
       AND ip.Date < ip1.Date 
      WHERE ip.ItemID = @id 
       AND ip1.ItemID IS NULL 
      ) 
     AND p.TariffID = (
      SELECT p.TariffID 
      FROM project p 
      LEFT JOIN item_project ip 
       ON p.ProjectID = ip.ProjectID 
      LEFT JOIN item_project ip1 
       ON ip.ItemID = ip1.ItemID 
       AND ip.Date < ip1.Date 
      WHERE ip.ItemID = @id 
       AND ip1.ItemID IS NULL 
      ) 
) AS cs 
    ON ip.ItemID = cs.ItemID 
WHERE ip.ItemID = @id 
    AND ip1.ItemID IS NULL 

qui me donne

"ItemID","ProjectID","TariffID","CustomerID","Date" 
"1","2","1","1","2010-11-10 00:00:00" 

qui est la mauvaise date

SET @id=2 me donne:

"2","2","1","1",NULL 

Wh ich est correcte, à l'exception de la date

SET @id=3 me donne:

"3","2","1","1",NULL 

qui est aussi correcte, à l'exception de la date.

est ici la base de données

CREATE TABLE IF NOT EXISTS `item_project` (
    `ID` int(10) unsigned NOT NULL auto_increment, 
    `ItemID` varchar(10) NOT NULL, 
    `ProjectID` int(10) unsigned NOT NULL, 
    `Date` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, 
    PRIMARY KEY (`ID`) 
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1; 

INSERT INTO `item_project` (`ID`, `ItemID`, `ProjectID`, `Date`) VALUES 
    (1, '1', 1, '2010-11-05 00:00:00'), 
    (2, '1', 2, '2010-11-10 00:00:00'), 
    (3, '1', 3, '2010-11-20 00:00:00'), 
    (4, '2', 2, '2010-11-21 00:00:00'), 
    (5, '3', 4, '2010-11-21 00:00:00'), 
    (6, '3', 2, '2010-11-22 00:00:00'), 
    (7, '1', 2, '2010-11-23 00:00:00'), 

CREATE TABLE IF NOT EXISTS `project` (
    `ProjectID` int(10) unsigned NOT NULL auto_increment, 
    `Name` varchar(45) NOT NULL, 
    `TariffID` varchar(45) NOT NULL, 
    `CustomerID` varchar(45) NOT NULL, 
    PRIMARY KEY (`ProjectID`) 
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1; 

INSERT INTO `project` (`ProjectID`, `Name`, `TariffID`, `CustomerID`) VALUES 
    (1, 'Test', '2', '1'), 
    (2, 'Another test', '1', '1'), 
    (3, 'Project1', '1', '1'), 
    (4, 'Main project', '2', '2'); 

CREATE TABLE IF NOT EXISTS `tariff` (
    `TariffID` int(10) unsigned NOT NULL auto_increment, 
    `Tariff` varchar(45) NOT NULL, 
    PRIMARY KEY (`TariffID`) 
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1; 

INSERT INTO `tariff` (`TariffID`, `Tariff`) VALUES 
    (1, 'Tariff 1'), 
    (2, 'Tariff 2'); 

Modifier: Un élément peut revenir à un ancien tarif ou d'un client. Dans ce cas, la date indiquée devrait être la date à laquelle cela s'est produit.

Répondre

1

Ma précédente réponse semblait également fonctionner avec le nouveau jeu de données, mais je pense que je comprends le problème que vous voyez. Nouvelle solution proposée:

SELECT i_general.ItemID, ProjectID, TariffID, CustomerID, the_date 
FROM 
(
    SELECT ip.ItemID, p.ProjectID, p.TariffID, p.CustomerID 
    FROM item_project ip 
    INNER JOIN project p ON ip.ProjectID = p.ProjectID 
    INNER JOIN tariff t ON p.TariffID = t.TariffID 
    INNER JOIN (
     SELECT ip.ItemID, MAX(Date) AS max_date 
     FROM item_project ip 
     GROUP BY ip.ItemID 
    ) ip_max ON ip_max.ItemID=ip.ItemID AND ip_max.max_date=ip.Date 
) i_general 
INNER JOIN 
(
    SELECT ItemID_1 AS ItemID, IF(MAX(Next_Change_Date) IS NULL, MIN(Date_1), MAX(Next_Change_Date)) AS the_date 
    FROM 
    (
     SELECT ItemID_1, Date_1, MIN(Date_2) AS Next_Change_Date 
     FROM 
     (
      SELECT ip1.ItemID AS ItemID_1, ip1.Date AS Date_1, p1.TariffID AS TariffID_1, p1.CustomerID AS CustomerID_1 
      FROM item_project ip1 
      INNER JOIN project p1 ON ip1.ProjectID = p1.ProjectID 
     ) ipp1 
     LEFT JOIN 
     (
      SELECT ip2.ItemID AS ItemID_2, ip2.Date AS Date_2, p2.TariffID AS TariffID_2, p2.CustomerID AS CustomerID_2 
      FROM item_project ip2 
      INNER JOIN project p2 ON ip2.ProjectID = p2.ProjectID 
     ) ipp2 ON ItemID_1=ItemID_2 AND Date_1 < Date_2 AND ((TariffID_1!=TariffID_2 OR CustomerID_1!=CustomerID_2) AND Date_2 IS NOT NULL) 
     GROUP BY ItemID_1, Date_1 
    ) i_date_pair_info 
    GROUP BY ItemID 
) i_date_info ON i_date_info.ItemID = i_general.ItemID

Je pense qu'il fournit le résultat que vous recherchez.

Il est plus robuste que l'un des sous-requêtes internes, i_date_pair_info, explicitement paires chaque jour avec tous les changements suite, s'il y a un. Le regroupement élimine alors tout mais le changement le plus tôt.

+0

Malheureusement, je n'arrive pas à faire fonctionner cela avec les données réelles. Cela fonctionne avec les données de test dans le même scénario, donc je vous donnerai la prime à la fin de la journée si personne d'autre ne publie quoi que ce soit. –

+0

Bummer. Si vous pouvez publier de nouvelles données de test, j'aurai probablement le temps d'en faire un autre. Merci. – Riedsio

+0

ne pouvait pas fonctionner, mais il s'avère que ce serait beaucoup mieux dans une table séparée, car nous avons maintenant apparemment besoin de données historiques, aussi. Merci d'avoir essayé, cependant. –

2

Situation intéressante. Voici ce que je suis venu avec

SELECT i_general.ItemID, ProjectID, TariffID, CustomerID, the_date 
FROM 
(
    SELECT 
     ip.ItemID, 
     p.ProjectID, 
     p.TariffID, 
     p.CustomerID 
    FROM item_project ip 
    INNER JOIN project p ON ip.ProjectID = p.ProjectID 
    INNER JOIN tariff t ON p.TariffID = t.TariffID 
    INNER JOIN (
     SELECT 
      ip.ItemID, MAX(Date) AS max_date 
     FROM item_project ip 
     GROUP BY ip.ItemID 
     ) ip_max ON ip_max.ItemID=ip.ItemID AND ip_max.max_date=ip.Date 
) i_general 
INNER JOIN (
    SELECT ip1.ItemID, IF(MIN(ip2.Date) IS NULL,MIN(ip1.Date),MIN(ip2.Date)) AS the_date 
    FROM item_project ip1 
    INNER JOIN project p1 ON ip1.ProjectID = p1.ProjectID 
    LEFT JOIN item_project ip2 ON ip1.ItemID=ip2.ItemID AND ip1.Date < ip2.Date 
    LEFT JOIN project p2 ON ip2.ProjectID = p2.ProjectID AND (p2.TariffID!=p1.TariffID OR p2.CustomerID!=p1.CustomerID) 
    GROUP BY ip1.ItemID 
    ) i_date_info ON i_date_info.ItemID = i_general.ItemID 

Bien sûr, vous pouvez insérer dans quelques WHERE ItemID = @id comme bon vous semble. Plus il y a de requêtes internes, mieux c'est.

En tout cas, il en résulte

+--------+-----------+----------+------------+---------------------+ 
| ItemID | ProjectID | TariffID | CustomerID | the_date   | 
+--------+-----------+----------+------------+---------------------+ 
| 1  |   3 | 1  | 1   | 2010-11-10 00:00:00 | 
| 2  |   2 | 1  | 1   | 2010-11-21 00:00:00 | 
| 3  |   2 | 1  | 1   | 2010-11-22 00:00:00 | 
+--------+-----------+----------+------------+---------------------+ 

Ainsi, il semble fonctionner avec l'ensemble de données existant. Lemme savoir si vous pouvez fournir des données de test sur lesquelles il ne fonctionne pas.

+1

+1 Cela fonctionne définitivement pour les données de test, mais je semble avoir des problèmes avec les données réelles. Quand j'identifie un motif, j'ajoute quelques données de test supplémentaires, mais cela devra attendre jusqu'à la semaine prochaine. –

+0

Mise à jour de la question.Les données qui causent des problèmes sont les éléments qui changent d'un client/tarif, puis reviennent. –

Questions connexes