将“空”行添加到查询结果中

时间:2012-04-16 18:31:23

标签: sql oracle

我真的很难接受这个任务 - 我需要根据特定标准填充一个带有“0”值的行的报告,这是一个例子:

假设我们有一张表BROKERS,其中包含公司名称,交易类型以及当月和所有月份的累计金额。

COMPANY       TRAN_TYPE          CURR_MNTH         ALL_MNTH  
Broker1       CURRENCY_SELL      $1000.00          $1500000.00 
Broker1       GOLD_SELL          $50000.00         $2500000.00 
Broker1       GOLD_BUY           $80000.00         $8500000.00 
Broker1       STOCKS_SELL        $35000.00         $3500000.00 

表BROKERS没有字段TRAN_TYPE,但有一个字段TRAN_TYPE_CD,它引用另一个名为TRAN_TYPE_CD_EXPL的表,其中解释了所有代码:

TRAN_TYPE_CD  TRAN_TYPE_CD_EXPLD
1             STOCKS_SELL
2             STOCKS_BUY
3             GOLD_SELL
4             GOLD_BUY
5             SILVER_SELL
6             SILVER_BUY
7             COPPER_SELL
8             COPPER_BUY
9             CURRENCY_SELL
10            CURRENCY_BUY

所以上面显示的结果只是这两个表的简单连接:

select  b.COMPANY, tt.TRAN_TYPE, b.CURR_MONTH, b.ALL_MNTH
from    BROKERS b, TRAN_TYPE_CD_EXPL tt
where   b.TRAN_TYPE_CD = tt.TRAN_TYPE_CD;

一切都很简单,但问题就出在这里:我正在处理的报告应该是这样的:

COMPANY       MARKET      TRAN_TYPE          CURR_MNTH         ALL_MNTH  
Broker1       FOREX       CURRENCY_SELL      $1000.00          $1500000.00 
Broker1       FOREX       CURRENCY_BUY       $0.00             $5500000.00 
Broker1       CONTRACTS   GOLD_SELL          $50000.00         $2500000.00 
Broker1       CONTRACTS   GOLD_BUY           $80000.00         $8500000.00 
Broker1       STOCKMARKET STOCKS_SELL        $35000.00         $3500000.00 
Broker1       STOCKMARKET STOCKS_BUY         $0.00             $9500000.00 

所以让我解释一下: firstable,报告应该包含一个列,它应该根据TRAN_TYPE列中的值进行填充,但是数据库中没有表MARKET,所以每当你需要在报告或其他地方填充它时,你需要像这样使用解码(假设每个人都知道所有类型的tran_types属于哪里):

SELECT DECODE (TRAN_TYPE_CD_EXPL.TRAN_TYPE_CD_EXPLD,
             'CURRENCY_SELL', 'FOREX',
             'CURRENCY_BUY', 'FOREX',
             'STOCKS_SELL', 'STOCKMARKET',
             'STOCKS_BUY', 'STOCKMARKET') AS MARKET,

或基于TRAN_TYPE_CD值:

SELECT DECODE (BROKERS.TRAN_TYPE_CD,
             9, 'FOREX',
             10, 'FOREX',
             1, 'STOCKMARKET',
             2, 'STOCKMARKET') AS MARKET,

2)问题2更复杂:报告逻辑说 - 公司在特定组中至少有一个事务(对于市场类型'FOREX',我们说CURRENCY_SELL),报告应填充其他的tran_types即使是这家公司在本月没有任何交易,市场类型组的价格为0美元。所以在这种情况下,它应该用行

填充
Broker1       FOREX       CURRENCY_BUY       $0.00             $5500000.00

Broker1       STOCKMARKET STOCKS_BUY         $0.00             $9500000.00

问题是它将通过unix上的plsql批处理执行,因此它必须是单个查询。

非常感谢任何想法和/或建议!

由于

P.S。

它的oracle 11gr2,具有只读角色。

4 个答案:

答案 0 :(得分:2)

首先,您是否有理由无法创建市场表?这显然是最直接的解决方案。但是,如果您没有数据库访问权限并且必须将其入侵查询,则可以执行以下操作:

