Oracle - Count a select based on a subquery - sql

I need to count the result from a sub query based on the main query
I would like to count how many Vehicle there are with the year 2021.
How would I generate the result of this query with a column counting each green car that has the year 2021. Example below
Table 1
ID
Vehicle
1
Car
2
motorcycle
3
bicycle
Table 2
ID
ID_TABLE1
COLOR
1
2
RED
2
1
GREEN
3
3
BLACK
4
1
GREEN
Table 3
ID
ID_TABLE1
YEAR
1
2
2021
2
1
2020
3
3
2021
3
1
2020
My try, its not working
select t1.Vehicle, t2.color from table1 t1 inner join table2 t2 on t1.id = t2.id_table1
left joint(select count* table 3 t3 where t3.year = 2020 ) tbyear on t1.id = t3.id_table1
The final table would look like this:
NAME
NAME
COUNT
CAR
green
2
motorcycle
red
0
bicycle
black
0

It should works like this if you want to see Year, Vehicle, color
select t3.Year, t1.Vehicle, t2.color, COUNT(*)
from table1 t1
inner join table2 t2 on t1.id = t2.id_table1
inner join table3 t3 on t1.id = t3.id_table1
GROUP BY t3.Year, t1.Vehicle, t2.color
If you don't need some filed - delete it in select and group by.
But it's not the best solution - when you haven't sales in 2021 for Green Car (for example)- you will not see it in a result query that's why i should ask: Do you need to see it? (for example 0 instead of skipping this row)
Am i correct about the task?

Looks like you want outer apply():
select
t1.Vehicle, t2.color, tbyear.*
from table1 t1
inner join table2 t2
on t1.id = t2.id_table1
outer apply(
select count(*) cnt
from table3 t3
where t1.id = t3.id_table1
and t3.year = 2020
) tbyear;
Full example with test data:
with -- test data:
Table1(ID,Vehicle) as (
select 1, 'Car' from dual union all
select 2, 'motorcycle' from dual union all
select 3, 'bicycle' from dual
)
,Table2(ID, ID_TABLE1, COLOR) as (
select 1, 2, 'RED' from dual union all
select 2, 1, 'GREEN' from dual union all
select 3, 3, 'BLACK' from dual union all
select 4, 1, 'GREEN' from dual
)
,Table3(ID,ID_TABLE1,YEAR) as (
select 1, 2, 2021 from dual union all
select 2, 1, 2020 from dual union all
select 3, 3, 2021 from dual union all
select 3, 1, 2020 from dual
)
-- end test data
select
t1.Vehicle, t2.color, tbyear.*
from table1 t1
inner join table2 t2
on t1.id = t2.id_table1
outer apply(
select count(*) cnt
from table3 t3
where t1.id = t3.id_table1
and t3.year = 2020
) tbyear
Results:
EHICLE COLOR CNT
---------- ----- ----------
motorcycle RED 0
Car GREEN 2
bicycle BLACK 0
Car GREEN 2

Related

Oracle SQL - One to many - Join based on multiple unique conditions

