Dynamic tablename to %rowtype - database

In oracle is it possible to dynamically assign the table name with Rowtype anchor element.
If not is there any other way to achieve this scenario ?

I'm not sure what "scenario" it is, but - to me - looks like function that accepts table name as a parameter and returns ref cursor might be what you're looking for. Here's an example.
SQL> create or replace function f_test (par_table_name in varchar2)
2 return sys_refcursor
3 is
4 rc sys_refcursor;
5 begin
6 open rc for 'select * from ' || dbms_assert.sql_object_name(par_table_name);
7 return rc;
8 end;
9 /
Function created.
Testing: pass DEPT table name, and you'll get its contents:
SQL> select f_test('dept') from dual;
F_TEST('DEPT')
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
Now pass EMP table name:
SQL> select f_test('emp') from dual;
F_TEST('EMP')
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17.12.80 800 20
7499 ALLEN SALESMAN 7698 20.02.81 1600 300 30
7521 WARD SALESMAN 7698 22.02.81 1250 500 30
7566 JONES MANAGER 7839 02.04.81 2975 20
7654 MARTIN SALESMAN 7698 28.09.81 1250 1400 30
7698 BLAKE MANAGER 7839 01.05.81 2850 30
7782 CLARK MANAGER 7839 09.06.81 2450 10
7788 SCOTT ANALYST 7566 09.12.82 3000 20
7839 KING PRESIDENT 17.11.81 5000 10
7844 TURNER SALESMAN 7698 08.09.81 1500 30
7876 ADAMS CLERK 7788 12.01.83 1100 20
7900 JAMES CLERK 7698 03.12.81 950 30
7902 FORD ANALYST 7566 03.12.81 3000 20
7934 MILLER CLERK 7782 23.01.82 1300 10
14 rows selected.
SQL>

Related

SQL name string matching -sql server

I have a table with data in the form
Date Amount Payer
04/01/2021 50 LARRY BURNS
16/01/2021 46 JOHN SMITH
15/01/2021 35 SUSAN ARTHUR
14/01/2021 28 S. ARTHUR
13/01/2021 21 JO SMITH
12/01/2021 13 LARRY BURNS
11/01/2021 6 SUSAN ARTHUR
I also have another table with data in the form
ID Customer Name Customer Type
10001 LARRY BURNS CU
10002 JOHN SMITH CU
10003 SUSAN ARTHUR CU
The first table which is a transactions table does not have a foreign key to reference the ID from the customer. The only information provided is the Payer column which includes inconsistently spelled names of customers. Is it possible to do some form of 'name matching' as a pseudo-join to allow retrieval of the customer name and ID?
Ideally in the form:
Date Amount Payer Customer Name ID
04/01/2021 50 LARRY BURNS LARRY BURNS 10001
16/01/2021 46 JOHN SMITH JOHN SMITH 10002
15/01/2021 35 SUSAN ARTHUR SUSAN ARTHUR 10003
14/01/2021 28 S. ARTHUR SUSAN ARTHUR 10003
13/01/2021 21 JO SMITH JOHN SMITH 10002
12/01/2021 13 LARRY BURNS LARRY BURNS 10001
11/01/2021 6 SUSAN ARTHUR SUSAN ARTHUR 10003
Given that you're willing to have an allowance for differences, you could try something like the following:
DECLARE #Payer table (
[Date] date, Amount decimal(18,2), Payer varchar(50)
);
INSERT INTO #Payer VALUES
( '01/04/2021', 50, 'LARRY BURNS' ),
( '01/16/2021', 46, 'JOHN SMITH' ),
( '01/15/2021', 35, 'SUSAN ARTHUR' ),
( '01/14/2021', 28, 'S. ARTHUR' ),
( '01/13/2021', 21, 'JO SMITH' ),
( '01/12/2021', 13, 'LARRY BURNS' ),
( '01/11/2021', 6 , 'SUSAN ARTHUR' );
DECLARE #Customer table (
ID int, CustomerName varchar(50), CustomerType varchar(2)
);
INSERT INTO #Customer VALUES
( 10001, 'LARRY BURNS', 'CU' ),
( 10002, 'JOHN SMITH', 'CU' ),
( 10003, 'SUSAN ARTHUR', 'CU' );
SELECT
[Date],
Amount,
Payer,
ID,
CustomerName
FROM #Payer AS payer
OUTER APPLY (
SELECT TOP 1
ID,
CustomerName
FROM #Customer AS c
WHERE
c.CustomerName = payer.Payer
OR
DIFFERENCE ( payer.Payer, c.CustomerName ) >= 3
OR
DIFFERENCE ( c.CustomerName, payer.Payer ) >= 3
) AS customer;
Returns
+------------+--------+--------------+-------+--------------+
| Date | Amount | Payer | ID | CustomerName |
+------------+--------+--------------+-------+--------------+
| 2021-01-04 | 50.00 | LARRY BURNS | 10001 | LARRY BURNS |
| 2021-01-16 | 46.00 | JOHN SMITH | 10002 | JOHN SMITH |
| 2021-01-15 | 35.00 | SUSAN ARTHUR | 10003 | SUSAN ARTHUR |
| 2021-01-14 | 28.00 | S. ARTHUR | 10003 | SUSAN ARTHUR |
| 2021-01-13 | 21.00 | JO SMITH | 10002 | JOHN SMITH |
| 2021-01-12 | 13.00 | LARRY BURNS | 10001 | LARRY BURNS |
| 2021-01-11 | 6.00 | SUSAN ARTHUR | 10003 | SUSAN ARTHUR |
+------------+--------+--------------+-------+--------------+

