简体   繁体   English

在子查询中使用按个案排序

[英]Using an order by case in a sub-query

Each schedule has many ramps, and each ramp has an end_date . 每个时间表都有许多坡度,并且每个坡度都有一个end_date

I need to list all my ramps, along with an extra field that contains the id of the ramp with the latest end date for that schedule. 我需要列出所有坡道,以及一个额外的字段,其中包含坡道的ID和该计划的最新结束日期。 I also need to be able to use this extra field in my WHERE clause. 我还需要能够在我的WHERE子句中使用此额外字段。

This is typically a case for a sub-query using the MAX function, except for one problem: the ramp's end_date field can be null, indicating the ramp is current. 对于使用MAX函数的子查询,通常是这种情况,除了一个问题:斜坡的end_date字段可以为null,表示斜坡是当前的。 Thus, SELECT MAX(end_date) doesn't work, since null values are 'smaller' than non-null values. 因此, SELECT MAX(end_date)不起作用,因为null值比非null值“小”。

So far, this is what I've come up with: 到目前为止,这是我想出的:

SELECT r1.*,
    (SELECT r2.id
    FROM ramp as r2
    WHERE schedule_id = r.schedule_id
    ORDER BY IF(end_dte is NULL, '9999-99-99', end_dte) DESC
    LIMIT 1) as latestId
FROM ramp as r1

This produces this table, which is exactly what I want: 这将产生此表,这正是我想要的:

+-------+-------------+------------+-----------------+--------+------------+------------+----------+
| id    | schedule_id | suppr_flag | comment         | months | start_dte  | end_dte    | latestId |
+-------+-------------+------------+-----------------+--------+------------+------------+----------+
|    16 |           7 | NULL       | NULL            |   NULL | 2008-06-23 | NULL       |       16 |
|    15 |           6 | NULL       | NULL            |   NULL | 2007-05-01 | 2007-12-31 |       15 |
|    13 |           5 | NULL       | 1-15 deals      |   NULL | 2004-08-11 | NULL       |       13 |
|    11 |           4 | NULL       | NULL            |   NULL | 2005-08-11 | NULL       |       11 |
|    12 |           4 | NULL       | NULL            |     12 | 2004-08-11 | 2005-08-10 |       11 |
|    17 |          13 | NULL       | NULL            |      6 | 2009-03-05 | 2009-09-04 |       19 |
|    18 |          13 | NULL       | NULL            |      6 | 2009-09-05 | 2010-03-04 |       19 |
|    19 |          13 | NULL       | NULL            |   NULL | 2010-03-05 | NULL       |       19 |
|    20 |          14 | NULL       | NULL            |     12 | 2001-06-18 | 2008-06-17 |       20 |

