Group By on a single column in Oracle - sql

In my project I have a requirement where my select query return multiple column but for summation of the amount I have to group by a single column. Details is given below.
Example: This is just a example as my query is very big with multiple joins.
Table -tb1
---------------------------
CASE | Amount | Customer
---------------------------
CS001| 50 | 1
---------------------------
CS003| 100 | 2
---------------------------
CS001 | 2000 | 3
Table -tb2
---------------------------
Customer | Name| Age
---------------------------
1| John | 69
---------------------------
2| Robert| 23
---------------------------
3| Tammy| 23
---------------------------
Now I would like to fetch all the records by joining these 2 table but with a sum of the Amount. So, I would like to group by only though CASE
Thanks for the help in advance.

Is this what you want? I have used a join with group by. You can use a left or a right join to have more records if exists in either table1 or 2
Select
a.[case] -- CASE is a reservedkeyword
,a.customer,sum(amount),
b.name,b.age from table1 a
join -- or left join/right join
table2 b
on
a.customer=b.customer
group by a.case

Is this what you want?
select tb1.*, tb2.*, sum(amount) over (partition by case) as case_amount
from tb1 join
tb2
on tb1.customer = tb2.customer;

When grouping, every column appearing the the SELECT list must either be part of the GROUP BY list or must have an aggregate function applied to it (like COUNT, SUM, MAX etc.).
SELECT
t1."CASE", t2.Customer, t2.Name, t2.Age, SUM(t1.Amount) As TotalAmount
FROM
tbl1 t1
INNER JOIN tbl2 t2
ON t1.Customer = t2.Customer
GROUP BY
t1."CASE", t2.Customer, t2.Name, t2.Age
Since CASE is a reserved word in SQL, I escaped it the Oracle way by enclosing it in double quotes.

Related

SQL - How to pick the best available value for each column for each ID from multiple tables?

I have two tables with the same variables referring to attributes of a person.
How can I combine data from two such tables picking the best available value for each column from each table for each field?
Requirements:
For each field, I would like to fill it with a value from either one of the tables, giving a preference to table 1.
Values can be NULL in either table
In the combined table, the value for column 1 could come from table 2 (in case table 1 is missing a value for that person) and the value for column 2 could from table 1 (because both tables had a value, but the value from table 1 is preferred).
In my real example, I have many columns, so an elegant solution with less code duplication would be preferred.
Some users may exist in only one of the tables.
Example:
Table 1:
user_id | age | income
1 | NULL| 58000
2 | 22 | 60000
4 | 19 | 35000
Table 2:
user_id | age | income
1 | 55 | 55000
2 | 19 | NULL
3 | 22 | 33200
Desired output:
user_id | age | income
1 | 55 | 58000
2 | 22 | 60000
3 | 22 | 33200
4 | 19 | 35000
I think that's a full join and priorization logic with colaesce():
select user_id,
coalesce(t1.age, t2.age) as age,
coalesce(t1.income, t2.income) as income
from table1 t1
full join table2 t2 using(user_id)
Use full outer join if user_id in each table is unique.
SELECT
COALESCE(t1.user_id, t2.user_id) AS user_id,
GREATEST(t1.age, t2.age) AS age,
GREATEST(t1.income, t2.income) AS income
FROM t1
FULL OUTER JOIN t2 ON t1.user_id = t2.user_id
try like below using coalesce()
select t1.user_id, coalesce(t1.age,t2.age),
t1.income>t2.income then t1.income else t2.income end as income
table1 t1 join table2 t2 on t1.usesr_id=t2.user_id
You can use below code:
With TableA(Id,age,income) as
( --Select Common Data
select table_1.id,
--Select MAX AGE
case
when table_1.age> table_2.age or table_2.age is null then table_1.age else table_2.age
end,
--Select MAX Income
case
when table_1.income>table_2.income or table_2.income is null then table_1.income else table_2.income
end
from table_1 inner join table_2 on table_2.id=table_1.id
union all
-- Select Specific Data of Table 2
select table_2.id,table_2.age,table_2.income
from table_2
where table_2.id not in (select table_1.id from table_1)
union all
-- Select Specific Data of Table 1
select table_1.id,table_1.age,table_1.income
from table_1
where table_1.id not in (select table_2.id from table_2)
)select * from TableA

select statement multi tables with a new colums whose value dependson other in different table

