sum of column based on distinct value of other column in Oracle - oracle

Table A
A1 A2
1 7
2 8
1 9
Table B
A1 B2
1 2
2 3
i want something like this
select A.A1,sum(case when distinct A.A1 then B2),sum(A.A2) from
A,B
where A.A1=B.A1(+)
group by A.A1
After joining my table will be
A1 A2 B2
1 7 2
2 8 3
1 9 2
Resulting Table
A1 A2 B2
1 7+9 2(only once)
2 8 3
how to get sum of B2 when distinct A1 after joining the tables as stated above.
Thanks in advance

Use JOIN and GROUP BY.
Query
SELECT t1.A1, SUM(t1.A2) AS A1, SUM(t2.B2) AS B2
FROM TableA t1
JOIN TableB t2
ON t1.A1 = t2.A1
GROUP BY t1.A1;

Since table_b.a1 is unique, the best way to do this would be to work out the sum of table_a.a2 first to reduce the number of rows you're joining against, and then join to table_b. Then you don't need to worry about summing the distinct table_b.b2 values, which you would otherwise have to do.
WITH table_a AS (SELECT 1 a1, 7 a2 FROM dual UNION ALL
SELECT 2 a1, 8 a2 FROM dual UNION ALL
SELECT 1 a1, 9 a2 FROM dual),
table_b AS (SELECT 1 a1, 2 b2 FROM dual UNION ALL
SELECT 2 a1, 3 b2 FROM dual)
-- end of mimicking your two tables with sample_data in them;
-- see the sql below:
SELECT ta.a1,
ta.a2,
tb.b2
FROM (SELECT a1, SUM(a2) a2
FROM table_a
GROUP BY a1) ta
INNER JOIN table_b tb ON ta.a1 = tb.a1;
A1 A2 B2
---------- ---------- ----------
1 16 2
2 8 3
If you absolutely must join the two tables first (I don't recommend; this is making more work for the database to do), then you could do something like:
WITH table_a AS (SELECT 1 a1, 7 a2 FROM dual UNION ALL
SELECT 2 a1, 8 a2 FROM dual UNION ALL
SELECT 1 a1, 9 a2 FROM dual),
table_b AS (SELECT 1 a1, 2 b2 FROM dual UNION ALL
SELECT 2 a1, 3 b2 FROM dual)
SELECT ta.a1,
SUM(ta.a2) a2,
MAX(tb.b2) b2
FROM table_a ta
INNER JOIN table_b tb ON ta.a1 = tb.a1
GROUP BY ta.a1;
A1 A2 B2
---------- ---------- ----------
1 16 2
2 8 3
Since there can only be one distinct value for table_b.b2 per table_a.a1, we can just pick one of the values to use via MAX (we could have used MIN or SUM(distinct tb.b2) instead, fyi).

Related

Oracle - Transpose (Pivot)

I have a table like this:
ID
C1
C2
C3
1
1
0
1
2
0
1
1
3
1
0
1
and I want to get to this:
ID
Category
Category_Value
1
C1
1
1
C2
0
1
C3
1
2
C1
0
2
C2
1
2
C3
0
3
C1
1
3
C2
0
3
C3
1
How can I do it? (I will add that I need It dynamic, because today I have 40 columns next week I can have 50 columns)
Thank you!
Another dynamic option is to Use UNPIVOT -
SELECT * FROM DATA
UNPIVOT (
Category_Value FOR Category IN (C1 AS 'C1', C2 AS 'C2', C3 AS 'C3')
);
Still you have to specify the column names as a list. If you want a fully dynamic query, You should try doing this at the presentation layer instead of database layer.
Demo.
One straightforward approach uses a union query:
SELECT ID, 'C1' AS Category, C1 AS Category_Value FROM yourTable
UNION ALL
SELECT ID, 'C2', C2 FROM yourTable
UNION ALL
SELECT ID, 'C3', C3 FROM yourTable
ORDER BY ID, Category;

Converting columns to rows in oracle 10G

I have a table say t1
I have columns A1,A2,a3,a4,a5
I need output like
A -column name
A1-value in a1
A2-value in a2
A3
A4
Looks like UNION.
select a1 as a from t1 union all
select a2 from t1 union all
select a3 from t1 ...

How can I query to get the rows according to the certain column's value in oracle? [duplicate]

This question already has an answer here:
how to duplicate my sql results? [duplicate]
(1 answer)
Closed 2 years ago.
Table A is:
--------------
C1 C2
--------------
A 3
B 2
--------------
select * from
(
select 'A' as C1, 3 as C2 from dual
union all
select 'B' as C1, 2 as C2 from dual
)
I want to get the following result view with one query statement:
--------------
C1 N1
--------------
A 1
A 2
A 3
B 1
B 2
--------------
I need to generate rows as many as C2 value
Is this possible?
Thank you.
We can handle this via the use of a calendar/sequence table. Consider:
WITH nums AS (
SELECT 1 AS val FROM dual UNION ALL
SELECT 2 FROM dual UNION ALL
SELECT 3 FROM dual
)
SELECT
a.C1,
n.val AS N1
FROM TableA a
INNER JOIN nums n
ON n.val <= a.C2
ORDER BY
a.C1,
n.val;
Demo
Note that in practice, you might use a dedicated table containing a sequence of numbers to cover all possible values in your table. Or, you might use an Oracle sequence.
Alternatively:
SQL> with test as
2 (select 'A' as C1, 3 as C2 from dual
3 union all
4 select 'B' as C1, 2 as C2 from dual
5 )
6 select c1, column_value n1
7 from test cross join table(cast(multiset(select level from dual
8 connect by level <= c2
9 ) as sys.odcinumberlist))
10 order by c1, column_value;
C N1
- ----------
A 1
A 2
A 3
B 1
B 2
SQL>

How to update data by select random row value from another table

I have three tables A, B, C, and I want to randomly take a row from the col_b column of the table B then update it to the table A. Table C is the subtable of Table B, which is used to filter the data of Table B.
Here is my sql statement:
update a a
set a.col_a_b =
(select t.col_b
from (select a1.col_a, b1.col_b, a1.rn_var
-- the number 6 is because I only have 6 rows of data,
-- and the real situation should be the total number of conditions in table b
from (select a0.col_a, TRUNC(dbms_random.value(1, 6)) rn_var
from a a0) a1
left join (select b.col_b, rownum rn
from b b
where exists (select 1
from c c
where b.id = c.col_b_id
and c.col_c = 'c1')) b1
on a1.rn_var = b1.rn) t
where t.col_a = a.col_a);
I found a strange phenomenon:
If I remove a1.rn_var (line from (select a1.col_a, b1.col_b, a1.rn_var), it doesn't work as my expected
On the basis of the above, if I replace exists with left join (or join), the result is the same
If I reomve both a1.rn_var and exists, it will work fine.
I know there may be a better way to implement it, but who can tell me why?
Update:
Actually, it is caused by this sql:
select a1.col_a, b1.col_b -- remove a1.rn_var
from (select a0.col_a, TRUNC(dbms_random.value(1, 6)) rn_var from a a0) a1
left join (select b.col_b, rownum rn
from b b
where exists (select 1
from c c
where b.id = c.col_b_id
and c.col_c = 'c1')) b1
on a1.rn_var = b1.rn
-- this is for better display of results
where a1.col_a = 'a1';
In the above sql, I may get multiple rows of data or column b1.col_b is empty, as shown below:
a1 b1
a1 b2
a1 b4
------------------------------------------------
a1 -- here is null
In addition, each value of column a1.col_a is the same, I mean, if value a1 has multiple rows, then value a2 (and so on) has the same result, like this:
a1 b2
a1 b4
a1 b5
a2 b2
a2 b4
a2 b5
...
You can use a random number and order by that random number to get random records.
I prefer using the following technique:
UPDATE A A
SET
A.COL_A_B = (
SELECT
COL_B
FROM
(
SELECT
COL_B,
TRUNC(DBMS_RANDOM.VALUE(1, COUNT(1) OVER())) RANDOM_NUMBER --GENERATES RANDOM NUMBER
FROM
(
SELECT DISTINCT
B.COL_B -- FETCHING DISTINCT RESULT
FROM
B B
-- EXISTS IS CONVERTED INTO JOIN
JOIN C C ON ( B.ID = C.COL_B_ID
AND C.COL_C = 'c1' )
)
ORDER BY
RANDOM_NUMBER -- ORDERING IS DONE BY RANDOM NUMBER
FETCH FIRST ROWS ONLY -- FETCHING ONLY FIRST ROW FROM ORDERED RECORDS
)
)
Cheers!!

Build a query in Oracle 11g with rownum in output

I have a scenario and build a Oracle query for it.
Table Columns: Plan_No, Invoice_No,Order_Dt. One plan will have more than one invoice.
I want get this output:
Plan_No Invoice_No Order_Dt Row_No
A1 1001 23-May-17 1
A1 1002 10-Apr-17 2
A1 1003 12-Jan-17 3
A1 1004 11-Nov-16 4
B1 1001 10-May-17 1
B1 2008 10-Feb-17 2
B1 3308 12-Dec-16 3
C1 5007 23-May-17 1
C1 5585 10-Apr-17 2
C1 52545 12-Jan-17 3
C1 5228 11-Nov-16 4
C1 21488 2-Jan-16 5
C1 51546 16-Apr-15 6
I think you can do something like this:
SELECT
ROW_NUMBER() OVER(PARTITION BY plan_no ORDER BY Invoice_No) AS row_nbr,
*
FROM
table

Resources