2013-03-06 48 views
3

我有同一个表都工作了,我基本上是希望将搜索结果结合起来,例如2个类似的查询是什么第一查询不返回第二个查询提供默认值。我在这里尽可能简化了问题。我使用Oracle btw。SQL一个独特的列值合并结果集

表有帐号在它的信息的数量的帐户,并有用于与commit_date插入帐户信息时,要告诉每个帐户多个条目。我需要获取当前某个日期的帐户信息。

的查询需要帐户ID和日期的列表。

下面是该查询:

-- Select the row which was current for the accounts for the given date. (won't return anything for an account which didn't exist for the given date) 
SELECT actr.* 
FROM Account_Information actr 
WHERE actr.account_id in (30000316, 30000350, 30000351) 
AND actr.commit_date <= to_date('2010-DEC-30','YYYY-MON-DD ') 
AND actr.commit_date = 
(
    SELECT MAX(actrInner.commit_date) 
    FROM Account_Information actrInner 
    WHERE actrInner.account_id = actr.account_id 
    AND actrInner.commit_date <= to_date('2010-DEC-30','YYYY-MON-DD ') 
) 

这看起来有点丑陋,但它返回一个单独的行,这是在指定日期的当前每个帐户。问题是,如果帐户在给定日期之后才存在,它不会返回任何内容。

选择每个帐户的最早的帐户信息的繁琐 - 我并不需要提供一个日期为这一个:

-- Select the earliest row for the accounts. 
SELECT actr.* 
FROM Account_Information actr 
WHERE actr.account_id in (30000316, 30000350, 30000351) 
AND actr.commit_date = 
(
    SELECT MAX(actrInner .commit_date) 
    FROM Account_Information actrInner 
    WHERE actrInner .account_id = actr.account_id 
) 

但我想在这样的方式合并结果集:

对于每一个客户,如果在第一个结果集为它帐户信息 - 使用。 否则,请使用第二个结果集中的帐户信息。

我研究过所有的联接我可以没有成功使用。工会几乎这样做,但他们只会合并为独特的行。我想根据每行中的帐户ID进行合并。

Sql Merging two result sets - 我的情况显然要复杂得多

SQL to return a merged set of results - 可能是我能够适应这种技术?我是一个被迫编写SQL的程序员,我不能很好地遵循这个例子,看看我能够如何修改它以满足我的需要。

回答

5

标准的方式做,这是一个左外连接和合并。也就是说,你的整体查询将是这样的:

SELECT ... 
FROM defaultQuery 
LEFT OUTER JOIN currentQuery ON ... 

如果你做了SELECT *,每一行会对应到当前的帐户数据加上您的默认值。和我一起到目前为止?

现在,而不是SELECT *,你想返回的每一列,你配对列做COALESCE()

SELECT COALESCE(currentQuery.columnA, defaultQuery.columnA) ... 

如果存在的话这将选择当前帐户数据,否则将选择默认数据。

+0

啊,谢谢你方便的解释。我认为我应该可以通过加入来完成,但无法弄清楚如何在列上加倍。我之前没有使用coalesce,这似乎是拼图的缺失部分。我现在就读它了! – Scott 2013-03-07 05:33:19

1

为此,您可以更直接地使用分析功能:

select * 
from (SELECT actr.*, max(commit_date) over (partition by account_id) as maxCommitDate, 
      max(case when commit_date <= to_date('2010-DEC-30','YYYY-MON-DD ') then commit_date end) over 
        (partition by account_id) as MaxCommitDate2 
     FROM Account_Information actr 
     WHERE actr.account_id in (30000316, 30000350, 30000351) 
    ) t 
where (MaxCommitDate2 is not null and Commit_date = MaxCommitDate2) or 
     (MaxCommitDate2 is null and Commit_Date = MaxCommitDate) 

子查询计算两个值,提交日期的两种可能性。然后where子句使用所需的逻辑选择适当的行。

+0

这是一个有趣的方式,结合这两个查询,然后删除不需要的行。 – Scott 2013-03-07 05:47:49

+0

@Scott。 。 。在我看来,这比处理两个单独但相似的查询更有效率和可维护性。 – 2013-03-07 11:47:57

+0

我完全同意。查询实际上是在hsql中,因为我们使用的是hibernate,并且正在使用的查询构建器不是很好。只有这么多我可以改变而不会破坏一切。如果我有我的方式,我只会使用hibernate在数据库中存储的特效库的结果集上进行数据绑定。我当然没有SQL专家,并且COALESCE足以让我走到我想去的地方。 – Scott 2013-03-08 04:37:49

1

我已经结合了其他答案。尝试了在apex.oracle.com。这里有一些解释。

MAX(CASE WHEN commit_date <= to_date('2010-DEC-30', 'YYYY-MON-DD'))将给我们最近的日期不在12月30日之前,或者如果没有一个是NULL。结合COALESCE,我们得到 COALESCE(MAX(CASE WHEN commit_date <= to_date('2010-DEC-30', 'YYYY-MON-DD') THEN commit_date END), MAX(commit_date))

现在我们拿到我们拥有的帐户ID和提交日期,并将它们与原始表结合以获取所有其他字段。下面是我想出了整个查询:

SELECT * 
FROM Account_Information 
JOIN (SELECT account_id, 
      COALESCE(MAX(CASE WHEN commit_date <= 
            to_date('2010-DEC-30', 'YYYY-MON-DD') 
           THEN commit_date END), 
         MAX(commit_date)) AS commit_date 
     FROM Account_Information 
     WHERE account_id in (30000316, 30000350, 30000351) 
     GROUP BY account_id) 
    USING (account_id, commit_date); 

请注意,如果你使用使用,你必须使用*而不是acrt.*

+0

非常整洁的查询,我知道我的原始查询不是过滤每个帐户ID只有1行的最佳方式。我认为这很清楚,我需要阅读coalesce,它看起来非常有用! – Scott 2013-03-07 05:43:37

相关问题