2017-06-14 237 views
0

这个问题专门针对MySQL,但我试图以标准SQL适用的方式提问。(My)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 

我的解决方案的工作,但我希望有一个更优雅的,不重复的解决方案。如果子查询存在,则—返回子查询中的值;否则,可能会返回其他内容。

回答

1

在回答自己的答案,我会建议使用:

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

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

+0

更有效,没有'ORDER BY'语句,你清楚地指出我完全忘记了'MIN()'是一个函数!成功。标记为已接受(主要是因为我不想标记自己的问题的答案,但也因为你是一个更好的解决方案)。 – Mattallurgy

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 

左侧加入条目或者是有还是没有,这意味着它不为空或空。 COALESCE()函数返回其非空的第一个参数。

+0

该解决方案是生产矿山不可或缺的;尽管'JOIN'语句并不完全符合我想要做的,但我不熟悉'COALESCE'是如何工作的。你对我对这个功能的理解的进一步让我能够开发出我认为被接受的解决方案(一旦我可以这么做)。谢谢! – Mattallurgy

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声明的第一个参数,另一个查询是第二个。