账户和客户余额(虚拟列)

问题描述 投票:0回答:1

我的客户可以拥有一个或多个帐户。我正在调用 2 个函数 (get_customer_balance 和 get_account_balance)来计算余额。

正如您从下面的测试案例中看到的,我在每个查询中调用函数两次。我想知道这些场景是否适合虚拟领域?如果可以的话,如何实现?


ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY HH24:MI:SS';

CREATE TABLE CUSTOMERS (
CUSTOMER_ID, FIRST_NAME, LAST_NAME,IS_ACTIVE) AS  SELECT 'L382059', 'Leo', 'Langford','Y' FROM DUAL UNION ALL
SELECT 'P382319', 'Tom', 'Micelli','Y' FROM DUAL UNION ALL 
SELECT 'E379466', 'Bonnie', 'Winterbottom','Y' FROM DUAL  UNION ALL 
SELECT 'X060162', 'Lisa','Saladino','Y'  FROM DUAL UNION ALL 
SELECT 'Y331964', 'Sandy', 'Herring','Y' FROM DUAL  UNION ALL 
SELECT 'Z888555', 'Barbara', 'Broadwater','Y' FROM DUAL;

CREATE TABLE vendors AS
    SELECT level AS vendor_id,
       'Vendor ' || level AS vendor_name
    FROM   dual
    CONNECT BY level <= 3;

CREATE TABLE CUSTOMER_ACCOUNTS (
ACCOUNT_NUMBER,
CUSTOMER_ID, VENDOR_ID,
IS_ACTIVE) AS 
SELECT 'Z17ARWYYZRCU2Q2', 'P382319', 1, 'Y' FROM DUAL 
 UNION ALL
 SELECT '0T81Z07CS6LXQ7Z', 'P382319', 3, 'Y' FROM DUAL 
UNION ALL 
SELECT 'YWYXC3Q5N9XZ7S', 'L382059', 1, 'Y' FROM DUAL UNION ALL
SELECT '612ZKAQ66VA3W3', 'Y331964', 3, 'Y' FROM DUAL    UNION ALL 
SELECT 'BCHD9TW78W67S1D', 'Z888555', 3, 'Y' FROM DUAL UNION ALL 
SELECT '0HLS87LDR1TE8WB', 
'X060162', 3, 'Y' FROM DUAL  UNION ALL 
SELECT 'Z69AG7DKS37UYU',
'X060162', 3, 'Y' FROM DUAL  UNION ALL 
SELECT 'B17ARWYYZRCU2Q2', 
'X060162', 3, 'Y' FROM DUAL  UNION ALL 
SELECT 'THVQD6M9LR7AVK', 'E379466', 1, 'Y' FROM DUAL  UNION ALL 
SELECT '0Z76WT5NTLRZPTW',
'E379466', 1, 'Y' FROM DUAL;

create table transactions (
     transaction_id NUMBER GENERATED BY DEFAULT AS IDENTITY,
    account_number VARCHAR2(15),
    transaction_type varchar2(1) DEFAULT 'C',
    transaction_amount NUMBER(10,2),
     transaction_date DATE DEFAULT SYSDATE 
);

insert  into transactions(
account_number, transaction_type, transaction_amount, transaction_date)
SELECT 'Z17ARWYYZRCU2Q2', 'D', (LEVEL * 1250.50), date '2023-05-14' + level * interval '5 15:13' day to minute from dual
          connect by level <= 7
union all
SELECT 'Z17ARWYYZRCU2Q2', 'C', (LEVEL * 1175.75), date '2023-07-04' + level * interval '1 21:23' day to minute from dual
          connect by level <= 5
union all
SELECT '0T81Z07CS6LXQ7Z', 'D', (LEVEL * 1250.50), date '2023-02-14' + level * interval '3 15:13' day to minute from dual
          connect by level <= 17
union all
SELECT '0T81Z07CS6LXQ7Z', 'C', (LEVEL * 75.75), date '2023-02-04' + level * interval '2 21:23' day to minute from dual
          connect by level <= 11
union all
select '612ZKAQ66VA3W3', 'D', 555.25 * LEVEL, (DATE '2023-07-13' + 13/24) + (level * 2)  from dual 
    connect by level <= 25 
UNION ALL 
select '612ZKAQ66VA3W3', 'C', 555.25 * LEVEL, (DATE '2023-07-23' + 13/24) + (level * 2)  from dual 
    connect by level <= 20 
UNION ALL 
SELECT '0HLS87LDR1TE8WB', 'D', (LEVEL * 1250.50), date '2023-05-04' + level * interval '1 15:13' day to minute from dual
          connect by level <= 7
union all
SELECT '0HLS87LDR1TE8WB', 'C', (LEVEL * 1175.75), date '2023-05-04' + level * interval '1 15:13' day to minute from dual
          connect by level <= 5
