2

我需要帮助来查找与最近日期、下一个最近日期和之后的日期相对应的行,其中某些条件 ABC 为“Y”并按列名 XYZ ASC 对其进行分组,但 XYZ 可以出现多次。所以,假设 XYZ 是 50,那么对于三年内的行,XYZ 将是 50。我有以下代码执行但只返回数千行中的两行,这是不可能的。我尝试只执行日期条件,但它返回的日期也小于或等于 MAX(DATE)-3。不知道我哪里出错了。

select * from money.cash where DATE =(
  select
  MAX(DATE)
  from
  money.cash
  where
  DATE > (select MAX(DATE)-3 from money.cash)
)
GROUP BY XYZ ASC
having ABC = "Y";

表结构如下(只是示意图,不是实物)。

Comp_ID   DATE   XYZ   ABC  $$$$ ....
1     2012-1-1    10    Y   SOME-AMOUNT
2     2011-1-1    10    Y
3     2006-1-1    10    Y
4     2011-1-1    20    Y
5     2002-1-1    20    Y
6     2000-1-1    20    Y
7     1998-1-1    20    Y

所需的 o/p 将是 XYZ=10 的前三行(按升序排列)和 XYZ=20 的最近 3 个日期。

最后且重要 - 此表的值随着新数据的进入而不断变化。因此,o/p(将在新表中)必须反映第一个/原始/上表中的动态。

4

2 回答 2

1

MySQL 没有对greatest-n-per-group查询友好的功能。

一种选择是...
- 查找MAX(Date)每个组( XYZ)
- 然后使用该结果查找该MAX(Date)日期之前的所有记录
- 然后对该日期之前的所有记录再次执行此操作

这确实是低效的,但 MySQL 还没有有效地做到这一点所需的功能。对不起...

CREATE TABLE yourTable
     (
      comp_id                          INT,
      myDate                           DATE,
      xyz                              INT,
      abc                              VARCHAR(1)
)
;

INSERT INTO yourTable SELECT 1, '2012-01-01', 10, 'Y';
INSERT INTO yourTable SELECT 2, '2011-01-01', 10, 'Y';
INSERT INTO yourTable SELECT 3, '2006-01-01', 10, 'Y';
INSERT INTO yourTable SELECT 4, '2011-01-01', 20, 'Y';
INSERT INTO yourTable SELECT 5, '2002-01-01', 20, 'Y';
INSERT INTO yourTable SELECT 6, '2000-01-01', 20, 'Y';
INSERT INTO yourTable SELECT 7, '1998-01-01', 20, 'Y';


SELECT
  yourTable.*
FROM
(
  SELECT
    lookup.XYZ,
    COALESCE(MAX(yourTable.myDate), lookup.MaxDate)  AS MaxDate
  FROM
  (
    SELECT
      lookup.XYZ,
      COALESCE(MAX(yourTable.myDate), lookup.MaxDate)  AS MaxDate
    FROM
    (
      SELECT
        yourTable.XYZ,
        MAX(yourTable.myDate)  AS MaxDate
      FROM
        yourTable
      WHERE
        yourTable.ABC = 'Y'
      GROUP BY
        yourTable.XYZ
    )
      AS lookup
    LEFT JOIN
      yourTable
        ON  yourTable.XYZ    = lookup.XYZ
        AND yourTable.myDate < lookup.MaxDate
        AND yourTable.ABC    = 'Y'
    GROUP BY
      lookup.XYZ,
      lookup.MaxDate
  )
    AS lookup
  LEFT JOIN
    yourTable
      ON  yourTable.XYZ    = lookup.XYZ
      AND yourTable.myDate < lookup.MaxDate
      AND yourTable.ABC    = 'Y'
  GROUP BY
    lookup.XYZ,
    lookup.MaxDate
)
  AS lookup
INNER JOIN
  yourTable
    ON  yourTable.XYZ     = lookup.XYZ
    AND yourTable.myDate >= lookup.MaxDate
WHERE
  yourTable.ABC = 'Y'
ORDER BY
  yourTable.comp_id
;


DROP TABLE yourTable;

还有其他选择,但它们都有点老套。搜索 SO greatest-n-per-group mysql

我使用您的示例数据的结果:

Comp_ID | DATE     | XYZ | ABC
------------------------------
   1    | 2012-1-1 | 10  |  Y
   2    | 2011-1-1 | 10  |  Y
   3    | 2006-1-1 | 10  |  Y
   4    | 2011-1-1 | 20  |  Y
   5    | 2002-1-1 | 20  |  Y
   6    | 2000-1-1 | 20  |  Y
于 2012-11-13T18:24:39.713 回答
0

这是另一种方式,希望比 Dems 的回答更有效。
使用以下索引对其进行测试(abc, xyz, date)

SELECT m.xyz, m.date                --- for all columns:    SELECT m.* 
FROM 
    ( SELECT DISTINCT xyz
      FROM  money.cash
      WHERE abc = 'Y'
    ) AS dm
  JOIN
    money.cash AS m
      ON  m.abc = 'Y'
      AND m.xyz = dm.xyz
      AND m.date >= COALESCE(
            ( SELECT im.date
              FROM  money.cash AS im
              WHERE im.abc = 'Y'
                AND im.xyz = dm.xyz
              ORDER BY im.date DESC
                LIMIT 1 
                OFFSET 2                --- to get 3 latest rows per xyz 
            ), DATE('1000-01-01') ) ;

如果您有多个相同的行(abc, xyz, date),则查询可能会返回超过 3 行xyz(所有并列在第 3 位的都将显示)。

于 2012-11-13T19:59:06.767 回答