WITH m AS (
    select 'CURRENCY_SELL' as tran_type, 'FOREX' as market_name from dual
    UNION ALL
    select 'CURRENCY_BUY' as tran_type, 'FOREX' as market_name from dual
    UNION ALL
    select 'STOCKS_SELL' as tran_type, 'STOCKMARKET' as market_name from dual
    UNION ALL
    select 'STOCKS_BUY' as tran_type, 'STOCKMARKET' as market_name from dual
)
select
    b.company, m.tran_type, m.market_name, 
    nvl(v.curr_month, 0) as curr_month,
    nvl(v.all_mnth, 0) as all_mnth
from
    m
cross join
    (select distinct b.company from brokers) b
left join (
    select b.COMPANY, tt.TRAN_TYPE, b.CURR_MONTH, b.ALL_MNTH
    from    BROKERS b, TRAN_TYPE_CD_EXPL tt
    where   b.TRAN_TYPE_CD = tt.TRAN_TYPE_CD
) v
on v.company = b.company and v.tran_type = m.tran_type;

首先,我使用内联市场视图完成了公司的交叉连接 - 您将获得每个公司的所有这些记录的组合,即使它们在Brokers表中不存在。我已执行左外连接以获取您的数字,因此如果返回NULL值(没有相应的记录),它会插入0。

这可能不完全正确(例如,我不知道你如何划分你的月份),但是应该指出正确的方向。

更新

好的,所以如果我理解正确,你想把“空”行限制为经纪人在同一市场中至少有一笔交易的交易类型。

我将假设“经纪人”是本月的一个视图 - 所以如果表中有记录,就会发生在本月。

所以我们可以删除交叉连接并改为:

WITH m AS (
    select 9 as tran_type_cd, 'FOREX' as market_name from dual
    UNION ALL
    select 10, 'FOREX' as market_name from dual
    UNION ALL
    select 1, 'STOCKMARKET' from dual
    UNION ALL
    select 2, 'STOCKMARKET' from dual
    UNION ALL 
    SELECT 3, 'CONTRACTS' from dual
    UNION ALL 
    SELECT 4, 'CONTRACTS' from dual
)
select
    bm.company, tt.tran_type, m.market_name, 
    nvl(v.curr_month, 0) as curr_month,
    nvl(v.all_mnth, 0) as all_mnth
from
    (select distinct b.company, m.market_name
     from brokers b
     join m on m.tran_type_cd = b.tran_type_cd) bm
join
    m on m.market_name = bm.market_name
join
    TRAN_TYPE_CD_EXPL tt on tt.tran_type_cd = m.tran_type_cd
left join (
    select b.COMPANY, b.tran_type_cd, b.CURR_MONTH, b.ALL_MNTH
    from    BROKERS b
) v
on v.company = bm.company and v.tran_type_cd = m.tran_type_cd;

视图“bm”(我知道,这是一个很棒的首字母缩写词选择!)应该会为您提供一个与本月公司相关的明确市场列表。然后我加入了市场视图,以获得与该市场相关的所有交易类型。和以前一样,如果Brokers表中没有匹配的记录,我使用左连接用0填充空行。

这是SQL小提琴:

http://sqlfiddle.com/#!4/2f16e/13

答案 1 :(得分:2)

查询的第一部分与您的完全一样,只有市场作为内联表。第二部分通过连接市场两次添加缺失的行来添加缺失的行,然后减去已存在于第一部分中的行。

WITH Market AS (
  SELECT 9 TRAN_TYPE_CD, 'FOREX' Market FROM dual
  UNION ALL SELECT 10, 'FOREX' FROM dual
  UNION ALL SELECT 1, 'STOCKMarket'  FROM dual
  UNION ALL SELECT 2, 'STOCKMarket' FROM dual
  UNION ALL SELECT 3, 'CONTRACTS' FROM dual
  UNION ALL SELECT 4, 'CONTRACTS' FROM dual
)
SELECT b.COMPANY, Market.Market, tt.TRAN_TYPE_CD_EXPLD, 
       b.CURR_MONTH, b.ALL_MONTH
  FROM BROKERS b 
 INNER JOIN TRAN_TYPE_CD_EXPL tt
    ON b.TRAN_TYPE_CD = tt.TRAN_TYPE_CD
 INNER JOIN Market
    ON b.TRAN_TYPE_CD = Market.TRAN_TYPE_CD
UNION ALL
(
  SELECT b.COMPANY, Market.Market, tt.TRAN_TYPE_CD_EXPLD, 
         0 CURR_MONTH, 0 ALL_MONTH
    FROM BROKERS b 
   INNER JOIN Market
      ON b.TRAN_TYPE_CD = Market.TRAN_TYPE_CD
   INNER JOIN Market Market2
      ON Market.Market = Market2.Market
     AND Market.TRAN_TYPE_CD <> Market2.TRAN_TYPE_CD
   INNER JOIN TRAN_TYPE_CD_EXPL tt
      ON Market2.TRAN_TYPE_CD = tt.TRAN_TYPE_CD
 MINUS
 SELECT b.COMPANY, Market.Market, tt.TRAN_TYPE_CD_EXPLD, 
        0 CURR_MONTH, 0 ALL_MONTH
   FROM BROKERS b 
  INNER JOIN TRAN_TYPE_CD_EXPL tt
     ON b.TRAN_TYPE_CD = tt.TRAN_TYPE_CD
  INNER JOIN Market
     ON b.TRAN_TYPE_CD = Market.TRAN_TYPE_CD
)

这里有Sql Fiddle来测试结果。

答案 2 :(得分:1)

不知道你要在哪里获取all_mnth的数据,所以你应该首先弄明白。让我们知道然后加入,在零值中应该很容易。下面是我通过问题1的测试查询(类似于@Dan A.我“创建了”市场“表”):

with brokers as
(
select 'Broker1' company, 9 tran_type_cd, 1000  curr_mnth, 1500000 all_mnth from dual union
select 'Broker1' company, 3 tran_type_cd, 50000 curr_mnth, 2500000 all_mnth from dual union
select 'Broker1' company, 4 tran_type_cd, 80000 curr_mnth, 8500000 all_mnth from dual union
select 'Broker1' company, 1 tran_type_cd, 35000 curr_mnth, 3500000 all_mnth from dual 
)
, tran_type_cd_expl as
(
select 1  TRAN_TYPE_CD, 'STOCKS_SELL'  TRAN_TYPE_CD_EXPLD from dual union
select 2  TRAN_TYPE_CD, 'STOCKS_BUY'  TRAN_TYPE_CD_EXPLD from dual union
select 3  TRAN_TYPE_CD, 'GOLD_SELL'  TRAN_TYPE_CD_EXPLD from dual union
select 4  TRAN_TYPE_CD, 'GOLD_BUY'  TRAN_TYPE_CD_EXPLD from dual union
select 5  TRAN_TYPE_CD, 'SILVER_SELL'  TRAN_TYPE_CD_EXPLD from dual union
select 6  TRAN_TYPE_CD, 'SILVER_BUY'  TRAN_TYPE_CD_EXPLD from dual union
select 7  TRAN_TYPE_CD, 'COPPER_SELL'  TRAN_TYPE_CD_EXPLD from dual union
select 8  TRAN_TYPE_CD, 'COPPER_BUY'  TRAN_TYPE_CD_EXPLD from dual union
select 9  TRAN_TYPE_CD, 'CURRENCY_SELL'  TRAN_TYPE_CD_EXPLD from dual union
select 10  TRAN_TYPE_CD, 'CURRENCY_BUY'  TRAN_TYPE_CD_EXPLD from dual 
)
, market as
(
select 'CURRENCY_BUY'  tran_type_cd_expld, 'FOREX'       market from dual union
select 'CURRENCY_SELL' tran_type_cd_expld, 'FOREX'       market from dual union
select 'GOLD_BUY'      tran_type_cd_expld, 'CONTRACTS'   market from dual union
select 'GOLD_SELL'     tran_type_cd_expld, 'CONTRACTS'   market from dual union
select 'STOCKS_BUY'    tran_type_cd_expld, 'STOCKMARKET' market from dual union
select 'STOCKS_SELL'   tran_type_cd_expld, 'STOCKMARKET' market from dual 
)

select company, market, t.tran_type_cd_expld tran_type, curr_mnth, all_mnth
from brokers b, tran_type_cd_expl t, market m
where b.tran_type_cd = t.tran_type_cd
and t.tran_type_cd_expld = m.tran_type_cd_expld
;

答案 3 :(得分:0)

我相信您可以使用Subquery Factoring添加其他行(如SQL Server中的CTE)。如果您没有得到答案,我可以尝试在今晚晚些时候更新代码。