Получить дату, когда поле было впервые изменено на его текущее значение - PullRequest
1 голос
/ 26 ноября 2010

Это довольно неловкая вещь, чтобы выразить словами, но я хочу строку, когда товар впервые переключился на тариф / клиента. Если товар меняет клиента, то должна быть возвращена дата смены, независимо от разницы в тарифах. Если элемент переключает проекты, возвращаемая дата не должна изменяться, если только тариф нового проекта не совпадает со старым.

Не совсем уверен, как я могу сделать это понятнее, но я открыт для предложений.

Мой запрос выглядит так:

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

, что дает мне

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

неправильная дата

SET @id=2 дает мне:

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

Что правильно, кроме даты

SET @id=3 дает мне:

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

, что также правильно, кроме даты.

Вот база данных

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');

Редактировать : Элемент может вернуться к старому тарифу или клиенту. В этом случае указанная дата должна быть датой, когда это произошло.

Ответы [ 2 ]

2 голосов
/ 26 ноября 2010

Интересная ситуация. Вот что я придумал

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

Конечно, вы можете вставить несколько WHERE ItemID = @id, как считаете нужным. Чем больше будет внутренних запросов, тем лучше.

В любом случае это приводит к

+--------+-----------+----------+------------+---------------------+
| 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 |
+--------+-----------+----------+------------+---------------------+

Итак, похоже, что он работает с существующим набором данных. Позвольте мне знать, если вы можете предоставить тестовые данные, с которыми он не работает.

1 голос
/ 29 ноября 2010

Мой предыдущий ответ также работал с новым набором данных, но я думаю, что понимаю проблему, с которой вы столкнулись.Новое предлагаемое решение: 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

Я думаю, что оно дает результат, который вы ищете.

Это более надежно в том, что один из внутренних подзапросов i_date_pair_info явно связывает каждую датусо всеми последующими изменениями , если таковые имеются.Группировка затем удаляет все, кроме самых быстрых изменений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...