(我的)SQL:如果子查询不是空集,则返回子查询

时间:2017-06-14 13:01:35

标签: mysql sql

这个问题专门针对MySQL,但我试图以标准SQL适用的方式提出这个问题。

上下文:我试图通过以下方式确定结束日期:如果在输入的开始日期之后存在另一个开始日期,请使用现有的开始日期作为结束日期;否则,结束日期应为输入开始日期后30天。

我尝试的解决方案类似于以下内容:

SELECT
  IF(
    EXISTS(  
      SELECT
        DISTINCT start_date
      FROM table
      WHERE ? < start_date AND
            identifier = ?
      ORDER BY start_date
      LIMIT 1
    ), (
    SELECT
      DISTINCT start_date
    FROM table
    WHERE ? < start_date AND
          identifier = ?
    ORDER BY start_date
    LIMIT 1),
    DATE_ADD(?, INTERVAL 30 DAY)
  ) AS end_date

我的解决方案有效,但我希望有一个更优雅,非重复的解决方案。

通用解决方案是 - 如果子查询存在 - 返回子查询中的值;否则,可以返回其他内容。

3 个答案:

答案 0 :(得分:1)

而不是子查询执行左连接(到表本身)

SELECT
COALESCE(t2.start_date, t1.start_date)
FROM table t1
LEFT JOIN table t2 ON t1.identifier = t2.identifier AND t1.start_date > t2.start_date

左连接条目要么存在要么不存在,这意味着它不是null或null。 COALESCE()函数返回其第一个非空的参数。

答案 1 :(得分:1)

根据您自己的回答,我建议使用:

SELECT
  COALESCE((
    SELECT MIN(start_date)
    FROM TABLE
    WHERE start_date > ? 
    AND   identifier = ?), (
    SELECT
      DATE_ADD(?, INTERVAL 30 DAY)
    )) AS end_date 

似乎更容易理解恕我直言。即使它看起来不同,它几乎在幕后做同样的事情。

答案 2 :(得分:0)

根据fancyPants'解决方案,我使用COALESCE,但方式完全不同(因此我无法将响应完全标记为已接受)。

SELECT
  COALESCE((
    SELECT
      DISTINCT start_date
    FROM TABLE
    WHERE ? < start_date AND
          identifier = ?
    ORDER BY start_Date
    LIMIT 1), (
    SELECT
      DATE_ADD(?, INTERVAL 30 DAY)
    )) AS end_date

上述查询将按预期完成。您的子查询是COALESCE语句的第一个参数,另一个查询是第二个参数。