Oracle based PIVOT with multiple columns group

Using the following tables,
Productivity:
PRODUCTIVITYID PDATE EMPLOYEEID ROOMID ROOMS_SOLD SCR
81 03/26/2016 7499 21 56 43
82 03/26/2016 7566 42 - -
102 03/26/2016 7499 22 434 22
101 03/26/2016 7566 21 43 53
ProductivityD:
PRODUCTIVITYID WORKHRS MEALPANELTY DESCRIPTION
2 50 4 -
21 6.4 1 -
102 6 - -
81 1.32 - -
101 3.6 - -
Rooms:
ID ROOM PROPERTCODE
22 102 6325
41 103 6325
42 104 6325
43 105 6325
EMP:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
7566 JONES MANAGER 7839 04/02/1981 2975 - 20
7788 SCOTT ANALYST 7566 12/09/1982 3000 - 20
7902 FORD ANALYST 7566 12/03/1981 3000 - 20
7369 SMITH CLERK 7902 12/17/1980 800 - 20
7499 ALLEN SALESMAN 7698 02/20/1981 1600 300 30
The following query is generating below output but I need to group employees and sum workhrs and then pivot RM_ROOM and RM_SCR
WITH pivot_data AS (
SELECT eNAME,workhrs,room, 'RM' as RM,SCR from PRODUCTIVITY p,PRODUCTIVITYd d, emp e, ROOMS R
where p.PRODUCTIVITYID=d.PRODUCTIVITYID and e.empno=p.employeeid
AND R.ID=P.ROOMID
)
SELECT *
FROM pivot_data
PIVOT (
MIN(room) as room,min(scr) as SCR --<-- pivot_clause
FOR RM--<-- pivot_for_clause
IN ('RM') --<-- pivot_in_clause
)
Current Output:
ENAME WORKHRS 'RM'_ROOM 'RM'_SCR
JONES 3.6 101 53
ALLEN 6 102 22
ALLEN 1.32 101 43
Desired Output:
ENAME WORKHRS 'RM'_ROOM 'RM'_SCR 'RM'_ROOM 'RM'_SCR
JONES 3.6 101 53 - -
ALLEN 7.32 101 43 102 22
You are pivoting on a fixed value, the string literal 'RM', so you're really not doing anything useful in the pivot - the output is the same as you'd get from running the 'pivot_data' query on its own:
SELECT eNAME,workhrs,room, SCR from PRODUCTIVITY p,PRODUCTIVITYd d, emp e, ROOMS R
where p.PRODUCTIVITYID=d.PRODUCTIVITYID and e.empno=p.employeeid
AND R.ID=P.ROOMID;
ENAME WORKHRS ROOM SCR
----- ---------- ---------- ----------
JONES 3.6 101 53
ALLEN 1.32 101 43
ALLEN 6 102 22
You want the aggregate workhrs for each employee, and a pivot of the rooms they sold. If you change that query to get the analytic sum of workhrs and a ranking of the room/scr values (and using modern join syntax) you get:
select e.ename, r.room, p.scr,
sum(d.workhrs) over (partition by e.ename) as wrkhrs,
rank() over (partition by e.ename order by r.room, p.scr) as rnk
from productivity p
join productivityd d on d.productivityid = p.productivityid
join emp e on e.empno=p.employeeid
join rooms r on r.id = p.roomid;
ENAME ROOM SCR WRKHRS RNK
----- ---------- ---------- ---------- ----------
ALLEN 101 43 7.32 1
ALLEN 102 22 7.32 2
JONES 101 53 3.6 1
You can then pivot on that generated rnk number:
with pivot_data as (
select e.ename, r.room, p.scr,
sum(d.workhrs) over (partition by e.ename) as wrkhrs,
rank() over (partition by e.ename order by r.room, p.scr) as rnk
from productivity p
join productivityd d on d.productivityid = p.productivityid
join emp e on e.empno=p.employeeid
join rooms r on r.id = p.roomid
)
select *
from pivot_data
pivot (
min(room) as room, min(scr) as scr --<-- pivot_clause
for rnk --<-- pivot_for_clause
in (1, 2, 3) --<-- pivot_in_clause
);
ENAME WRKHRS 1_ROOM 1_SCR 2_ROOM 2_SCR 3_ROOM 3_SCR
----- ---------- ---------- ---------- ---------- ---------- ---------- ----------
ALLEN 7.32 101 43 102 22
JONES 3.6 101 53
You need to know the maximum number of rooms any employee may have - i.e. the highest rnk could ever be - and include all of those in the in clause. Which means you're likely to end up with empty columns, as in this example where there is no data for 3_room or 3_scr. You can't avoid that though, unless you get an XML result or generate the query dynamically.
What you are saying makes no sense. What do you mean by "pivot RM_ROOM"? So I have to guess. I am guessing you want to group employees and sum workhrs, and then pivot the result. The "Output" you show seems to be the output for pivot_data, your subquery.
Your answer will only have eNAME and for each of them, a count of hours worked. So you don't need to SELECT the room numbers in the pivot_data subquery. You only need eNAME and workhrs. Then it is a simple matter of using the PIVOT syntax:
WITH pivot_data AS (
SELECT eNAME, workhrs FROM PRODUCTIVITY p,PRODUCTIVITYd d, emp e, ROOMS R
where p.PRODUCTIVITYID=d.PRODUCTIVITYID and e.empno=p.employeeid
AND R.ID=P.ROOMID
)
SELECT *
FROM pivot_data
PIVOT (
SUM(workhrs)
FOR eNAME IN ('JONES', 'ALLEN')
)
/
Output:
'JONES' 'ALLEN'
---------- ----------
3.6 7.32

