I have the following data in TABLE_A, where ORG_1 is the parent of ORG_2:
ORG_1 ORG_2
01 02
02 03
02 04
05 06
So, org 01 is the parent of org 02, and org 02 is the parent of 03 and 04. Org 5 is the parent of only org 06.
I need to have unique names/numbers for the chains, and get reported the highest parent in the chain. Chain I define as 'all organisations that are related to each other'.
This is the desired result:
Chain ORG_1 ORG_2 Highest_Parent_In_Chain
1 01 02 01
1 02 03 01
1 02 04 01
2 05 06 05
Chain=1 has a tree structure starting from ORG_1=01. Chain=2 has it's own chain.
I found some info about CONNECT BY, CONNECT BY PRIOR and CONNECT_BY_ROOT, but I don't get it working. Does anyone has an idea how to achieve this with a query in Oracle?
The chain number can be created with the analytic DENSE_RANK() function.
The highest parent in chain is a feature of hierarchical queries: the function CONNECT_BY_ROOT().
Your hierarchical table is non-standard - in a standard arrangement, the top levels (organizations 01 and 05) would also have a row where they appear as ORG_2, with NULL as ORG_1. That way the highest levels in the hierarchy are very easy to find: just look for ORG_1 IS NULL. As it is, the START WITH clause is more complicated, because we must find the tops first. For that we look for values of ORG_1 that do not also appear in ORG_2. That is the work done in the subquery in the START WITH clause.
with
table_a ( org_1, org_2 ) as (
select '01', '02' from dual union all
select '02', '03' from dual union all
select '02', '04' from dual union all
select '05', '06' from dual
)
-- End of simulated input data (for testing purposes only).
-- Solution (SQL query) begins BELOW THIS LINE.
select dense_rank() over (order by connect_by_root(org_1)) as chain,
org_1, org_2,
connect_by_root(org_1) as highest_parent_in_chain
from table_a
connect by org_1 = prior org_2
start with org_1 in
( select org_1 from table_a a
where not exists (select * from table_a where org_2 = a.org_1)
)
;
CHAIN ORG_1 ORG_2 HIGHEST_PARENT_IN_CHAIN
----- ----- ----- -----------------------
1 01 02 01
1 02 03 01
1 02 04 01
2 05 06 05
Related
Assuming I have a table containing the following information:
ID NAME Boss Main responsibility
01 Tommy x3 Yes
02 Elis x2 Yes
02 Elis x3 No
03 John x65 yes
04 Lille x50 yes
is there a way I can perform a select on the table to get the following(sql :DB2)
ID NAME main responsibility
01 Tommy X3
02 Elis X2(main responsibility) AND X3
03 John X65
04 Lille x50
Thanks
If your version of DB2 support it, you may aggregate and use the LISTAGG() function:
SELECT
ID,
NAME,
LISTAGG(CONCAT(Boss, CASE WHEN main = 'Yes' THEN ' (main)' ELSE '' END), ', ')
WITHIN GROUP(ORDER BY main DESC) AS main
FROM yourTable
GROUP BY ID, NAME
ORDER BY ID;
i've a sheet like this:
Month(Col11)
Team (Col2)
03
luna
03
luna
04
pippo
04
gigi
04
luna
04
gigi
04
pippo
04
luna
04
luna
04
pippo
04
pippo
04
grisbi
04
grisbi
05
luna
05
luna
05
pippo
05
pippo
05
grisbi
05
grisbi
i need the sum of unique of each month, a result like this:
Month(Col11)
Sum of unique (Col2)
03
1
04
4
05
3
i try with:
=QUERY(database_tornei!A:K;"select Col11,count(Col2) group by Col11")
But i've the sum of all Teams in Col2.
Don't know how to use dinstinct in query :(
You can wrap your existing query() in another query() like this:
=query( query(A1:K, "select K, A, count(K) where K is not null group by K, A", 1), "select Col1, count(Col3) group by Col1", 1 )
This will get the count of uniques per month.
I asked some questions in the comments below the original post, but haven't heard back yet. So I'll just provide two versions of a formula, one for each case.
If your data in Col11 is text/strings, use this:
=ArrayFormula(QUERY(UNIQUE({K2:K,B2:B}),"Select Col1, COUNT(Col1) WHERE Col1 Is Not Null GROUP BY Col1 LABEL Col1 'Month', COUNT(Col1) 'Count Unique'"))
If your data in Col11 is real numbers, use this:
=ArrayFormula(QUERY(UNIQUE({TEXT(K2:K,"00"),B2:B}),"Select Col1, COUNT(Col1) WHERE Col1 <> '00' GROUP BY Col1 LABEL Col1 'Month', COUNT(Col1) 'Count Unique'"))
In this second case, you need to convert the numbers to text in order to produce a format with a leading zero as shown in your post example.
This still does not account for distinguishing the months from different years. If your sheet will only ever have months from a single year, you don't need to worry about it. But if you will keep cumulative data that spans more than one calendar year, you will want to change the format of Col11 to something like this:
03 [2021]
04 [2021]
...
12 [2021]
01 [2022]
02 [2022]
03 [2022]
If you decide to do it this way, you can still use the first formula I provided above. It will just assure that months from different years stay separate.
I have a historical table XY with these contents:
ID Person_ID Balance_on_account ts
---- ----------- -------------------- ----------
01 05 +10 10.10.14
02 05 -10 20.10.14
03 05 -50 30.10.14
04 05 +50 30.10.14
05 05 -10 30.10.14
06 06 11 11.10.14
07 06 -40 15.10.14
08 06 +5 16.10.14
09 06 -10 30.10.14
and I need to create an SQL query which will give me those Person_ID's and timestamps where are
a) the Balance_on_account is negative - that's the easy one,
b) and at the same time is the record of negative Balance_on_account followed by a positive number.
Like for Person_ID = 05 I would have the row with ID = 05, and for Person_ID = 06 the row with ID = 09.
I never used it, but you could try analytic LEAD function
SELECT *
FROM (
SELECT ID, Person_ID, Balance_on_account, ts
LEAD (Balance_on_account, 1)
OVER (PARTITION BY Person_ID ORDER BY ID) next_balance
FROM XY)
WHERE Balance_on_account < 0 and next_balance >= 0
ORDER BY ID
LEAD lets you access the following rows in a query without joining with itself.
PARTITION BY groups rows by Person_ID so it doesn't mix different person's balances and ORDER BY defines the order within each group.
The filtering cannot be done in the inner query because it'd filter out the rows with positive balance.
next_balance will be null for the last row.
source analytic functions and LEAD
The following query should give you the expected results provided the database platform you are using supports Common Table Expressions and Window Functions e.g. SQL Server 2008 and up.
SqlFiddle
WITH TsOrder AS
(
SELECT
Id
, Person_Id
, Balance_on_account
, ts
, ROW_NUMBER() OVER(PARTITION BY Person_Id
ORDER BY ts, Id) AS ts_Order
FROM
[TableName]
)
SELECT
*
FROM
TsOrder
LEFT JOIN TsOrder AS NextTs
ON TsOrder.Person_id = NextTs.Person_Id
AND TsOrder.ts_order = NextTs.ts_order - 1
WHERE
TsOrder.Balance_on_account < 0
AND NextTs.Balance_on_account > 0
So I have a table like:
UNIQUE_ID MONTH
abc 01
93j 01
acc 01
7as 01
oks 02
ais 02
asi 03
asd 04
etc
I query:
select count(unique_id) as amount, month
from table
group by month
now everything looks great:
AMOUNT MONTH
4 01
2 02
1 03
etc
is there a way to get oracle to split the amounts by weeks?
the way that the result look something like:
AMOUNT WEEK
1 01
1 02
1 03
1 04
etc
Assuming you know the year - lets say we go with 2014 then you need to generate all the weeks a year
select rownum as week_no
from all_objects
where rownum<53) weeks
then state which months contain the weeks (for 2014)
select week_no, to_char(to_date('01-JAN-2014','DD-MON-YYYY')+7*(week_no-1),'MM') month_no
from
(select rownum as week_no
from all_objects
where rownum<53) weeks
Then join in your data
select week_no,month_no, test.unique_id from (
select week_no, to_char(to_date('01-JAN-2014','DD-MON-YYYY')+7*(week_no-1),'MM') month_no
from
(select rownum as week_no
from all_objects
where rownum<53) weeks) wm
join test on wm.month_no = test.tmonth
This gives your data for the each week as you described above. You can redo your query and count by week instead of month.
If you have the select statement below where the PK is the primary key:
select distinct dbo.DateAsInt( dateEntered) * 100 as PK,
recordDescription as Data
from MyTable
and the output is something like this (the first numbers are spaced for clarity):
PK Data
2010 01 01 00 New Years Day
2010 01 01 00 Make Resolutions
2010 01 01 00 Return Gifts
2010 02 14 00 Valentines day
2010 02 14 00 Buy flowers
and you want to output something like this:
PK Data
2010 01 01 01 New Years Day
2010 01 01 02 Make Resolutions
2010 01 01 03 Return Gifts
2010 02 14 01 Valentines day
2010 02 14 02 Buy flowers
Is it possible to make the "00" in the PK have an "identity" number effect within a single select? Otherwise, how could you increment the number by 1 for each found activity for that date?
I am already thinking as I type to try something like Sum(case when ?? then 1 end) with a group by.
Edit: (Answer provided by JohnFX below)
This was the final answer:
select PK + row_number() over
(PARTITION BY eventid order by eventname) as PK,
recordDescription
from (select distinct -- Removes row counts of excluded rows)
dbo.DateAsInt( dateEntered) as PK,
recordDescription as Data
from MyTable) A
order by eventid, recordDescription
I think you are looking for ROW_NUMBER and the associated PARTITION clause.
SELECT DISTINCT dbo.DateAsInt(DateEntered) * 100 as PK,
ROW_NUMBER() OVER (PARTITION BY DateEntered ORDER BY recordDescription) as rowID,
recordDescription as Data
FROM MyTable
If DateEntered has duplicate values you probably also want to check out DENSE_RANK() and RANK() depending on your specific needs for what to do with the incrementor in those cases.
Datetime columns should never ever be used as primary key. Plus, if you had an indetity column, you couldn't have:
PK Data
2010 01 01 01 New Years Day
2010 01 01 02 Make Resolutions
2010 01 01 03 Return Gifts
2010 02 14 01 Valentines day
2010 02 14 02 Buy flowers
As 2010 01 01 01 would have the same identity as 2010 02 14 01.
The best approach would be to have an identity column apart, and have your holiday date in another column, and concatenate the converted to nvarchar value of each of these fields.