2016-12-22 22 views
2

我得到了一个表用户和一个表任务。任务按重要性排序并分配给用户的任务列表。任务具有状态:准备就绪或未准备好。现在,我想列出所有用户的最重要的任务,也准备好了。访问主表字段并结合Oracle SQL中的LIMIT子句的子查询

有趣的需求是每个用户的任务首先需要过滤和排序,然后选择最重要的任务。这是我想出了:

SELECT Users.name, 
    (SELECT * 
     FROM (SELECT Tasks.description 
       FROM Tasks 
       WHERE Tasks.taskListCode = Users.taskListCode AND Tasks.isReady 
       ORDER BY Tasks.importance DESC) 
     WHERE rownum = 1 
    ) AS nextTask 
    FROM Users 

然而,这导致错误

ORA-00904: "Users"."taskListCode": invalid identifier 

我想原因是oracle does not support correlating subqueries with more than one level of depth。但是,我需要两个级别,以便我可以执行WHERE rownum = 1

我也试了一下没有相关子查询:

SELECT Users.name, Task.description 
FROM Users 
LEFT JOIN Tasks nextTask ON 
    nextTask.taskListCode = Users.taskListCode AND 
    nextTask.importance = MAX(
     SELECT tasks.importance 
     FROM tasks 
     WHERE tasks.isReady 
     GROUP BY tasks.id 
    ) 

这将导致错误

ORA-00934: group function is not allowed here 

我将如何解决这个问题?

+0

你是什么意思由'WHERE task.isready'? Oracle数据库中没有布尔值。 – mathguy

回答

1

请解析函数尝试:

with tp as (select t.*, row_number() over (partition by taskListCode order by importance desc) r 
      from tasks t 
      where isReady = 1 /*or 'Y' or what is positive value here*/) 
select u.name, tp.description 
    from users u left outer join tp on (u.taskListCode = tp.taskListCode) 
    where tp.r = 1; 
+0

非常感谢!现在它适用于我。 – Yogu

2

一个变通此使用keep

SELECT u.name, 
     (SELECT MAX(t.description) KEEP (DENSE_RANK FIRST ORDER BY T.importance DESC) 
     FROM Tasks t 
     WHERE t.taskListCode = u.taskListCode AND t.isReady 
     ) as nextTask 
FROM Users u; 
+0

这个'MAX(t.description)'看起来很奇怪,还是需要解决?否则,这看起来比Kacper的答案更简洁。你知道演出是不同的吗? – Yogu

+0

@Yogu。 。 。事实上,它看起来很奇怪。 MAX()不执行任何操作,因为DENSE_RANK FIRST只匹配一个值。 。 .so MIN()和MAX()会做同样的事情。我从未在可能返回多行值的上下文中使用'KEEP';但我认为聚合函数在某些情况下可能有用。 –

+0

@GordonLinoff - “dense_rank first”可能会遇到关系,如果按“重要性”排序并不严格。可能有三项任务具有相同的重要性。然后MAX会按照字母顺序选择最新的描述。 MIN将按照字母顺序从最重要的任务中选择第一个描述。 – mathguy

1

下面是一个使用聚合而不是分析功能的解决方案。您可能希望针对分析功能解决方案运行此功能,以查看哪个更快;在许多情况下,汇总查询的速度稍快,但这取决于您的数据,索引使用情况等。

此解决方案与Gordon尝试执行的操作类似。我不知道他为什么使用相关子查询来写它,而不是直接连接(并且不知道它是否会起作用 - 我从来没有见过FIRST/LAST函数与相关子查询一起使用)。

它可能无法正常工作完全正确,如果有可能NULLimportance列 - 那么你将需要t.importance)之前添加nulls first。注意:max(t.description)是必要的,因为可能会有“重要性”(两个任务具有相同,对于给定用户而言最重要)的关系。在这种情况下,必须选择一项任务。如果根据重要性进行的排序是严格的(没有关系),那么MAX()不会做任何事情,因为它只在一组值中选择MAX,但编译器事先并不知道,所以它确实需要MAX()

select u.name, 
     max(t.description) keep (dense_rank last order by t.importance) as descr 
from users u left outer join tasks t on u.tasklistcode = t.tasklistcode 
where t.isready = 'Y' 
group by u.name