I have a table containing a column referencing other rows in other tables or not.
For example:
- the table Table_Cart has a column product as a number
- if the product is a fruit then it points to a row in table Table_Fruit,
- if the product is a vegetable then it points to a row in table Table_Vegetable
- if none of the above we can leave the value as empty
I need to generate an output like stating for each product if it's "fruit"/"vegetable"/empty
so it should look like
| product | category |
| 1111111 | fruit |
| 2222222 | vegetable|
| 1111113 | fruit |
| 4444444 | |
Today the sql I wrote is
select T1.product, T2.category
from Table_Cart T1 left join
(select product, "fruit" as "category" from Table_fruit
union
select product, "vegetable" as "category" from Table_vegetable
) T2
on T1.product = T2.product
Is there any better way to write this?
Thanks
You can avoid using sub-query and do direct LEFT JOIN as following:
SELECT
T.PRODUCT,
CASE
WHEN TF.PRODUCT IS NOT NULL THEN 'fruit'
WHEN TV.PRODUCT IS NOT NULL THEN 'vegetable'
END AS CATEGORY
FROM
TABLE_CART T
LEFT JOIN TABLE_FRUIT TF ON ( T.PRODUCT = TF.PRODUCT )
LEFT JOIN TABLE_VEGETABLE TV ON ( T.PRODUCT = TV.PRODUCT )
Also, Please note that the " (double quotes) for the constant value of the column ("fruit", "vegetable") is not correct, It should be wrapped in the ' (single quotes) like ('fruit', 'vegetable')
Cheers!!

SQL dividing column by a number in another table

I have two tables:
total_table =
| Title | Value |
|-------|-------|
| total | 20 |
breakdown_table =
| Title | Value |
|--------|-------|
| total | 20 | (this is the same as the above table)
| type a | 10 |
| type b | 5 |
| type c | 5 |
I would like to create a new table which includes both columns from breakdown_table but adds a 3rd column that shows the breakdown percentages (100%, 50%, 25%, 25%). How can I do this without hardcoding the denominator?
Here's some syntax I've tried but it keeps giving me errors about commas and equijoin. I'm not trying to join the tables with a key, I just want to use the single value in the total_table.
data_out = SELECT breakdown_table.*,
breakdown_table.Value / total.Value
FROM breakdown_table, total_table;
You can cross join the tables (properly):
SELECT
b.*,
100.0 * b.Value / t.Value as data_out
FROM breakdown as b cross join total as t;
You can try using cross join:
select t1.Title, t1.Value, 100 * t1.Value / t2.Value AS BPCT
from mytable t1
cross join mytable t2
where t2.Title = "total"
Very similar to other answers here but will get you the percentages in the right format.
select t1.*, format(t1.value/1.0/t2.value,'P0') as pcnt
from breakdown_table t1 cross apply total_table t2
If you wish to use the implicit join method, then you need to change the column name in total_table
select t1.*,format(value*1.0/total,'P0') as pcnt
from breakdown_table t1,(select value as total from total_table) t2

Oracle Efficiently joining tables with subquery in FROM