How to get the employees with their managers in a Report Format

Can someone help me to resolve the following issues please?
Issues:
I need a SQL Server Query to generate a Report listing the Employees in their order of Job Profile Hierarchy
-
The CTE Query generates a wrong output in the first record with Manager Name and Job Profile where MgrID is NULL
The Sample Data is:
Query:
Select * From MyEmp;
Result:
EmpNo EmpName JobProfile DeptNo MgrID LevelID
7839 KING PRESIDENT 10 NULL 01
7698 BLAKE MANAGER 30 7839 02
7782 CLARK MANAGER 10 7839 02
7566 JONES MANAGER 20 7839 02
7654 MARTIN SALESMAN 30 7698 03
7499 ALLEN SALESMAN 30 7698 03
7844 TURNER SALESMAN 30 7698 03
7900 JAMES CLERK 30 7698 03
7521 WARD SALESMAN 30 7698 03
7902 FORD ANALYST 20 7566 03
7369 SMITH CLERK 20 7902 04
7788 SCOTT ANALYST 20 7566 03
7876 ADAMS CLERK 20 7788 04
7934 MILLER CLERK 10 7782 03
The CTE Query is:
CTE Query:
WITH Subordinates AS
(
(SELECT e.EmpNo, e.EmpName, e.JobProfile, e.LevelID, e.MgrID,
m.EmpName MgrName, m.JobProfile MgrProfile
FROM MyEmp AS e
INNER JOIN
MyEmp AS m ON
e.MgrID is NULL
AND m.MgrID is NULL)
UNION ALL
(SELECT e.EmpNo, e.EmpName, e.JobProfile, e.LevelID, e.MgrID,
sub.EmpName MgrName, sub.JobProfile MgrProfile
FROM MyEmp AS e
INNER JOIN
Subordinates AS sub ON
e.MgrID = sub.EmpNo
)
)
SELECT * FROM Subordinates AS s;
Result:
EmpNo EmpName JobProfile LevelID MgrID MgrName MgrProfile
7839 KING PRESIDENT 01 NULL KING PRESIDENT
7698 BLAKE MANAGER 02 7839 KING PRESIDENT
7782 CLARK MANAGER 02 7839 KING PRESIDENT
7566 JONES MANAGER 02 7839 KING PRESIDENT
7902 FORD ANALYST 03 7566 JONES MANAGER
7788 SCOTT ANALYST 03 7566 JONES MANAGER
7876 ADAMS CLERK 04 7788 SCOTT ANALYST
7369 SMITH CLERK 04 7902 FORD ANALYST
7934 MILLER CLERK 03 7782 CLARK MANAGER
7654 MARTIN SALESMAN 03 7698 BLAKE MANAGER
7499 ALLEN SALESMAN 03 7698 BLAKE MANAGER
7844 TURNER SALESMAN 03 7698 BLAKE MANAGER
7900 JAMES CLERK 03 7698 BLAKE MANAGER
7521 WARD SALESMAN 03 7698 BLAKE MANAGER
The Oracle Query with CONNECT BY ... PRIOR TO is capable of resolving this problem, but I need a Query that can be effective on a SQL Server
Oracle Query
Select e.MgrID,
--m.EmpName MgrName, m.JobProfile MgrProfile,
e.EmpNo, e.EmpName, e.JobProfile
FROM MyEmp AS e
-- LEFT OUTER JOIN
-- MyEmp AS m ON
-- e.MgrID is NULL
--AND m.MgrID is NULL
START WITH e.MgrID is NULL
CONNECT BY PRIOR EmpNo = MgrID
;