except I cannot use latestId in a WHERE clause (it's an unknown column). 除非我不能在WHERE子句中使用latestId (这是一个未知列)。

Do you have any ideas? 你有什么想法?

A quick solution would be to repeat the whole query on the ORDER BY clause, because an alias is not seen there, but I don't like much how the query will look: 一种快速的解决方案是在ORDER BY子句上重复整个查询,因为在那里没有看到别名,但是我不太喜欢查询的外观:

SELECT r1.*,
    (SELECT r2.id
    FROM ramp as r2
    WHERE schedule_id = r1.schedule_id
    ORDER BY IF(end_dte is NULL, '9999-99-99', end_dte) DESC
    LIMIT 1) as latestId
FROM ramp as r1
ORDER BY
    (SELECT r2.id
    FROM ramp as r2
    WHERE schedule_id = r1.schedule_id
    ORDER BY IF(end_dte is NULL, '9999-99-99', end_dte) DESC
    LIMIT 1);

Or you can SELECT from your original query, and order the result: 或者,您可以从原始查询中进行SELECT,然后对结果进行排序:

SELECT s.*
FROM (
  SELECT r1.*,
      (SELECT r2.id
      FROM ramp as r2
      WHERE schedule_id = r1.schedule_id
      ORDER BY IF(end_dte is NULL, '9999-99-99', end_dte) DESC
      LIMIT 1) as latestId
  FROM ramp as r1
) s
ORDER BY s.latestId

But if I understand your logic correcty, you could use this query to get the maximum end_dte for every schedule_id : 但是,如果我了解您的逻辑正确性,则可以使用此查询来获取每个schedule_id的最大end_dte

SELECT schedule_id, MAX(COALESCE(end_dte, '9999-12-31')) max_dte
FROM ramp
GROUP BY schedule_id;

Then you can JOIN this query with ramp again to get the ID associated to the maximum end_dte . 然后,您可以再次使用ramp联接此查询,以获取与最大end_dte关联的ID。 On the ON clause you will neet to use COALESCE again: 在ON子句中,您将无需再次使用COALESCE:

SELECT r1.schedule_id, r2.id as latestId
FROM (
  SELECT schedule_id, MAX(COALESCE(end_dte, '9999-12-31')) max_dte
  FROM ramp
  GROUP BY schedule_id) r1 INNER JOIN
  ramp r2
  ON r1.max_dte = COALESCE(r2.end_dte, '9999-12-31')
     AND r1.schedule_id = r2.schedule_id

And then you can join this again to get the result you need: 然后,您可以再次加入以获得所需的结果:

SELECT ramp.*, m.latestId
FROM
  ramp INNER JOIN (
    SELECT r1.schedule_id, r2.id as latestId
    FROM (
      SELECT schedule_id, MAX(COALESCE(end_dte, '9999-12-31')) max_dte
      FROM ramp
      GROUP BY schedule_id) r1 INNER JOIN
      ramp r2
      ON r1.max_dte = COALESCE(r2.end_dte, '9999-12-31')
         AND r1.schedule_id = r2.schedule_id
      ) m ON ramp.schedule_id = m.schedule_id
ORDER BY
  latestId

Please see fiddle here . 请看这里的小提琴。 Notice that I am using '9999-12-31' and not '9999-99-99', the first one is a valid date, the second not. 请注意,我使用的是“ 9999-12-31”,而不是“ 9999-99-99”,第一个是有效日期,第二个不是有效日期。

Edit 编辑

If you also wish to consider the fact that more than one schedule_id shares the same maximum date, and you just need the latest (maximum) ID in this case, you could use a GROUP BY query, and a MAX aggregated function: 如果您还希望考虑一个以上的schedule_id共享相同的最大日期这一事实,并且在这种情况下只需要最新的(最大)ID,则可以使用GROUP BY查询和MAX聚合函数:

SELECT r1.schedule_id, MAX(r2.id) as latestId
FROM (
  SELECT schedule_id, MAX(COALESCE(end_dte, '9999-12-31')) max_dte
  FROM ramp
  GROUP BY schedule_id) r1 INNER JOIN
  ramp r2
  ON r1.max_dte = COALESCE(r2.end_dte, '9999-12-31')
     AND r1.schedule_id = r2.schedule_id
GROUP BY
  r1.schedule_id

and you use this updated version in your main query. 并在主查询中使用此更新版本。

you could use TWO columns in your order... first for non-null indication flag, then by the date. 您可以按顺序使用两列...首先是非空指示标志,然后是日期。 Change what you had of... 改变你拥有的...

ORDER BY IF(end_dte is NULL, '9999-99-99', end_dte) DESC

to

ORDER BY
   IF( end_dte is null, 1, 2 ),
   end_dte DESC

This way, it pushes all "NULL" end dates to the top of the list (via IF() value would be 1 vs 2 for anything else that HAD a date), THEN, by the date descending 这样,它将所有“ NULL”结束日期都推到列表的顶部(通过IF()值,对于具有日期的任何其他内容,该值将为1 vs 2),然后按日期降序

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM