I'm having issues displaying the nested table column data as some of the records are trailing off, is there a way to sort out the format where the order_items are below one another?
SQL> SELECT order_id, billing_name, items FROM orders;
ORDER_ID BILLING_NAME ITEMS(ORDER_ID, PRODUCT_ID, SELLER_ID, SUB_ORDER_NUMBER, QUANTITY, CONDITION, UNIT_PRICE, COST_CHARGE, TOTAL)
---------- --------------- ---------------------------------------------------------------------------------------------------------------------------------------
1 John Smith ORDER_ITEMS(ORDER_ITEM(1, 1, 1, '3026143053', 1, 'Brand new ', 53.49, 0, 53.49), ORDER_ITEM(1, 2, 2, '3029608429', 1, 'Brand new ', 1.9
2 Sarah Jones ORDER_ITEMS(ORDER_ITEM(2, 3, 3, '3054134547', 2, 'Brand New ', 53.49, 0, 106.98), ORDER_ITEM(2, 4, 4, '3053273551', 1, 'Brand New ', 29
3 Tom Sharpe ORDER_ITEMS(ORDER_ITEM(3, 2, 2, '3073748221', 1, 'Brand New ', 7.97, 2, 9.97), ORDER_ITEM(3, 6, 5, '3146744589', 1, 'Brand New ', 779.9
4 Derek Miller ORDER_ITEMS(ORDER_ITEM(4, 4, 4, '3124685316', 1, 'Brand New ', 299, 0, 299), ORDER_ITEM(4, 5, 5, '3157302741', 1, 'Brand New ', 639.95,
5 Mark Dwight ORDER_ITEMS(ORDER_ITEM(5, 1, 1, '3246315960', 1, 'Brand New ', 53.49, 0, 53.49), ORDER_ITEM(5, 2, 2, '3354174322', 1, 'Brand New ', 1.9
6 Lucy Nolan ORDER_ITEMS(ORDER_ITEM(6, 4, 4, '3821362630', 1, 'Brand New ', 299, 0, 299), ORDER_ITEM(6, 3, 3, '3902471881', 1, 'Brand New ', 53.49,
6 rows selected.
SQL> SPOOL OFF
Are you looking for a result like this?
ORDER_ID BILLING_NAME PRODUCT_ID SELLER_ID SUB_ORDER_ QUANTITY CONDITION UNIT_PRICE COST_CHARGE TOTAL
-------- --------------- ---------- --------- ---------- -------- --------- ---------- ----------- --------
1 John Smith 1 1 3026143053 1 Brand new 53.49 0 53.49
2 2 3029608429 1 Brand new 1.90 1 2.90
2 Sarah Jones 3 3 3054134547 2 Brand New 53.49 0 106.98
4 4 3053273551 1 Brand New 29.22 0 29.22
3 Tom Sharpe 2 2 3073748221 1 Brand New 7.97 2 9.97
6 5 3146744589 1 Brand New 779.95 0 779.95
4 Derek Miller 4 4 3124685316 1 Brand New 299.00 0 299.00
5 5 3157302741 1 Brand New 639.95 0 639.95
5 Mark Dwight 1 1 3246315960 1 Brand New 53.49 0 53.49
2 2 3354174322 1 Brand New 1.90 1 1.90
6 Lucy Nolan 4 4 3821362630 1 Brand New 299.00 0 299.00
3 3 3902471881 1 Brand New 53.49 1 54.49
You can do this with a combination of two things: A query that flattens the data (unnesting the nested table column - generating multiple rows per order_id) and SQL*Plus formatting commands - in this case the break command to show each (order_id, billing_name) just once for each group. You may also need/want to format the individual columns, so that a unit price of 1.9, for example, is shown as 1.90, but that is an unrelated (and much easier) problem; I don't show how to do that.
So, here is the SQL*Plus command first, and then the query. Note that your records in the nested table have an order_id attribute; that is supposed to be the order_id you have in the table already, so I left it out from the query (and its output). Indeed, it is not clear why it's part of the record, if the "tables" are nested within a parent table that has the order_id already; I will let you philosophise about that.
SQL> break on order_id on billing_name
SQL> select o.order_id, o.billing_name, product_id, seller_id, sub_order_number,
2 quantity, condition, unit_price, cost_charge, total
3 from orders o left outer join lateral (select * from table(o.items))
4 on null is null
5 /
The outer (lateral) join is necessary for the case when items is atomically null, and also for the case when items is an empty nested table. Both situations are possible; I assume you are aware that the two are not the same.
Related
I have a POST table, a CATEGORY table, a ACTION table and ACTION_TYPE table, I explain the ACTION table contains all the actions that were made, and the table ACTION_TYPE contains the actions details for example the ACTION whose ID = 4 has ACTION_TYPE_ID = 1 for POST_ID 6, which mean an action was made for post number 50, we can have many actions for one post_id
The POST table
id title content category_id
---------- ---------- ---------- ------------
1 title1 Text... 1
2 title2 Text... 1
3 title3 Text... 1
4 title4 Text... 3
5 title5 Text... 2
6 title6 Text... 1
The CATEGORY table
id name
---------- ----------
1 category_1
2 category_2
3 category_3
The ACTION_TYPE table
id name
---------- ----------
1 updated
2 deleted
3 restored
4 hided
The ACTION table
id post_id action_type_id date
---------- ---------- -------------- -----
1 1 1 2017-01-01
2 1 1 2017-02-15
3 1 3 2018-06-10
4 6 1 2019-08-01
5 5 2 2019-12-09
6 2 3 2020-04-27
7 2 1 2020-07-29
8 3 2 2021-03-13
Now I explain the case, I actually have two queries a query to count the posts for each category and another to count the actions performed on each post by category which work perfectly.
Here is my first query
select categories, count(*) as cnt_posts_per_cat
from(
select
case
when p.category_id is not null then c.name
end as categories
from post p
left join category c on p.category _id = c.id
)
group by categories
;
Which brings this result
categories cnt_posts_per_cat
---------- -------------------
category_1 4
category_2 1
category_3 1
Ans here is my second query
select categories, count(*) as cnt_actions_per_cat
from(
select distinct ac.post_id AS action_post_id, max(ac.date) over (partition by ac.post_id) as max_date,
case
when ac.action_type_id is not null then act.name
end as actions,
case
when p.category_id is not null then c.name
else 'na'
end as categories
from action ac
left join post p on ac.post_id = p.id
left join category c on p.category _id = c.id
left join action_type act on ac.action_type_id = act.id
where act.name in ('restored','deleted','updated')
)
group by categories
;
Which brings this correct result because it's seclect the last action for each action_type
categories cnt_actions_per_cat
---------- -------------------
category_1 3
category_2 1
category_3 na
But I would like to have a single result table for both queries at the same time as follow :
Here the result expected to be
categories cnt_posts_per_cat cnt_actions_per_cat
---------- ----------------- -------------------
category_1 4 3
category_2 1 1
category_3 1 na
i was trying union and union all but it's not correct it return following result
categories cnt_posts_per_cat
---------- -----------------
category_1 7
category_2 2
category_3 1
Best regards
How about correlated subqueries?
Sample data:
SQL> with
2 post (id, category_id) as
3 (select 1, 1 from dual union all
4 select 2, 1 from dual union all
5 select 3, 1 from dual union all
6 select 4, 3 from dual union all
7 select 5, 2 from dual union all
8 select 6, 1 from dual
9 ),
10 category (id, name) as
11 (select 1, 'category_1' from dual union all
12 select 2, 'category_2' from dual union all
13 select 3, 'category_3' from dual
14 ),
15 action_type (id, name) as
16 (select 1, 'updated' from dual union all
17 select 2, 'deleted' from dual union all
18 select 3, 'restored' from dual union all
19 select 4, 'hided' from dual
20 ),
21 action (id, post_id, action_type_id) as
22 (select 1, 1, 1 from dual union all
23 select 2, 1, 1 from dual union all
24 select 3, 1, 3 from dual union all
25 select 4, 6, 1 from dual union all
26 select 5, 5, 2 from dual union all
27 select 6, 2, 3 from dual union all
28 select 7, 2, 1 from dual union all
29 select 8, 3, 2 from dual
30 )
Query begins here:
31 select c.name,
32 --
33 (select count(*)
34 from post p
35 where p.category_id = c.id
36 ) cnt_posts_per_cat,
37 --
38 (select count(*)
39 from action a join post p on p.id = a.post_id
40 join action_type t on t.id = a.id
41 where p.category_id = c.id
42 and t.name in ('restored', 'deleted', 'updated')
43 ) cnt_actions_per_cat
44 from category c
45 order by c.name;
NAME CNT_POSTS_PER_CAT CNT_ACTIONS_PER_CAT
---------- ----------------- -------------------
category_1 4 3
category_2 1 0
category_3 1 0
SQL>
I have a dataset in which one column is Branch-ID and other one is Branch Manager and it looks as follows in the given url.
dataset
I want to combine the branch managers into one single column based on the branch-id. For example if Bob and Sandra are two different branch-managers but have the same branch id which is branch-id=1, then we should concatenate them together as Bob-Sandra and place them in a separately created column.
I have attached the expected output for the above dataset. expected_output_dataset
I am currently using Oracle Analytics Cloud Professional Version.
I don't know Oracle Analytics, but - if it has anything to do with an Oracle database and its capabilities, then listagg helps.
Sample data in lines #1 - 10; query you might be interested in begins at line #11.
SQL> with test (account_id, branch_id, branch_manager) as
2 (select 1, 123, 'Sandra' from dual union all
3 select 3, 124, 'Martha' from dual union all
4 select 4, 125, 'John' from dual union all
5 select 6, 126, 'Andrew' from dual union all
6 select 7, 126, 'Mathew' from dual union all
7 select 2, 123, 'Michael' from dual union all
8 select 5, 125, 'David' from dual union all
9 select 8, 126, 'Mark' from dual
10 )
11 select a.account_id, a.branch_id, a.branch_manager,
12 b.concatenated_column
13 from test a join (select branch_id,
14 listagg(branch_manager, '-') within group (order by null) concatenated_column
15 from test
16 group by branch_id
17 ) b on b.branch_id = a.branch_id;
ACCOUNT_ID BRANCH_ID BRANCH_ CONCATENATED_COLUMN
---------- ---------- ------- -------------------------
1 123 Sandra Michael-Sandra
3 124 Martha Martha
4 125 John David-John
6 126 Andrew Andrew-Mark-Mathew
7 126 Mathew Andrew-Mark-Mathew
2 123 Michael Michael-Sandra
5 125 David David-John
8 126 Mark Andrew-Mark-Mathew
8 rows selected.
SQL>
I have a hierarchical data of Category-Products. This is 3 level hierarchy & all the products will always be assigned to the last level. I want do display a drill down report of all the products grouped by Category - Sub Category & Sub Sub Category. Only those categories will be displayed on report for which we have product result. (Result Products are decided by some other criteria, out of scope for this question).
How can I get all the Category data till root level in oracle.
Sample Data
CategoryId Name Parent
1 Clothing NULL
2 Men's Wear 1
3 Shirt 2
4 T-Shirt 2
5 Women's Wear 1
6 Salwar 5
7 Saree 5
8 Electronics NULL
9 Computers 8
10 Mobiles 8
Products table will have Category Id reference. Ex. 3, 4 or 6, 7 etc
I want to retrieve only categories till root level where we have products. I have below query but I am not sure if this is good practice to specify multiple values for START WITH clause. Is there any better option?
SELECT DISTINCT CategoryId,Name,Parent
FROM tblCategory
START WITH CategoryId IN (3,6)
CONNECT BY CategoryId = PRIOR Parent
For above query I have specified only two categories but in real world it could be thousands. Below is result data showing only categories for selected products.
Output:
CategoryId Name Parent
1 Clothing NULL
2 Men's Wear 1
3 Shirt 2
5 Women's Wear 1
6 Salwar 5
So you basically solved your problem. You can list ID's as you did or you can store them somewhere and use in IN subquery, like here for instance:
with tblCategory(CategoryId, Name, Parent) as (
select 1, 'Clothing', null from dual union all
select 2, 'Men''s Wear', 1 from dual union all
select 3, 'Shirt', 2 from dual union all
select 4, 'T-Shirt', 3 from dual union all
select 5, 'Women''s Wear', 1 from dual union all
select 6, 'Salwar', 5 from dual union all
select 7, 'Saree', 5 from dual union all
select 8, 'Electronics', null from dual union all
select 9, 'Computers', 8 from dual union all
select 10, 'Mobiles', 8 from dual ),
ids(cid) as (select 3 from dual union all select 6 from dual)
select distinct categoryid, name, parent
from tblcategory
start with categoryid in (select cid from ids)
connect by categoryid = prior parent
Result:
CATEGORYID NAME PARENT
---------- ------------ ----------
6 Salwar 5
3 Shirt 2
5 Women's Wear 1
2 Men's Wear 1
1 Clothing
You could also produce more readable output like here:
select connect_by_root(categoryid) root,
sys_connect_by_path(name, ' => ') path
from tblcategory
where connect_by_isleaf = 1
start with categoryid in (select cid from ids)
connect by categoryid = prior parent
Result:
ROOT PATH
------ --------------------------------------------------------------------------------
3 => Shirt => Men's Wear => Clothing
6 => Salwar => Women's Wear => Clothing
I am using Oracle Forms and Reports. I am a beginner.
I have a table invoice having fields INVNO,INVDATE.
Invoice table:
Invno Invdate
INVNO1 03/03/2017
Another table passing having these fields :
Passing table
Invno debitcode credit amount sln
INVNO1 debit1 credit1 100 1
INVNO1 debit2 credit2 200 2
INVNO1 debit3 credit3 150 3
INVNO1 debit4 credit4 250 4
Number of records for debit and credit may vary and maximum number of records is 7.
In a form I want to display a horizontal row of record depending on number of records
Invoice No Debit1 Credit1 Amount Debit2 credit2 Amount ..Debit4 Credit4
Forms can't do anything "dynamic", so you'll have to hardcode all 7 credit/debit values, such as this (I've done it up to 3 values). I'd suggest you to create a view based on such a query:
SQL> with passing (invno, debit, credit, amount, sln) as
2 (select 'invno1', 'debit1', 'credit1', 100, 1 from dual union
3 select 'invno1', 'debit2', 'credit2', 200, 2 from dual union
4 select 'invno1', 'debit3', 'credit3', 150, 3 from dual union
5 select 'invno1', 'debit4', 'credit4', 250, 4 from dual)
6 select invno,
7 max(decode(sln, 1, debit)) debit1,
8 max(decode(sln, 1, credit)) credit1,
9 max(decode(sln, 1, amount)) amount1,
10 --
11 max(decode(sln, 2, debit)) debit2,
12 max(decode(sln, 2, credit)) credit2,
13 max(decode(sln, 2, amount)) amount2,
14 --
15 max(decode(sln, 3, debit)) debit3,
16 max(decode(sln, 3, credit)) credit3,
17 max(decode(sln, 3, amount)) amount3
18 from passing
19 group by invno;
INVNO DEBIT1 CREDIT1 AMOUNT1 DEBIT2 CREDIT2 AMOUNT2 DEBIT3 CREDIT3 AMOUNT3
------ ------ ------- ---------- ------ ------- ---------- ------ ------- ----------
invno1 debit1 credit1 100 debit2 credit2 200 debit3 credit3 150
As of Reports: well, the simplest option is to reuse query (or a view, as I've suggested) you used in Forms. Or, if you feel like it, create a matrix report which is capable of doing it dynamically.
P.S. Oh, yes - forgot to ask: title says "error". Which error? You didn't specify it.
I am working on a time attendance system. I have the employees' transactions stored in the following table:
I want to get the earliest and the latest transactions for each employee including their date and type.
I am able to get the dates using grouping and aggregation. However, I am not able to figure out how to get types with them.
Would you please help me in it.
Thank you.
That's what the FIRST and LAST aggregate functions are designed for.
Here is a link to the documentation:
FIRST: http://download.oracle.com/docs/cd/E11882_01/server.112/e17118/functions065.htm#SQLRF00641
LAST: http://download.oracle.com/docs/cd/E11882_01/server.112/e17118/functions083.htm#sthref1206
And here is an example:
SQL> create table my_transactions (id,employee_id,action_date,type)
2 as
3 select 1, 1, sysdate, 'A' from dual union all
4 select 2, 1, sysdate-1, 'B' from dual union all
5 select 3, 1, sysdate-2, 'C' from dual union all
6 select 4, 1, sysdate-3, 'D' from dual union all
7 select 5, 2, sysdate-11, 'E' from dual union all
8 select 6, 2, sysdate-12, 'F' from dual union all
9 select 7, 2, sysdate-13, 'G' from dual
10 /
Table created.
SQL> select *
2 from my_transactions
3 order by id
4 /
ID EMPLOYEE_ID ACTION_DATE T
---------- ----------- ------------------- -
1 1 04-07-2011 10:15:07 A
2 1 03-07-2011 10:15:07 B
3 1 02-07-2011 10:15:07 C
4 1 01-07-2011 10:15:07 D
5 2 23-06-2011 10:15:07 E
6 2 22-06-2011 10:15:07 F
7 2 21-06-2011 10:15:07 G
7 rows selected.
SQL> select employee_id
2 , min(action_date) min_date
3 , max(type) keep (dense_rank first order by action_date) min_date_type
4 , max(action_date) max_date
5 , max(type) keep (dense_rank last order by action_date) max_date_type
6 from my_transactions
7 group by employee_id
8 /
EMPLOYEE_ID MIN_DATE M MAX_DATE M
----------- ------------------- - ------------------- -
1 01-07-2011 10:15:07 D 04-07-2011 10:15:07 A
2 21-06-2011 10:15:07 G 23-06-2011 10:15:07 E
2 rows selected.
Regards,
Rob.
You could try to use analytical(or windowing functions)
select *
from
(select id, employee_id, action_date,type,
max(action_date) over (partition by employee_id) max_action_date,
min(action_date) over (partition by employee_id) min_action_date
from transaction)
where action_date in (max_action_date, min_action_date)