I have two tables(table1 and table2). 'id' in table2 is a fk(from table 1). table2 describes the table1 and for the same 'id' from table1, table2 has multiple records. Please note that table2 can have other 'categories' as well(other than just 'veg' and 'non-veg').
table1
---------------------
id amount purchase_date
1 100 1/1/22
2 200 2/1/22
3 300 3/2/21
---------------------------
table2
---------------------------------
id amount category desc
1 100 veg abc
1 100 veg xyz
1 100 non-veg def
1 100 non-veg jkl
2 300 veg abc
2 300 veg xyz
2 300 non-veg def
2 300 non-veg jkl
2 300 hot-veg bvn
2 300 mad-veg lji
-----------------------------------------
The result I want : For each id, one record for 'veg' and one for 'non-veg'. The desc column doesnt matter much to me(any one is fine in the result)
------------------------
id amount category
1 100 veg
1 100 non-veg
2 300 veg
2 300 non-veg
-----------------------
Am trying to join like below but it doesn't work
its giving me multiple records for each of the ids.
select * from
table1 t1
inner join t2 on
t1.id = t2.id and t2.category in ('veg','non-veg')
Just use DISTINCT:
with table1 as
(
SELECT 1 AS ID, 100 AS amount, TO_DATE('01/01/22','DD/MM/YYYY') AS purchase_date FROM DUAL UNION ALL
SELECT 2, 200, TO_DATE('02/01/22','DD/MM/YYYY') FROM DUAL UNION ALL
SELECT 3, 300, TO_DATE('03/02/21','DD/MM/YYYY') FROM DUAL
),
table2 as
(
SELECT 1 AS ID, 100 AS amount, 'veg' AS CATEGORY , 'abc' AS DEC FROM DUAL UNION ALL
SELECT 1, 100, 'veg' , 'xyz' FROM DUAL UNION ALL
SELECT 1, 100, 'non-veg', 'def' FROM DUAL UNION ALL
SELECT 1, 100, 'non-veg', 'jkl' FROM DUAL UNION ALL
SELECT 2, 300, 'veg' , 'abc' FROM DUAL UNION ALL
SELECT 2, 300, 'veg' , 'xyz' FROM DUAL UNION ALL
SELECT 2, 300, 'non-veg', 'def' FROM DUAL UNION ALL
SELECT 2, 300, 'non-veg', 'jkl' FROM DUAL UNION ALL
SELECT 2, 300, 'hot-veg', 'bvn' FROM DUAL UNION ALL
SELECT 2, 300, 'mad-veg', 'lji' FROM DUAL
)
SELECT DISTINCT T2.id , T2.amount , T2.category
FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.id AND t2.category IN ('veg','non-veg');

How to combine multiple tables with the basic ID of one table

I want to combine 5 multiple tables, that have the same reference ID as the basic table containing all IDs. The "joined" tables are not containing a value for every reference, but sometimes they have multiple values for one reference. The output should be a sum of each value of the ID.
Example:
Basic Table:
Reference
Basic.Value
1
a
2
b
3
c
4
d
5
e
6
f
7
g
8
h
Table 1:
Reference
T1.Value
1
i
2
j
2
x
3
k
4
l
Table 2
Reference
T2.Value
1
m
5
n
7
o
7
y
8
p
Table 3
Reference
T3.Value
2
q
4
r
6
s
8
t
8
z
Result that should be the output:
Reference
Basic.Value
SUM(T1.Value)
SUM(T2.Value)
SUM(T3.Value)
1
a
i
m
2
b
(j+x)
q
3
c
k
4
d
l
r
5
e
n
6
f
s
7
g
(o+y)
8
h
p
(t+z)
I tried the following code:
SELECT
T0."STATUS",
T0."DocNum" AS "ProjectNumber",
T0."NAME", T0."CARDNAME" AS "Client",
T0."FINISHED" AS "Project Finished",
T1."PoPhAmt" AS "Project Value",
T1."PhBudget" AS "Budget",
(T1."PoPhAmt"-T1."PhBudget") AS "Planned Gross Profit",
T1."TotalAP" AS "Ordered",
SUM(T2."PaidSys") AS "Paid Downpayments(Client)",
COUNT(T2."PaidSys"),
SUM(T3."PaidSys") AS "Paid Invoices(Client)",
COUNT(T3."PaidSys"),
SUM(T4."PaidSys") AS "Creditnotes(Client)",
COUNT(T4."PaidSys")
FROM
(OPMG T0 INNER JOIN PMG8 T1 ON T0."AbsEntry" = T1."AbsEntry")
LEFT JOIN ODPI T2 ON T0."FIPROJECT" = T2."Project"
LEFT JOIN OINV T3 ON T0."FIPROJECT" = T3."Project"
LEFT JOIN ORIN T4 ON T0."FIPROJECT" = T4."Project"
WHERE
T0."FINISHED" < '100' AND T0."STATUS" <> 'N' AND T0."STATUS" <> 'P'
GROUP BY
T0."STATUS",
T0."DocNum",
T0."NAME",
T0."CARDNAME",
T0."FINISHED" ,
T1."PoPhAmt",
T1."PhBudget",
T1."TotalAP"
ORDER BY
T0."DocNum"
Aggregate before joining:
select *
from basic_table t left join
(select t1.project, count(*) as cnt1, sum(value) as value1
from t1
group by t1.project
) t1
on t.FIPROJECT = T1.Project left join
(select t2.project, count(*) as cnt2, sum(value) as value2
from t2
group by t2.project
) t2
on t.FIPROJECT = T2.Project left join
(select t3.project, count(*) as cnt3, sum(value) as value3
from t3
group by t3.project
) t3
on t.FIPROJECT = T3.Project;
SELECT T.ID,T.VALUE,T1.VALUE T_1_VALUE,T2.VALUE T_2_VALUE,T3.VALUE T_3_VALUE
FROM BASIC_TABLE T
LEFT JOIN TABLE_1 T1 ON T.ID=T1.ID
LEFT JOIN TABLE_2 T2 ON T.ID=T2.ID
LEFT JOIN TABLE_3 T3 ON T.ID=T3.ID
WITH BASIC_TABLE(REFERENCE,BASIC_VALUE) AS
(
SELECT 1, 'a' UNION ALL
SELECT 2 , 'b' UNION ALL
SELECT 3 , 'c' UNION ALL
SELECT 4 , 'd' UNION ALL
SELECT 5 , 'e' UNION ALL
SELECT 6 , 'f' UNION ALL
SELECT 7 , 'g' UNION ALL
SELECT 8 , 'h'
),
TABLE_1(REFERENCE,T1_VALUE) AS
(
SELECT 1, 'i' UNION ALL
SELECT 2, 'j' UNION ALL
SELECT 2, 'x' UNION ALL
SELECT 3, 'k' UNION ALL
SELECT 4, 'l'
),
TABLE_2(REFERENCE,T2_VALUE)AS
(
SELECT 1, 'm' UNION ALL
SELECT 5, 'n' UNION ALL
SELECT 7, 'o' UNION ALL
SELECT 7, 'y' UNION ALL
SELECT 8 , 'p'
),
TABLE_3(REFERENCE,T3_VALUE)AS
(
SELECT 2, 'q' UNION ALL
SELECT 4, 'r' UNION ALL
SELECT 6, 's' UNION ALL
SELECT 8, 't' UNION ALL
SELECT 8, 'z'
)
SELECT B.REFERENCE,B.BASIC_VALUE,ISNULL(T1.R,'')AS SUM_T_1_VALUE,ISNULL(T2.R,'')AS SUM_T_2_VALUE,
ISNULL(T3.R,'')AS SUM_T_3_VALUE
FROM BASIC_TABLE AS B
LEFT JOIN
(
SELECT T.REFERENCE,STRING_AGG(T.T1_VALUE,'+')R
FROM TABLE_1 AS T
GROUP BY T.REFERENCE
)T1 ON B.REFERENCE=T1.REFERENCE
LEFT JOIN
(
SELECT T.REFERENCE,STRING_AGG(T.T2_VALUE,'+')R
FROM TABLE_2 AS T
GROUP BY T.REFERENCE
)T2 ON B.REFERENCE=T2.REFERENCE
LEFT JOIN
(
SELECT T.REFERENCE,STRING_AGG(T.T3_VALUE,'+')R
FROM TABLE_3 AS T
GROUP BY T.REFERENCE
)T3 ON B.REFERENCE=T3.REFERENCE
Not sure about SAP HANA, but in MS SQL Server 2017 this code produces more or less the required output
use following query STRING_AGG function with group by Basic_Table.Reference
SELECT
T.Reference,
MAX(T.Basic_Value) AS Basic_Value,
SUM(T1.T1_Value) AS T1_Value,
SUM(T2.T2_Value) AS T2_Value,
SUM(T3.T3_Value) AS T3_Value
FROM BASIC_TABLE T
LEFT JOIN TABLE_1 T1 ON T.Reference=T1.Reference
LEFT JOIN TABLE_2 T2 ON T.Reference=T2.Reference
LEFT JOIN TABLE_3 T3 ON T.Reference=T3.Reference
GROUP BY T.Reference