Oracle INSERT ALL with SELECT giving invalid specification error

I want to use the INSERT ALL statement to insert 2 rows into 2 different tables.
But if I want to insert values by myself, the below query works fine.
insert all
into REGIONS values (5,'Africa')
into JOBS values ('ZZZZ','Shop Sleeper',1000,1000)
select * from DUAL;
However if I want to duplicate a row with a different primary key value, the below statement gives me ORA-01747 error.
insert all
into REGIONS (select :REGION_ID,REGION_NAME from REGION where REGION_ID = 4)
into JOBS (select :JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY where JOB_ID = 'ST_CLERK')
select * from DUAL;
I dont know how to rectify the query. Please help.
insert all
into REGIONS (select :REGION_ID,REGION_NAME from REGION where REGION_ID = 4)
into JOBS (select :JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY where JOB_ID = 'ST_CLERK')
select * from DUAL;
The above INSERT ALL is incorrect syntactically. You must mention the VALUES keyword, and list the required columns you want to select from the table to insert the rows.
The correct syntax is:
INSERT ALL
INTO REGIONS VALUES
(
REGION_ID,
REGION_NAME
)
INTO JOBS VALUES
(
JOB_ID,
JOB_TITLE,
MIN_SALARY,
MAX_SALARY
)
SELECT REGION_ID,
REGION_NAME,
JOB_ID,
JOB_TITLE,
MIN_SALARY,
MAX_SALARY
FROM region, jobs
WHERE region.column=job.column --> Jon with the required key
AND ...; --> Put the required filter conditions
Test Case #1
With same columns in destination table.
SQL> CREATE TABLE tab1(a NUMBER, b varchar2(20));
Table created.
SQL> CREATE TABLE tab2(a NUMBER, b varchar2(20));
Table created.
SQL>
SQL> INSERT ALL
2 INTO tab1(A, b) VALUES(empno, ename)
3 INTO tab2(A, b)VALUES(empno, ename)
4 SELECT empno, ename FROM emp;
28 rows created.
SQL>
So, all rows are inserted into the tables tab1 and tab2 respectively. Let's see:
SQL> SELECT * FROM tab1;
A B
---------- --------------------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
14 rows selected.
SQL> SELECT * FROM tab2;
A B
---------- --------------------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
14 rows selected.
SQL>
Test Case #2
With different columns in destination table.
SQL> CREATE TABLE tab1(a NUMBER);
Table created.
SQL> CREATE TABLE tab2(b varchar2(20));
Table created.
SQL>
SQL> INSERT ALL
2 INTO tab1(A) VALUES(empno)
3 INTO tab2(b)VALUES(ename)
4 SELECT empno, ename FROM emp;
28 rows created.
Let's see:
SQL> SELECT * FROM tab1;
A
----------
7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934
14 rows selected.
SQL> SELECT * FROM tab2;
B
--------------------
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER
14 rows selected.
SQL>
Test Case #3
With different columns in destination table and different columns in source table
SQL> CREATE TABLE tab1(A VARCHAR2(20));
Table created.
SQL> CREATE TABLE tab2(b NUMBER);
Table created.
SQL>
SQL> INSERT ALL
2 INTO tab1(A) VALUES(ename)
3 INTO tab2(b)VALUES(deptno)
4 SELECT e.ename ename, d.deptno deptno FROM emp e, dept d
5 where e.deptno = d.deptno;
28 rows created.
SQL>
Let's see:
SQL> SELECT * FROM tab1;
A
--------------------
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER
14 rows selected.
SQL> SELECT * FROM tab2;
B
----------
20
30
30
20
30
30
10
20
10
30
20
30
20
10
14 rows selected.
SQL>
Try this...
INSERT ALL
INTO REGIONS(REGION_ID,REGION_NAME)
SELECT REGION_ID,REGION_NAME from REGION where REGION_ID = 4
INTO JOBS(JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY)
SELECT JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY where JOB_ID = 'ST_CLERK'
SELECT * FROM DUAL;

