如何绕过子查询中对外表的引用?

时间:2013-05-03 11:33:00

标签: mysql subquery aggregate-functions

我一直在处理这两个表:

文献

id    company_id    etc
=======================
1     2             x
2     2             x

id    document_id   version    date_created    date_issued   date_accepted
==========================================================================
1     1             1          2013-04-29      2013-04-30    NULL
2     2             1          2013-05-01      NULL          NULL
3     1             2          2013-05-01      2013-05-01    2013-05-03

有一个页面,我想列出所有文件及其属性。 我想从每个文档中添加一个具有状态的状态。 状态可以从相应Version具有的最新日期派生。 可能会接受旧版本。

我正在寻找的查询结果是这样的:

id    company_id    etc   status
==================================
1     2             x     accepted
2     2             x     created

我首先创建了一个结合了所有日期并在其旁边添加状态的查询。 它按预期工作,当我添加document_id时,事情看起来没问题。

SELECT `status`
FROM (
    SELECT max(date_created) as `date`,'created' as `status` FROM version WHERE document_id = 1
    UNION
    SELECT max(date_issued),'issued' FROM version WHERE document_id = 1
    UNION
    SELECT max(date_accepted),'accepted' FROM version WHERE document_id = 1
    ORDER BY date DESC
    LIMIT 1
) as maxi

当我尝试将此查询作为子查询合并时,我无法使其工作。

SELECT *, (
  SELECT `status` FROM (
    SELECT max(date_created) as `date`,'created' as `status`FROM version WHERE document_id = document.id
    UNION
    SELECT max(date_issued),'issued' FROM version WHERE document_id = document.id
    UNION
    SELECT max(date_accepted),'accepted' FROM version WHERE document_id = document.id
    ORDER BY date DESC
    LIMIT 1
  ) as maxi
) as `status`
FROM `document`

这会给我一个错误Unknown column 'document.id' in 'where clause'。所以我在SO处阅读并认为它无法达到值offer.id,因为它是子查询中的子查询。所以我尝试采用另一种方法并立即获取所有状态,以避免WHERE语句,并加入它们。我最后得到了下一个查询。

SELECT MAX(`date`),`status`, document_id
FROM (
    SELECT datetime_created as `date`, 'created' as `status`,document_id FROM `version`
    UNION
    SELECT datetime_issued, 'issued',document_id FROM `version`
    UNION
    SELECT datetime_accepted, 'accepted',document_id FROM `version`
) as dates
GROUP BY offer_id

这次没有错误,但我意识到status可能不是正确的,因为它在GROUP BY期间丢失了。我已经尝试了两者的组合,但这两个缺点一直阻碍着我。任何人都可以建议如何在单个查询中执行此操作而不更改我的数据库? (我知道将日期保存在一个单独的表中只是一件事)

3 个答案:

答案 0 :(得分:1)

我没有对此进行测试,但您可以这样做(您可能需要调整细节)

它基本上是从一个完全不同的角度来看待它。

 select
    d.*,
    (CASE GREATEST(ifnull(v.date_created, 0), ifnull(v.date_issued,0), ifnull(v.date_accepted,0) ) 
      WHEN null THEN 'unknown'
      WHEN v.date_accepted THEN 'accepted'
      WHEN v.date_issued THEN 'issued'
      WHEN v.date_created THEN 'created'
      END) as status 
from document d
left join version v on 
    v.document_id = d.document_id and 
    not exists (select 1 from (select * from version) x where x.document_id = v.document_id and x.id <> v.id and x.version > v.version)

答案 1 :(得分:0)

select Doc.document_id,Doc.company_id,Doc.etc,f.status
from Document Doc
inner join 
    (select Ver.document_id,
    case when Ver.date_accepted is not null then 'Accepted'
    when Ver.date_issued is not null then 'Issued'
    when Ver.date_created is not null then 'Created'
    end as status
from version Ver
inner join (
                select document_id,MAX(version) VersionId
                from version
                group by document_id
            )t on t.document_id=Ver.document_id 
where t.VersionId=Ver.version
)f on Doc.document_id=f.document_id

<强> SQL Fiddle

答案 2 :(得分:0)

您可以规范化表格设计,将状态/日期移到与版本不同的表格上吗?

如果不是这样的话: -

SELECT Document.id, Document.company_id, Document.etc, CASE WHEN Sub1.status = 3 THEN 'accepted' WHEN Sub1.status = 2 THEN 'issued' WHEN Sub1.status = 1 THEN 'created' ELSE NULL END AS status
FROM Document
INNER JOIN (
    SELECT document_id, MAX(CASE WHEN date_accepted IS NOT NULL THEN 3 WHEN date_issued IS NOT NULL THEN 2 WHEN date_created IS NOT NULL THEN 1 ELSE NULL END) AS status 
    FROM Version
    GROUP BY document_id
) Sub1
ON Document.id = Sub1.document_id

子选择从版本表中获取任何文档的最高状态。每个可能的版本最高状态都作为数字返回,并通过对文档ID进行分组,它将获得任何版本的最高状态。这将与Document表以及转换为文本说明的版本号的编号连接在一起。