Total Pageviews

Showing posts with label Oracle. Show all posts
Showing posts with label Oracle. Show all posts

2020/03/08

[Java] [Spring] [JDBC] [Oracle] How to call stored procedure - example 1

Assume I have a stored procedure as bellows:
create or replace PACKAGE PACKAGE1 AS 
     PROCEDURE TEST_HELLO 
    (
      I_NAME IN VARCHAR2,
      outParam1 OUT VARCHAR2,
      o_return_code OUT INT
    );
END PACKAGE1;

create or replace PACKAGE BODY PACKAGE1
AS
   PROCEDURE TEST_HELLO 
    (
      I_NAME IN VARCHAR2,
      outParam1 OUT VARCHAR2,
      o_return_code OUT INT
    ) AS 
    BEGIN
      outParam1 := 'Hello World! ' || I_NAME;
      DBMS_OUTPUT.put_line (outParam1);
      o_return_code := 0;
    END TEST_HELLO;
END PACKAGE1;


Step1. Create a custom repository interface:
package com.example.jpa.repository.custom;

import java.util.Map;

public interface EmployeeRepositoryCustom {
    Map<String, Object> sayHello(String name);
}


Step2. Create a custom implementation class:
package com.example.jpa.repository.impl;

import com.example.jpa.entity.Employee;
import com.example.jpa.repository.custom.EmployeeRepositoryCustom;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;

import java.util.Map;

@Slf4j
public class EmployeeRepositoryImpl implements EmployeeRepositoryCustom {

    @Autowired
    private NamedParameterJdbcTemplate jdbcTemplate;
    
    @Override
    public Map<String, Object> sayHello(String name) {
        SimpleJdbcCall jdbcCall
                = new SimpleJdbcCall(jdbcTemplate.getJdbcTemplate().getDataSource())
                .withCatalogName("PACKAGE1")
                .withProcedureName("TEST_HELLO");

        Map<String, Object> output = jdbcCall.execute(name);
        output.entrySet().forEach(entry -> log.debug("key = {}, value = {}", entry.getKey(), entry.getValue()));

        return output;
    }
}


Step3. Create an repository interface
package com.example.jpa.repository;

import com.example.jpa.entity.Employee;
import com.example.jpa.repository.custom.EmployeeRepositoryCustom;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, String>, EmployeeRepositoryCustom {
}


Step4. Create a test case:
package com.example.jpa;

import com.example.jpa.entity.Employee;
import com.example.jpa.repository.EmployeeRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

@SpringBootTest
@Slf4j
public class TestEmployeeRepository {

    @Autowired
    private EmployeeRepository employeeRepository;

    @Test
    public void testSayHello() {
        String name = "Albert Kuo";
        Map<String, Object> output = employeeRepository.sayHello(name);

        String message = (String) output.get("OUTPARAM1");
        int returnCode = ((BigDecimal) output.get("O_RETURN_CODE")).intValue();
        log.debug("message = {}, returnCode = {}", message, returnCode);

        Assert.assertEquals(0, returnCode);
        Assert.assertEquals("Hello World! " + name, message);
    }

}


Step5. Check result:
[           main] c.e.j.r.impl.EmployeeRepositoryImpl      : key = OUTPARAM1, value = Hello World! Albert Kuo
[           main] c.e.j.r.impl.EmployeeRepositoryImpl      : key = O_RETURN_CODE, value = 0
[           main] com.example.jpa.TestEmployeeRepository   : message = Hello World! Albert Kuo, returnCode = 0


2020/01/06

[Oracle] PL/SQL Quick Start

Create Package



CREATE OR REPLACE 
PACKAGE PKG_TEST AS 
   /* TODO enter package declarations 
     (types, exceptions, methods etc) here */ 
END PKG_TEST;




Create Package Body














Update Package












Execute Stored Procedure
var o_message varchar2;
var o_return_code number;
exec package1.test_hello('Albert',:o_message, :o_return_code);
print o_message;
print o_return_code;




2019/11/14

[Oracle] 安裝 Oracel 11g 過程中,發生找不到 wfmlrsvcapp.ear 錯誤

Problem
安裝 Oracel 11g 過程中,發生找不到 wfmlrsvcapp.ear 錯誤

How-To
由於安裝檔被分成 win64_11gR2_database_1of2.zip 與 win64_11gR2_database_2of2.zip,在執行安裝時,會發生此錯誤。

應將 win64_11gR2_database_2of2 目錄下所有檔案,複製到  win64_11gR2_database_1of2 目錄下,再開始安裝,即可避免此錯誤。


2016/02/24

[Oracle] How to grant privilege and create synonym in Oracle

If I would like to grant two views, dbm200va and dbm400va, to another database user. How do to it?