Regarding multiple insertion of rows through single query.(oracle)

Is the mechanism used in multiple insertion of rows in the table through single query is same as that of inserting single row with a single query.If not what is the exact mechanism?
If you are fetching the data from an existing table, you can use INSERT INTO TABLE3 ( SELECT * FROM TABLE1 UNION SELECT * FROM TABLE2 ....) to fetch and insert the data in a single go.
SQL> SELECT * FROM SCOTT.EMP WHERE JOB = 'ANALYST1';
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO GENDER
---------- ---------- --------- ---------- --------- ---------- ---------- ---------- --------
8909 LUTHAR ANALYST1 7698 22-JUL-99 1232 788 50 F
8999 AMAN ANALYST1 7698 22-JUL-99 8569 788 50 M
7788 SCOTT ANALYST1 7566 19-APR-87 3000 150 M
7902 2 ANALYST1 7566 03-DEC-81 3000 M
SQL> SELECT * FROM SCOTT.EMP WHERE JOB = 'MANAGER';
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO GENDER
---------- ---------- --------- ---------- --------- ---------- ---------- ---------- ---------
7566 5 MANAGER 7839 02-APR-81 2975 150 F
7698 10000 MANAGER 7839 01-MAY-81 2850 150 F
7782 CLARK MANAGER 7839 09-JUN-81 2450 150 F
SQL> CREATE TABLE EMP1 AS ( SELECT * FROM SCOTT.EMP WHERE 1=2);
Table created.
SQL> SELECT * FROM EMP1;
no rows selected
SQL> INSERT INTO EMP1 ( SELECT * FROM SCOTT.EMP WHERE JOB = 'ANALYST1'
2 UNION
3 SELECT * FROM SCOTT.EMP WHERE JOB = 'MANAGER');
7 rows created.
SQL> SELECT * FROM EMP1;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO GENDER
---------- ---------- --------- ---------- --------- ---------- ---------- ---------- --------
7566 5 MANAGER 7839 02-APR-81 2975 150 F
7698 10000 MANAGER 7839 01-MAY-81 2850 150 F
7782 CLARK MANAGER 7839 09-JUN-81 2450 150 F
7788 SCOTT ANALYST1 7566 19-APR-87 3000 150 M
7902 2 ANALYST1 7566 03-DEC-81 3000 M
8909 LUTHAR ANALYST1 7698 22-JUL-99 1232 788 50 F
8999 AMAN ANALYST1 7698 22-JUL-99 8569 788 50 M
7 rows selected.
You can chain many SQL statements in a single Oracle query by separating each SQL command with a semicolon. For instance:
INSERT INTO table VALUES(1,2); INSERT INTO table VALUES(3,4);

Resources