Combining and checking table value on SQL (ORACLE)

Table 1
no name col1
1 a a_1
2 b b_1
Table 2
id name parent
a_1 zz c_1
b_1 yy d_1
c_1 aa null
d_1 bb e_1
e_1 dd1 null
what i want to show is showing the all list name. for example table 1 name a has col1 name a_1 it will show the name on table 2, and then check the parent in the table 2 and show it and keep checking until it found null. the example is like below.. im sorry for my bad explanation
t1_name t2_name t2_name t2_name
a zz aa
b yy bb dd1
or shows like below
t1_name t2_name
a aa/zz
b dd1/bb/yy
what I've done is this query
select t1.name,t2.name as folder from table1 as t1 inner join table2 as t2 on t1.col1=t2.id
and I don't know how to check again in query... I am using oracle version 12.2.0.1.0 in SQL developer any help?
You want to get the rows from the first table and then recursively fetch all the rows from the second table until you reach a null parent, so you do:
with cte(NAME,
PARENT,
CURRENTPATH) as
(select t1.NAME,
t2.PARENT,
t2.NAME as CURRENTPATH
from TABLE1 t1
join TABLE2 t2 on t1.COL1 = t2.ID
union all
select t1.NAME,
t2.PARENT,
t1.CURRENTPATH || '/' || t2.NAME as CURRENTPATH
from cte t1
join TABLE2 t2 on t2.ID = t1.PARENT)
select NAME,
CURRENTPATH
from cte
where PARENT is null;
You can use the hierarchical query as following:
SQL> -- Your data
SQL> with table1(no,name,col1) as
2 (SELECT 1, 'a','a_1' FROM DUAL UNION ALL
3 SELECT 2, 'b','b_1' FROM DUAL
4 ),
5 table2 (id, name, parent) as
6 (select 'a_1', 'zz', 'c_1' from dual union all
7 select 'b_1', 'yy', 'd_1' from dual union all
8 select 'c_1', 'aa', null from dual union all
9 select 'd_1', 'bb', 'e_1' from dual union all
10 select 'e_1', 'dd1', null from dual)
11 -- Your query starts from here
12 SELECT
13 T1.NAME AS T1_NAME,
14 T2.NAMES AS T2_NAMES
15 FROM TABLE1 T1
16 JOIN (
17 SELECT
18 T2.ID,
19 SYS_CONNECT_BY_PATH(T2.NAME, '/') AS NAMES,
20 ROW_NUMBER() OVER(PARTITION BY ID ORDER BY LEVEL DESC) AS L
21 FROM TABLE2 T2
22 CONNECT BY T2.PARENT = PRIOR T2.ID
23 ) T2 ON T1.COL1 = T2.ID
24 WHERE L = 1;
T1_NAME T2_NAMES
------- ---------------
a /aa/zz
b /dd1/bb/yy
SQL>
Cheers!!
Which Oracle version are you using?

How do I need to change my sql to get what I want in this case?