Syntax for tables/views is as bellows:
GRANT privilege-type ON [TABLE] { table-Name | view-Name } TO grantees



In addition to grant privileges by ap_dbm, ap_psr also need to create synonym on its side.
Create synonym syntax is as following:
CREATE [PUBLIC] SYNONYM [schema .] synonym FOR [schema .] object [@ dblink];



Reference
  1. grant privilege: http://docs.oracle.com/javadb/10.8.1.2/ref/rrefsqljgrant.html
  2. create synonym : http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_7001.htm

2016/02/07

[Oracle] How to get the date of the last day of the month in Oracle

Problem
If I would like to get the date of the last day of the month, how to do it?

How to
Oracle had build-in function, LAST_DAY, to fulfill this requirement.

Here is the example:
SELECT to_char(sysdate, 'YYYYMMDD') today,
       to_char(LAST_DAY(sysdate), 'YYYYMMDD') last_day_of_month
FROM dual

Query result :


Reference
[1] https://docs.oracle.com/cd/B28359_01/server.111/b28286/functions077.htm

2016/01/08

[Oracle] Nulls with Comparison Conditions

Problem
Assume the data in the table is as following:
1
2
3
4
select fyr, age, type1
from ave107fa
where paydat between '1041201' and '1041231'
order by type1 ;



We can find out the value of type1 has D and null.

If I would like to find the data which Type1 is not eqal to D:
1
2
3
4
5
select fyr, age, type1
from ave107fa
where paydat between '1041201' and '1041231'
       and type1 <> 'D'
order by type1 ;

But Oracle return nothing
:


How To
In Oracle,  null represents a lack of data, a null cannot be equal or unequal to any value or to another null. Therefore, it will return nothing.

Hence, we can modify SQL statement as bellows:
1
2
3
4
5
select fyr, age, type1
from ave107fa
where paydat between '1041201' and '1041231'
      and nvl(type1, ' ') <> 'D'
order by type1 ;


The data which Type1 is null can be retrieved now:


Reference
[1] https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements005.htm

2016/01/03

[Oracle] How to compiles all procedures, functions, packages, and triggers in the specified schema.

Problem
If you do alter table in Oracle database, your stored procedures or views' state may become invalid as bellows:


You need to rebuild all invalid stored procedures one by one
1
ALTER PROCEDURE PROC_FMS406R_TAB5_RPT1_STEP1 COMPILE;

If I have multiple invalid stored procedures, it will be very annoying. 
Does Oracle provide any convenient way to rebuild all invalid stored procedures?

How-To
You can use exec dbms_utility.compile_schema(SCHEMA NAME) to fulfill this requirement. Assume my schema name is AP_PSR, then the command is as follows:
1
exec dbms_utility.compile_schema('AP_PSR');

See...all invalid stored procedures had become invalid




Reference
[1] http://dbataj.blogspot.tw/2007/08/how-to-compile-invalid-objects.html

2015/12/02

How to utilize Oracle SQL Developer to Connect to Microsoft SQL Server

Problem
Oracle SQL Developer only support connection to Oracle and Access by default.
If I would like to connection to Microsoft SQL Server, how to configure it?



How-To
Step 1. Download jTDS - SQL Server and Sybase JDBC driver from http://sourceforge.net/projects/jtds/files/

Step 2. Tool => Preference => Third Party JDBC Driver. Set library file to Third Party JDBC Driver

Step 3. Click create new database connection. You can find out SQLServer option is the create new database connection dialog after forging configuration.

Step 4. Fill in the SQL Server database connection information and do test. It can connection to SQL Server database successfully via Oracle SQL Developer.


Reference
[1] https://www.dotblogs.com.tw/smartleos/archive/2013/09/16/118705.aspx

2015/10/16

[Oracle] Using "WITH AS" to Refactor SQL

As-Is
Assume I have a SQL statement as bellows:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
SELECT :startYear AS account_yr,
       budget_status AS budget_status,
       data_type AS data_type,
       sum(ALLC_AMOUNT) AS bondARest
