2017-03-07 60 views
-1

我想用两个表进行查询。即使表格中没有记录,我也想显示用户所选年份的所有月份。不过,我无法显示所有的月份,也没有空值。请帮忙?如何在oracle中选择用户选择年份的所有月份

这里是我的查询:

SELECT  spendList.NUMBER, 
      spendList.User, 
      TO_CHAR(spendList.DATE, 'Month') as Month, 
      spendList.AMOUNT, allowence.FUND 
FROM  T_EXPENDITURE spendList 
LEFT JOIN T_ALLOWENCE allowence 
ON   spendList.DEP_NO = allowence.DEP_NO 
WHERE  TO_CHAR(spendList.DATE, 'YYYY') = :userYear 
ORDER BY spendList.DEPARTMENT 

结果一定是这样的:

NUMBER USER MONTH  SPEND_AMOUNT ALLOWENCE 
12345 Clerk January  123    2500 
7869  Manager February  150    3000 
12345 Clerk March      2500 
7869  Manager April      3000 
12345 Clerk May       2500 
7869  Manager June       3000 
12345 Clerk July       2500 
7869  Manager August      3000 
12345 Clerk September     2500 
7869  Manager September     3000 
12345 Clerk October      2500 
7869  Manager Nevember      3000 
12345 Clerk December      2500 

我会用这导致了报告,并在报告中有前人的精力是今年所有月份。

报告会是这样:

NUMBER USER January February ... December ALLOWENCE 
12345 Clerk  123  null   null  2500 
+0

方法。 com/node/2029 –

+0

而您正在寻找的搜索词是“日历表”或“日历视图”。 –

+0

[如何在Oracle中填充日历表?](http://stackoverflow.com/questions/8374959/how-to-populate-calendar-table-in-oracle) –

回答

0

使用PARTITION加入:

甲骨文设置

CREATE TABLE T_EXPENDITURE ("NUMBER", "USER", "DATE", amount, dep_no) AS 
    SELECT 1, 'Clerk', DATE '2017-01-10', 50, 1 FROM DUAL UNION ALL 
    SELECT 1, 'Clerk', DATE '2017-01-15', 73, 1 FROM DUAL UNION ALL 
    SELECT 1, 'Clerk', DATE '2017-02-14', 13, 1 FROM DUAL UNION ALL 
    SELECT 2, 'Manager', DATE '2017-02-01', 150, 2 FROM DUAL; 

CREATE TABLE T_ALLOWENCE (dep_no, fund) AS 
    SELECT 1, 2500 FROM DUAL UNION ALL 
    SELECT 1, 3000 FROM DUAL; 

查询

SELECT e."NUMBER", 
     e."USER", 
     c.month, 
     SUM(e.amount) AS amount, 
     e.fund 
FROM 
    (
    SELECT e.*, a.fund 
    FROM t_allowance a 
      INNER JOIN t_expenditure e 
      ON (e.dep_no = a.dep_no) 
) e 
    PARTITION BY (e."NUMBER", e."USER", e.FUND) 
    RIGHT OUTER JOIN 
    (
    SELECT ADD_MONTHS(TO_DATE(:useryear || '0101', 'YYYYMMDD'), LEVEL - 1) AS month 
    FROM DUAL 
    CONNECT BY LEVEL <= 12 
) c 
    ON(c.month <= e."DATE" AND e."DATE" < ADD_MONTHS(c.month, 1)) 
GROUP BY e."NUMBER", e."USER", e.FUND, c.MONTH 
ORDER BY e."NUMBER", c.MONTH; 

输出

NUMBER USER MONTH  AMOUNT FUND 
------ ------- ---------- ------ ---- 
    1 Clerk 2017-01-01 123 2500 
    1 Clerk 2017-02-01  13 2500 
    1 Clerk 2017-03-01  2500 
    1 Clerk 2017-04-01  2500 
    1 Clerk 2017-05-01  2500 
    1 Clerk 2017-06-01  2500 
    1 Clerk 2017-07-01  2500 
    1 Clerk 2017-08-01  2500 
    1 Clerk 2017-09-01  2500 
    1 Clerk 2017-10-01  2500 
    1 Clerk 2017-11-01  2500 
    1 Clerk 2017-12-01  2500 
    2 Manager 2017-01-01  3000 
    2 Manager 2017-02-01 150 3000 
    2 Manager 2017-03-01  3000 
    2 Manager 2017-04-01  3000 
    2 Manager 2017-05-01  3000 
    2 Manager 2017-06-01  3000 
    2 Manager 2017-07-01  3000 
    2 Manager 2017-08-01  3000 
    2 Manager 2017-09-01  3000 
    2 Manager 2017-10-01  3000 
    2 Manager 2017-11-01  3000 
    2 Manager 2017-12-01  3000 

查询2

SELECT * 
FROM (
    SELECT "NUMBER", 
     "USER", 
     EXTRACT(MONTH FROM "DATE") AS month, 
     amount, 
     e.dep_no, 
     fund 
    FROM T_EXPENDITURE e 
     INNER JOIN T_ALLOWENCE a 
     ON (e.dep_no = a.dep_no) 
    WHERE EXTRACT(YEAR FROM e."DATE") = :useryear 
) 
PIVOT (
    SUM(amount) 
    FOR month IN (
    1 AS Jan, 2 AS Feb, 3 AS Mar, 4 AS Apr, 5 AS May, 6 AS Jun, 
    7 AS Jul, 8 AS Aug, 9 AS Sep, 10 AS Oct, 11 AS Nov, 12 AS Dec 
) 
); 

输出:HTTP://www.orafaq使用`DBA_TABLES`以产生足够的行

NUMBER USER DEP_NO FUND JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC 
------ ------- ------ ---- --- --- --- --- --- --- --- --- --- --- --- --- 
    1 Clerk  1 2500 123 13 
    2 Manager  2 3000  150 
+0

它给c.MONTH无效标识符错误... –

+1

@ T.Rifle查询不会给我一个错误;请检查您是否已正确复制。我还添加了一个与您的更新报告格式相匹配的更新。今后请(a)首先提出完整的问题,而不是在出现[XY-problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)解决方案和(b)不会如此戏剧性地更改您的问题输出,因为这会使一些答案失效。 – MT0

+0

感谢您的回答。查询2对我很好。 –

1

该解决方案使用WITH子句语法生成一年的所有月份的一个子查询(技术上每个月的第一天)。它假设:userYear作为一个四位数字被传递到一个日期,然后截取yyyy面具以获得一年中的第一天。 add_months()用于获取剩余的月份。

通过派生每个记录的月份的第一天,将此子查询外连接到您的T_EXPENDITURE表。

with calendar as (
    select add_months(trunc(to_date(:userYear,'yyyy'),'yyyy'), level-1) as mon 
    from dual 
    connect by level <=12) 
SELECT to_char(calendar.mon,'MONTH') as Month, 
     spendList.NUMBER, 
     spendList.User, 
     spendList.AMOUNT, 
     allowence.FUND 
FROM calendar 
left join T_EXPENDITURE spendList 
    on trunc(spendList.DATE, 'MON') = calendar.mon 
LEFT JOIN T_ALLOWENCE allowence 
ON spendList.DEP_NO=allowence.DEP_NO 
ORDER BY spendList.DEPARTMENT 
+0

感谢您的答案,但它给出了相同的结果。即使他们有空值,我也想显示所有月份。 –

+0

我刚修改了查询:请再试一次。如果它仍然不起作用,您需要发布一些示例数据。 – APC

相关问题