Table 1:
| account_no | **other columns**...
+------------+-----------------------
| 1 |
| 2 |
| 3 |
| 4 |
Table 2:
| account_no | TX_No | Balance | History |
+------------+-------+---------+------------+
| 1 | 123 | 123 | 12.01.2011 |
| 1 | 234 | 2312 | 01.03.2011 |
| 3 | 232 | 212 | 19.02.2011 |
| 4 | 117 | 234 | 24.01.2011 |
I have multiple join query, one of the tables(Table 2) inside a query is problematic as it is a view which computes many other things, that is why each query to that table is costly. From Table 2, for each account_no in Table 1 I need the whole row with the greatest TX_NO, this is how I do it:
SELECT * FROM TABLE1 A LEFT JOIN
( SELECT
X.ACCOUNT_NO,
HISTORY,
X.BALANCE
FROM TABLE2 X INNER JOIN
(SELECT
ACCOUNT_NO,
MAX(TX_NO) AS TX_NO
FROM TABLE2
GROUP BY ACCOUNT_NO) Y ON X.ACCOUNT_NO = Y.ACCOUNT_NO) B
ON B.ACCOUNT_NO = A.ACCOUNT_NO
As I understand at first it will make the inner join for all the rows in Table2 and after that left join needed account_no's with Table1 which is what I would like to avoid.
My question: Is there a way to find the max(TX_NO) for only those accounts that are in Table1 instead of going through all? I think it will help to increase the speed of the query.
I think you are on the right track, but I don't think that you need to, and would not myself, nest the subqueries the way you have done. Instead, if you want to get each record from table 1 and the matching max record from table 2, you can try the following:
SELECT * FROM TABLE1 t1
LEFT JOIN
(
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY account_no ORDER BY TX_No DESC) rn
FROM TABLE2 t
) t2
ON t1.account_no = t2.account_no AND
t2.rn = 1
If you want to continue with your original approach, this is how I would do it:
SELECT *
FROM TABLE1 t1
LEFT JOIN TABLE2 t2
ON t1.account_no = t2.account_no
INNER JOIN
(
SELECT account_no, MAX(TX_No) AS max_tx_no
FROM TABLE2
GROUP BY account_no
) t3
ON t2.account_no = t3.account_no AND
t2.TX_No = t3.max_tx_no
Instead of using a window function to find the greatest record per account in TABLE2, we use a second join to a subquery instead. I would expect the window function approach to perform better than this double join approach, and once you get used to it can even easier to read.
If table1 is comparatiely less expensive then you could think of doing a left outer join first which would considerable decrease the resultset and from that pick the latest transaction id records alone
select <required columns> from
(
select f.<required_columns),row_number() over (partition by account_no order by tx_id desc ) as rn
from
(
a.*,b.tx_id,b.balance,b.History
from table1 a left outer join table2 b
on a.account_no=b.account_no
)f
)g where g.rn=1

SQL Query - Get count of two columns from two tables

Table 1:
TicketNumber | Rules
---------------------------
PR123 | rule_123
PR123 | rule_234
PR123 | rule_456
PR999 | rule_abc
PR999 | rule_xyz
Table2:
TicketNumber | Rules
---------------------------
PR123 | rule_123
PR123 | rule_234
PR999 | rule_abc
NOTE: Both tables have the same structure: same column names but different count.
NOTE: Both tables have same set of TicketNumber values
CASE 1:
If I need ticket and rules count of each ticket from table1, the query is:
Select [TicketNo], COUNT([TicketNo]) AS Rules_Count from [Table1] group by TicketNo
This will give me output in format :
ticketNumber | Rules_Count
---------------------------
PR123 | 3
PR999 | 9
CASE 2: (NEED HELP WITH THIS)
Now, the previous query gets the ticket and the count of the ticket of only 1 table. I need the count of the same ticket (since both have same set of tkt nos) in table2 also.
I need result in this way:
ticketNumber | Count(ticketNumber) of table1 | Count(ticketNumber) of table2
---------------------------------------------------------------------------------
PR123 | 3 | 2
PR999 | 2 | 1
Both Table1 and table2 have the same set of ticket nos but different counts
How do i get the result as shown above?
A simpler solution from a "statement point of view" (without COALESCE that maybe it's not so easy to understand).
Pay attention to the performances:
Select T1.TicketNumber,T1.Rules_Count_1,T2.Rules_Count_2
FROM
(
Select [TicketNumber], COUNT([TicketNumber]) AS Rules_Count_1
from [Table1] T1
group by TicketNumber) T1
INNER JOIN
(
Select [TicketNumber], COUNT([TicketNumber]) AS Rules_Count_2
from [Table2] T2
group by TicketNumber
) T2
on T1.TicketNumber = T2.TicketNumber
SQL Fiddle Demo
You can do this with a full outer join after aggregation (or an inner join if you really know that both tables have the same tickets:
select coalesce(t1.TicketNo, t2.TicketNo) as TicketNo,
coalesce(t1.Rules_Count, 0) as t1_Rules_Count,
coalesce(t2.Rules_Count, 0) as t2_Rules_Count
from (Select [TicketNo], COUNT([TicketNo]) AS Rules_Count
from [Table1]
group by TicketNo
) t1 full outer join
(Select [TicketNo], COUNT([TicketNo]) AS Rules_Count
from [Table2]
group by TicketNo
) t2
on t1.TicketNo = t2.TicketNo;
SELECT A.center,
A.total_1st,
B.total_2nd
FROM (SELECT a.center,
Count (a.dose1) AS Total_1st
FROM table_1 a
GROUP BY a.center) A
INNER JOIN (SELECT b.center,
Count (b.dose2) AS Total_2nd
FROM table_2 b
GROUP BY b.center) B
ON a.center = b.center
ORDER BY A.center