FROM
  (SELECT lpad(to_char(a.ACCOUNT_YR, 'yyyy')-1911, 3, '0') AS ACCOUNT_YR,
          a.BUDGET_STATUS AS BUDGET_STATUS,
          a.BUDGET_CODE AS BUDGET_CODE,
          a.DEBT_CODE AS DEBT_CODE,
          a.DATA_TYPE AS DATA_TYPE,
          b.DEBT_TYPE AS DEBT_TYPE,
          b.BOND_TYPE AS BOND_TYPE,
          nvl(b.ALLC_AMOUNT, 0) AS ALLC_AMOUNT
   FROM
     (SELECT ACCOUNT_YR,
             BUDGET_CODE,
             DEBT_CODE,
             DATA_TYPE,
             BUDGET_STATUS,
             END_DATE,
             MAX(BUDGET_STATUS) OVER (PARTITION BY ACCOUNT_YR, BUDGET_CODE, DEBT_CODE, DATA_TYPE, SUBSTR(BUDGET_STATUS, 0, 1)) AS maxBudgetStatus
      FROM DBM091FA
      WHERE DATA_TYPE IN ('C',
                          'I')) a,
        DBM091FB b
   WHERE a.ACCOUNT_YR=b.ACCOUNT_YR
     AND a.BUDGET_CODE=b.BUDGET_CODE
     AND a.DEBT_CODE=b.DEBT_CODE
     AND a.DATA_TYPE=b.DATA_TYPE
     AND a.BUDGET_STATUS=b.BUDGET_STATUS
     AND a.BUDGET_STATUS=a.maxBudgetStatus
   ORDER BY a.ACCOUNT_YR,
            a.BUDGET_STATUS,
            a.BUDGET_CODE,
            a.DEBT_CODE)
WHERE budget_code=1
  AND debt_type=1
  AND bond_type=21
  AND account_yr BETWEEN '083' AND :startYear
GROUP BY budget_status,
         data_type
UNION
SELECT account_yr,
       budget_status,
       data_type,
       sum(ALLC_AMOUNT) bondARest
FROM
  (SELECT lpad(to_char(a.ACCOUNT_YR, 'yyyy')-1911, 3, '0') AS ACCOUNT_YR,
          a.BUDGET_STATUS AS BUDGET_STATUS,
          a.BUDGET_CODE AS BUDGET_CODE,
          a.DEBT_CODE AS DEBT_CODE,
          a.DATA_TYPE AS DATA_TYPE,
          b.DEBT_TYPE AS DEBT_TYPE,
          b.BOND_TYPE AS BOND_TYPE,
          nvl(b.ALLC_AMOUNT, 0) AS ALLC_AMOUNT
   FROM
     (SELECT ACCOUNT_YR,
             BUDGET_CODE,
             DEBT_CODE,
             DATA_TYPE,
             BUDGET_STATUS,
             END_DATE,
             MAX(BUDGET_STATUS) OVER (PARTITION BY ACCOUNT_YR, BUDGET_CODE, DEBT_CODE, DATA_TYPE, SUBSTR(BUDGET_STATUS, 0, 1)) AS maxBudgetStatus
      FROM DBM091FA
      WHERE DATA_TYPE IN ('C',
                          'I')) a,
        DBM091FB b
   WHERE a.ACCOUNT_YR=b.ACCOUNT_YR
     AND a.BUDGET_CODE=b.BUDGET_CODE
     AND a.DEBT_CODE=b.DEBT_CODE
     AND a.DATA_TYPE=b.DATA_TYPE
     AND a.BUDGET_STATUS=b.BUDGET_STATUS
     AND a.BUDGET_STATUS=a.maxBudgetStatus
   ORDER BY a.ACCOUNT_YR,
            a.BUDGET_STATUS,
            a.BUDGET_CODE,
            a.DEBT_CODE)
WHERE budget_code=1
  AND debt_type=1
  AND bond_type=21
  AND account_yr > :startYear
GROUP BY account_yr,
         budget_status,
         data_type
ORDER BY account_yr

You may notice the SQL statement which had been highlighted is duplicated.

To-be
You can utilize "with as..." to do SQL refactor.

The WITH clause, or subquery factoring clause, is part of the SQL-99 standard and was added into the Oracle SQL syntax in Oracle 9.2. The WITH clause may be processed as an inline view or resolved as a temporary table. The advantage of the latter is that repeated references to the subquery may be more efficient as the data is easily retrieved from the temporary table, rather than being requeried by each reference. You should assess the performance implications of the WITH clause on a case-by-case basis.