union all
SELECT 'Z69AG7DKS37UYU', 'D', ((LEVEL * 5) * 1750), date '2023-06-01' + level * interval '1 18:43:35' day to second from dual
          connect by level <= 15
union all
SELECT 'Z69AG7DKS37UYU', 'C', ((LEVEL * 5) * 1750), date '2023-06-11' + level * interval '1 15:23:49' day to second from dual
          connect by level <= 13;


CREATE OR REPLACE FUNCTION   get_customer_balance
(  i_customer_id   IN   customers.customer_id%TYPE
)
RETURN  transactions.transaction_amount%TYPE
IS
  v_balance   transactions.transaction_amount%TYPE;
BEGIN
  SELECT SUM (
                 CASE  t.transaction_type
             WHEN  'C'
             THEN  -t.transaction_amount
             ELSE  t.transaction_amount
         END 
             )
  INTO   v_balance
  FROM   customer_accounts  ca
  JOIN   transactions       t  ON  t.account_number  = ca.account_number
  WHERE  ca.customer_id  = i_customer_id  -- one customer
  OR     ca.customer_id  IS NULL;         -- all customers

  RETURN v_balance;
END  get_customer_balance;
/

CREATE OR REPLACE FUNCTION get_account_balance(
  i_account_number IN TRANSACTIONS.ACCOUNT_NUMBER%TYPE
) RETURN TRANSACTIONS.TRANSACTION_AMOUNT%TYPE
IS
  v_balance TRANSACTIONS.TRANSACTION_AMOUNT%TYPE;
BEGIN
  SELECT SUM(
           CASE transaction_type WHEN 'C' THEN -1 ELSE 1 END 
           * transaction_amount
         )
  INTO   v_balance
  FROM   transactions
  WHERE  account_number = i_account_number -- one account
  OR     i_account_number IS NULL;         -- all accounts
  RETURN v_balance;
END;
/

SELECT 
    CA.ACCOUNT_NUMBER, 
     C.CUSTOMER_ID, 
     C.FIRST_NAME, 
     C.LAST_NAME, 
   get_account_balance(ca.account_number) AS balance 
  FROM CUSTOMER_ACCOUNTS CA
INNER JOIN customers c ON ca.customer_id = c.customer_id
WHERE get_account_balance(ca.account_number)  > 200000; 

ACCOUNT_NUMBER  CUSTOMER_ID 
 FIRST_NAME  LAST_NAME  BALANCE
Z69AG7DKS37UYU  X060162  Lisa  Saladino 253750

SELECT C.CUSTOMER_ID,
       C.FIRST_NAME,
       C.LAST_NAME, 
       get_customer_balance(C.CUSTOMER_ID) AS balance
FROM   customers c
WHERE get_customer_balance(C.CUSTOMER_ID) > 200000;


CUSTOMER_ID  FIRST_NAME 
 LAST_NAME. BALANCE
P382319  Tom  Micelli 
 203704.75
X060162  Lisa  Saladino 
 271127.75

oracle function virtual
1个回答
0
投票

我建议只使用普通的 SQL 而不是函数。函数的使用需要对每个客户进行单独的查找和排序,如果您针对非常大的客户群运行此函数,则可能会陷入困境。试试这个,两者之间的唯一区别是额外的

GROUP BY
列:

-- customer balance
SELECT C.CUSTOMER_ID,
       C.FIRST_NAME,
       C.LAST_NAME, 
       SUM(CASE transaction_type WHEN 'C' THEN -1 ELSE 1 END * transaction_amount) customer_balance
 FROM  customers c
       JOIN customer_accounts  ca ON ca.customer_id = c.customer_id
       JOIN transactions t  ON  t.account_number  = ca.account_number
 GROUP BY C.CUSTOMER_ID,
          C.FIRST_NAME,
          C.LAST_NAME
HAVING SUM(CASE transaction_type WHEN 'C' THEN -1 ELSE 1 END * transaction_amount) > 200000;  

-- account balance
SELECT ca.account_number,
       C.CUSTOMER_ID,
       C.FIRST_NAME,
       C.LAST_NAME, 
       SUM(CASE transaction_type WHEN 'C' THEN -1 ELSE 1 END * transaction_amount) account_balance
 FROM  customers c
       JOIN customer_accounts  ca ON ca.customer_id = c.customer_id
       JOIN transactions t  ON  t.account_number  = ca.account_number
 GROUP BY ca.account_number,
          C.CUSTOMER_ID,
          C.FIRST_NAME,
          C.LAST_NAME
HAVING SUM(CASE transaction_type WHEN 'C' THEN -1 ELSE 1 END * transaction_amount) > 200000;  
© www.soinside.com 2019 - 2024. All rights reserved.