复杂的SELECT语句包括多个连接而不返回所需的结果

时间:2014-08-04 18:11:39

标签: mysql join relational-database

我正在尝试创建一个SELECT来从几个表中返回信息。我有它的工作,但后来收到了额外的要求,现在我无法弄清楚如何得到我想要的东西。

我有一个表格,其中包含可能包含在报告中的程序信息(基于进一步的要求)......此文件称为里程碑。 我有另一个表,其中包含与程序相关的项目 - 如果ID匹配 我有一个新表,有一个手动输入的覆盖结束日期 - 这是新的要求。里程碑表中有一个系统结束日期,但如果输入此覆盖日期,则它优先于系统结束日期。如果已输入覆盖日期,则异常文件将具有相同的程序ID和两个与里程碑表中的日期匹配的日期。

日期是yyyy-mm-dd格式化

Example data:

Milestones:

prgId | startDate  | endDate
------------------------------
  123 | 2014-03-09 | 2014-11-10
  123 | 2014-07-10 | 2014-11-10
  324 | 2014-05-09 | 2014-11-12

exceptions:

prgId | startDate  | overEnd
-------------------------------
  123 | 2014-03-09 | 2014-05-31

projects:

prgId | cust
-------------
  123 | 12121
  123 | 4323

我目前要归还的是:

prgId       prjCnt       startDate       endDate     overEnd
123           2          2014-03-09     2014-11-10   2014-05-31
123           2          2014-07-10     2014-11-10
324           0          2014-05-09     2014-11-12

我确实意识到,现在程序123的两个项目将显示两个行 - 我们将寻找一种方法将它们与正确的那些相关联,但还没有。

我们添加了覆盖日期要求,以便当前程序的报告不会同时显示“123”行,而只会显示当前程序(第二行)。

我当前的SELECT就像这样(对不起,我不能让它更容易显示它真的很长):

SELECT milestones.*,  newtbl.prjcnt, exceptions.overEnd  
FROM milestones 
LEFT JOIN ((
     SELECT prgGuid, count( prgGuid ) AS prjcnt 
     FROM projects 
     GROUP BY prgGuid 
    ) AS newtbl ) 
ON milestones.prgId = newtbl.prgId 
LEFT JOIN exceptions 
ON (milestones.prgId = exceptions.prgId 
AND milestones.startDate = exceptions.startDate) 
WHERE <(milestones.startDate > '2013-00-00') 
AND (milestones.startDate <= CURDATE() AND milestones.endDate >= CURDATE()) 
ORDER BY milestones.endDate, milestones.startDate DESC 

现在我想要的是将此更改为仅抓取程序,项目计数,开始和结束日期以及开始日期为2013年至当前日期且尚未结束的程序的覆盖结束日期。现在....如果一个程序有一个覆盖结束日期并且该结束日期是当前的(&gt; =当前日期),那么它应该被包含但是如果覆盖日期是NULL或者&lt; =当前日期,我不想要包括它。

我想要归还的是:

prgId       prjCnt       startDate       endDate     overEnd
123           2          2014-07-10      2014-11-10
324           0          2014-05-09      2014-11-12

之前的第一行已过期,所以不应该显示。

我尝试了一些事情,但我最终没有结果,或者我得到了我目前得到的所有东西。

有人可以帮我弄清楚SELECT应该是什么吗?

1 个答案:

答案 0 :(得分:1)

因此,如果我关注您,您的DDL可能如下所示:

CREATE TABLE MILESTONES
    (`prgId` int, `startDate` varchar(10), `endDate` varchar(10))
;

INSERT INTO MILESTONES
    (`prgId`, `startDate`, `endDate`)
VALUES
    (123, '2014-03-09', '2014-11-10'),
    (123, '2014-07-10', '2014-11-10'),
    (324, '2014-05-09', '2014-11-12')
;

CREATE TABLE EXCEPTIONS
    (`prgId` int, `startDate` varchar(10), `overEnd` varchar(10))
;

INSERT INTO EXCEPTIONS
    (`prgId`, `startDate`, `overEnd`)
VALUES
    (123, '2014-03-09', '2014-05-31')
;

CREATE TABLE PROJECTS
    (`prgId` int, `cust` int)
;

INSERT INTO PROJECTS
    (`prgId`, `cust`)
VALUES
    (123, 12121),
    (123, 4323)
;

您当前的查询不起作用(请注意我已根据您的问题更正了我认为是您的查询中的错别字):

SELECT milestones.*,  newtbl.prjcnt, exceptions.overEnd  
FROM milestones 
LEFT JOIN ((
     SELECT prgId, count( prgId ) AS prjcnt 
     FROM projects 
     GROUP BY prgId 
    ) AS newtbl ) 
ON milestones.prgId = newtbl.prgId 
LEFT JOIN exceptions 
ON (milestones.prgId = exceptions.prgId 
AND milestones.startDate = exceptions.startDate) 
WHERE (milestones.startDate > '2013-00-00') 
AND (milestones.startDate <= CURDATE() AND milestones.endDate >= CURDATE()) 
ORDER BY milestones.endDate, milestones.startDate DESC 

工作解决方案如下所示:

SELECT DISTINCT
  M.prgId as PRGID
, ( SELECT COUNT(X.prgID)
    FROM PROJECTS X
    WHERE X.prgID = M.prgID ) as PRJCNT
, M.startDate as STARTDATE
, M.endDate as ENDDATE
, COALESCE(E.overEnd,'') as OVEREND
FROM MILESTONES M
  LEFT OUTER JOIN PROJECTS P
    ON M.prgId = P.prgId
  LEFT JOIN EXCEPTIONS E
    ON M.prgId = E.prgId
   AND M.startDate = E.startDate
WHERE M.startDate > '2013-01-01'
  AND M.startDate <= CURDATE()
  AND M.endDate >= CURDATE()
  AND ( E.overEnd IS NULL
     OR E.overEnd > CURDATE() )

您可以在此处看到它:SQLFiddle

请注意,该解决方案依赖于COALESCE函数来实现干净输出,并且在WHERE子句中放置了更多业务规则。