The foregoing SQL statement will be amended as following:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
with predictedNumber as (
SELECT lpad(to_char(a.ACCOUNT_YR, 'yyyy')-1911, 3, '0') AS ACCOUNT_YR,
       a.BUDGET_STATUS AS BUDGET_STATUS,
       a.BUDGET_CODE AS BUDGET_CODE,
       a.DEBT_CODE AS DEBT_CODE,
       a.DATA_TYPE AS DATA_TYPE,
       b.DEBT_TYPE AS DEBT_TYPE,
       b.BOND_TYPE AS BOND_TYPE,
       nvl(b.ALLC_AMOUNT, 0) AS ALLC_AMOUNT
FROM
  (SELECT ACCOUNT_YR,
          BUDGET_CODE,
          DEBT_CODE,
          DATA_TYPE,
          BUDGET_STATUS,
          END_DATE,
          MAX(BUDGET_STATUS) OVER (PARTITION BY ACCOUNT_YR, BUDGET_CODE, DEBT_CODE, DATA_TYPE, SUBSTR(BUDGET_STATUS, 0, 1)) AS maxBudgetStatus
   FROM DBM091FA
   WHERE DATA_TYPE IN ('C',
                       'I')) a,
     DBM091FB b
WHERE a.ACCOUNT_YR=b.ACCOUNT_YR
  AND a.BUDGET_CODE=b.BUDGET_CODE
  AND a.DEBT_CODE=b.DEBT_CODE
  AND a.DATA_TYPE=b.DATA_TYPE
  AND a.BUDGET_STATUS=b.BUDGET_STATUS
  AND a.BUDGET_STATUS=a.maxBudgetStatus
ORDER BY a.ACCOUNT_YR,
         a.BUDGET_STATUS,
         a.BUDGET_CODE,
         a.DEBT_CODE
)
select :startYear AS account_yr, budget_status AS budget_status, data_type AS data_type, sum(ALLC_AMOUNT) AS bondARest
from
predictedNumber
where budget_code=1 and debt_type=1 and bond_type=21 and account_yr between '083' and :startYear
group by budget_status, data_type

union

select account_yr, budget_status, data_type, sum(ALLC_AMOUNT) bondARest
from
predictedNumber
where budget_code=1 and debt_type=1 and bond_type=21 and account_yr > :startYear
group by account_yr, budget_status, data_type
order by account_yr


Reference
[1] https://oracle-base.com/articles/misc/with-clause

2015/09/21

[Oracle] How to get the last day of the month in Oracle

Requirement
If we would like to get the date of the last date of this month, does oracle have any build-in function?

How-To
Oracle has LAST_DAY function. The last day of the month is defined by the session parameter NLS_CALENDAR. The return type is always DATE, regardless of the datatype of date.

Example.
1
2
3
   SELECT to_char(sysdate, 'YYYYMMDD') "today",
          to_char(LAST_DAY(SYSDATE), 'YYYYMMDD') " last day of the month"
   FROM DUAL

Result:





Reference
[1] https://docs.oracle.com/cd/B28359_01/server.111/b28286/functions077.htm

2015/08/17

[Oracle] LISTAGG cannot handle NVARCHAR2

Problem
Assume this following SQL statement will get agency name
1
2
3
4
SELECT age, agency
FROM ave011fa
WHERE fyr='104'
AND age IN ('0240005', '0000000', '2971021');

The search result is as bellows:

If we would like to concatenate multiple agencies into one row, we need to make good use of LISTAGG function.

Therefore, the SQL statement will modify as following:
1
2
3
4
5
6
SELECT fyr,
       LISTAGG(AGENCY, ';') WITHIN GROUP (ORDER BY fyr) AGENCY
FROM ave011fa
WHERE fyr='104'
AND age IN ('0240005', '0000000', '2971021')
GROUP BY fyr;


But the agency name's characters are broken

Solution
Owing to agency column's data type is NVARCHAR2, LISTAGG function cannot handle NVARCHAR2 properly

So you need to cast agency to a char to fix this problem

1
2
3
4
5
6
SELECT fyr,
        LISTAGG(TO_CHAR(AGENCY), ';') WITHIN GROUP (ORDER BY fyr) AGENCY
FROM ave011fa
WHERE fyr='104'
AND age IN ('0240005', '0000000', '2971021')
GROUP BY fyr

Then we can get the expected result:


Reference
[1] http://stackoverflow.com/questions/15304648/oracle-sql-developer-3-1-07-extra-spaces-between-characters-using-listagg
[2] http://www.techonthenet.com/oracle/functions/listagg.php

2015/07/29

oracle.net.ns.NetException: Got minus one from a read call

Problem
My web application environment is :

  • Database: Oracle
  • Application Server: JBoss

As I startup JBoss, it show this error message unexpectedly:
1
2
3
4
5
6
 Caused by: oracle.net.ns.NetException: Got minus one from a read call
  at oracle.net.ns.Packet.receive(Packet.java:311) ~[oracle.jdbc-11.2.0.4-java-6.jar:11.2.0.3.0]
  at oracle.net.ns.NSProtocol.connect(NSProtocol.java:300) ~[oracle.jdbc-11.2.0.4-java-6.jar:11.2.0.3.0]
  at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:1140) ~[oracle.jdbc-11.2.0.4-java-6.jar:11.2.0.3.0]
  at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:340) ~[oracle.jdbc-11.2.0.4-java-6.jar:11.2.0.3.0]
  ... 124 common frames omitted


Resolution
This exception result from the number of process exceed the maximum value.

Therefore, you need to alter the number of process in oracle :
ALTER SYSTEM
SET processes=<number> SCOPE=spfile;

Remember to retsart Oracle.

Reference
[1] http://oraclepath.blogspot.tw/2013/10/javasqlsqlexception-got-minus-one-from.html