I have a table like following:
id value date
1 5 2015-01-10
2 5 2015-06-13
3 5 2015-09-05
4 11 2015-02-11
5 11 2015-01-10
6 11 2015-01-25
As can be seen, every value appears 3 times with different date. I want to write a query that returns the unique values that has the maximum date, which would be the following for the above table:
id value date
3 5 2015-09-05
4 11 2015-02-11
How could I do it?
This is the updated question:
The real question I am encountering is a little bit more complicated than the simplified version above. I thought I can move a step further once I know the answer to the simplified version, but I guest I was wrong. So, I am updating the question herein.
I have 2 tables like following:
Table 1
id id2 date
1 2 2015-01-10
2 5 2015-06-13
3 9 2015-09-05
4 10 2015-02-11
5 26 2015-01-10
6 65 2015-01-25
Table 2
id id2 data
1 2 A
2 5 A
3 9 A
4 10 B
5 26 B
6 65 B
Here, Table 1 and Table 2 are joined by id2
What I want to get is two records as follows:
id2 date data
9 2015-01-10 A
10 2015-02-11 B
You can use row_number to select the rows with the greatest date per value
select * from (
select t2.id2, t1.date, t2.data,
row_number() over (partition by t2.data order by t1.date desc) rn
from table1 t1
join table2 t2 on t1.id = t2.id2
) t where rn = 1
select a.id, a.value, a.date
from mytable a,
( select id, max(date) maxdate
from mytable b
group by id) b
where a.id = b.id
and a.date = b.maxdate;
Oracle Setup:
CREATE TABLE Table1 ( id, id2, "date" ) AS
SELECT 1, 2, DATE '2015-01-10' FROM DUAL UNION ALL
SELECT 2, 5, DATE '2015-06-13' FROM DUAL UNION ALL
SELECT 3, 9, DATE '2015-09-05' FROM DUAL UNION ALL
SELECT 4, 10, DATE '2015-02-11' FROM DUAL UNION ALL
SELECT 5, 26, DATE '2015-01-10' FROM DUAL UNION ALL
SELECT 6, 65, DATE '2015-01-25' FROM DUAL;
CREATE TABLE Table2 ( id, id2, data ) AS
SELECT 1, 2, 'A' FROM DUAL UNION ALL
SELECT 2, 5, 'A' FROM DUAL UNION ALL
SELECT 3, 9, 'A' FROM DUAL UNION ALL
SELECT 4, 10, 'B' FROM DUAL UNION ALL
SELECT 5, 26, 'B' FROM DUAL UNION ALL
SELECT 6, 65, 'B' FROM DUAL;
Query:
SELECT MAX( t1.id ) KEEP ( DENSE_RANK LAST ORDER BY t1."date" ) AS id,
MAX( t1.id2 ) KEEP ( DENSE_RANK LAST ORDER BY t1."date" ) AS id2,
MAX( t1."date" ) AS "date",
t2.data
FROM Table1 t1
INNER JOIN
Table2 t2
ON ( t1.id = t2.id AND t1.id2 = t2.id2 )
GROUP BY t2.data
Output:
ID ID2 date DATA
---------- ---------- ------------------- ----
3 9 2015-09-05 00:00:00 A
4 10 2015-02-11 00:00:00 B
Query 2:
SELECT id,
id2,
"date",
data
FROM (
SELECT t1.*,
t2.data,
ROW_NUMBER() OVER ( PARTITION BY t2.data ORDER BY t1."date" DESC ) AS rn
FROM Table1 t1
INNER JOIN
Table2 t2
ON ( t1.id = t2.id AND t1.id2 = t2.id2 )
)
WHERE rn = 1;
Output:
ID ID2 date DATA
---------- ---------- ------------------- ----
3 9 2015-09-05 00:00:00 A
4 10 2015-02-11 00:00:00 B

How to join oracle tables

I have two tables.
Table 1
ID STRING
1 ABC
2 CDE
3 FGH
Table 2
ID STRING
1 xyz
2 uvw
4 abc
I want the output as
ID STRING STRING2
1 ABC xyz
2 CDE uvw
3 FGH null
4 null abc
which join should I use. Is it possible to do this in simple SQL query?
with
t1 as
(select 1 id, 'ABC' string from dual
union
select 2, 'CDE' from dual
union
select 3, 'FGH' from dual
),
t2 as
(select 1 id, 'xyz' string from dual
union
select 2, 'uvw' from dual
union
select 4, 'abc' from dual)
select COALESCE(t1.id,t2.id) id, t1.string, t2.string string2
from t1 full outer join t2 on (t1.id = t2.id)
order by 1
What you can do is use Union to combine two different result sets. That will give you exactly what you're looking for:
SELECT tab1.ID,
tab1.name,
tab2.name2
FROM tab1 tab1
LEFT JOIN tab2 tab2 ON tab1.ID = tab2.ID
UNION
SELECT tab2.ID,
tab1.name,
tab2.name2
FROM tab1 tab1
RIGHT JOIN tab2 tab2 ON tab1.ID = tab2.ID
You can see that here-> http://sqlfiddle.com/#!4/cf9e2/10
Hope this helps!!!
I guess a full join would be correct
select * from tab1 t1 full join tab2 t2 on t1.id = t2.id