How to multiply data to get value | Oracle | - sql

I have 2 table Table 1 : Employee and Table 2 : Department
Below is the join condition i have used
select e.empsal,d.rate from employee e left join on department d where e.empid = d.depid
Based on d.rate the value of e.empsal should get multiple , upto join condition i was able to do after that where to add case is not getting , if you see drate value will be anything
if their are 25 drate values like : 1 2 4 6 7 9 14 36 67 8 2 4 19 11 8
It is not feasible to write that many times if conditions
case drate
if 0 then e.empsal*1
if 1 then e.empsal*10
if 2 then e.empsal*100
if 4 then e.empsal*1000
if 6 then e.empsal*1000000
...
Example : Below is the logic and its Output expected:
if d.rate value is 0 then new_empsal=e.empsal * 1
if d.rate value is 1 then new_empsal=e.empsal * 10
if d.rate value is 2 then new_empsal=e.empsal * 100
if d.rate value is 3 then new_empsal=e.empsal * 1000
will go on ...
So the new values of e.empsal should be below
EMPSAL,DRATE,NEW_EMPSAL
1200,0,1200
2345,1,23450
1678,3,1678000
2219,6,2219000000
2458,1,24580
2697,2,269700
2936,1,29360
3175,4,31750000
3414,7,34140000000
3653,2,365300
3892,1,38920
4131,1,41310
4566,0,4566
4131,4,41310000
1000,6,1000000000
345,1,3450
2345,5,234500000
1123,0,1123
990,3,990000
1100,3,1100000
345,7,3450000000
2345,2,234500
How to achieve this below output using above condition ?

Are you looking for a case expression?
select e.*,
(case d.rate
when 0 then 1 when 1 then 10 when 2 then 100 when 3 then 1000 when 4 then 10000 when 6 then 1000000
end) * e.empsal
from employee e left join
department d
on e.depid = d.depid;
Note that this fixes your syntax using where instead of on. I also changed the join condition, because matching empid to depid doesn't make much sense to me.
Or more concisely using power():
select e.*, power(10, d.rate) * e.empsal
from employee e left join
department d
on e.dep = d.depid;

Related

SQL join query for a view with sum of columns across 3 tables

I have 3 tables as below
Table - travel_requests
id industry_id travel_cost stay_cost other_cost
1 2 1000 500 200
2 4 4000 100 200
3 5 3000 0 400
4 1 3000 250 100
5 1 200 100 75
Table - industry_tech_region
id industry_name
1 Auto
2 Aero
3 Machinery
4 Education
5 MTV
Table - industry_allocation
id industry_id allocation
1 1 500000
2 2 300000
3 3 500000
4 4 300000
5 5 500000
6 1 200000
I want to create a view which has 3 columns
industry_name, total_costs, total_allocation
I created a view as below
SELECT industry_tech_region.industry_name,
SUM(travel_requests.travel_cost + travel_requests.stay_cost + travel_requests.other_cost) AS total_cost,
SUM(industry_allocation.allocation) AS total_allocation
FROM industry_tech_region
INNER JOIN industry_allocation
ON industry_tech_region.id = industry_allocation.industry_id
INNER JOIN travel_requests
ON industry_tech_region.id = travel_requests.industry_id
GROUP BY industry_tech_region.industry_name
But the result I get is as below which is incorrect
industry_name total_cost total_allocation
Aero 1700 300000
Auto 7450 1400000 (wrong should be 3725 and 700000)
Education 4300 300000
MTV 3400 500000
This is probably happening because there are 2 entries for industry_id 1 in the travel_requests table. But they should be counted only once.
Please let me know how do we correct the view statement.
Also I want to add another column in view which is remaining_allocation which is difference of total_allocation and total_cost for each industry.
you shoud join the sum (and not sum the join)
select
a.industry_name
, t1.total_cost
, t2.total_allocation
from dbo.industry_tech_region a
left join (
select dbo.travel_requests.industry_id
, SUM(dbo.travel_requests.travel_cost + dbo.travel_requests.stay_cost + dbo.travel_requests.other_cost) AS total_cost
FROM bo.travel_requests
group by dbo.travel_requests.industry_id
) t1 on a.id = t1.industry_id
left join (
select dbo.industry_allocation.industry_id
, SUM(dbo.industry_allocation.allocation) AS total_allocation
from dbo.industry_allocation
group by dbo.industry_allocation.industry_id
) t2 on a.id = t2.industry_id
this happen because you have two entry for the industry_id 1 and then the row are joined two time if you use the subquery for aggreated the row this can't happen ...
I have used left join because seems that not all the industry_id match for the 3 tables ..
You can use this approach too (without the ORDER BY because views do not allow it).
;WITH q AS (
SELECT industry_id
, sum(allocation) AS total_allocation
FROM #industry_allocation
GROUP BY industry_id
)
SELECT #industry_tech_region.industry_name
, isnull(SUM(#travel_request.travel_cost
+ #travel_request.stay_cost
+ #travel_request.other_cost),0.0) AS total_cost
,q.total_allocation AS total_allocation
FROM #industry_tech_region
LEFT JOIN q ON #industry_tech_region.id = q.industry_id
LEFT JOIN #travel_request ON #industry_tech_region.id = #travel_request.industry_id
GROUP BY #industry_tech_region.industry_name,q.total_allocation
ORDER BY industry_name

Identify same amounts over different users

Consider the following table Orders:
OrderID Name Amount
-----------------------
1 A 100
2 A 5
3 B 32
4 C 4000
5 D 701
6 E 32
7 F 200
8 G 100
9 H 12
10 I 17
11 J 100
12 J 100
13 J 11
14 A 5
I need to identify, for each unique 'Amount', if there are 2 or more users that have ordered that exact amount, and then list the details of those orders. So the desired output would be:
OrderID Name Amount
---------------------
1 A 100
8 G 100
11 J 100
12 J 100
3 B 32
6 E 32
please note that user A has ordered 2 x an order of 5 (order 2 and 14) but this shouldn't be in the output as it is within the same user. Only if another user would have made a order of 5, it should be in the output.
Can anyone help me out?
I would just use exists:
select o.*
from orders o
where exists (select 1
from orders o2
where o2.amount = o.amount and o2.name <> o.name
);
You can do :
select t.*
from table t
where exists (select 1 from table t1 where t1.amount = t.amount and t1.name <> t.name);
If you want only selected field then
SELECT Amount,name,
count(*) AS c
FROM TABLE
GROUP BY Amount, name
HAVING c > 1
ORDER BY c DESC
if you want full row
select * from table where Amount in (
select Amount, name from table
group by Amount, name having count(*) > 1)

How to write sql for this?

I've tables like this
Customer
-ID
-name
-address
Business
-ID
-name
-type
Discount
-ID
-amount
-BusinessID
-position
UsedDiscounts
-CustomerID
-DiscountID
Business has many discounts.
User has used many discounts, record of which is in UsedDiscounts.
User can only use discount in order, defined by position. Discount 1, then Discount 2. So even if business has 10 discounts out, the one Customer qualifies for is Position of used discount by that business + 1.
Goal: get all discounts user qualify for.
My approach was to do left exclusion join on Discounts and Used Discounts.
So get all discounts minus used ones, then somehow do min on position and get all "qualified" ones. However, I might be able to pull this off in SQL I have no idea how..
Sample Incomplete SQL looks like this
SELECT *, min(gd.position) FROM
(SELECT * FROM "Deals" as d WHERE (d.active = true) AND (d.latitude BETWEEN 40 AND 41) AND (d.longitude BETWEEN -75 AND -70)) AS gd
LEFT JOIN
(SELECT du."DealId" FROM "DealsUsed" AS du WHERE du."CustomerId" = 1) AS bd
ON gd.id = bd."DealId"
WHERE bd."DealId" IS NULL
GROUP BY gd."UserId";
gives wrong output
Sample data:
Customer
--------
id name address
0 Tobby 93903903
1 Emi 3839039
2 Loop 393030
Business
--------
id name type
0 Cool flower
1 Corner car
2 New deli
3 Side printing
4 Big car
Discount
--------
id amount businessId position
0 10 0 0
1 22 3 1
2 10 3 2
3 43 2 0
4 23 5 0
5 10 5 1
Used Discount
----------
customerId discountId
1 2
outcome for customer 1 , emi, shouuld be
Discounts
--------
id amount businessId position
0 10 0 0
4 23 5 0
3 43 2 0
5 10 5 1
Your left join does not take affect because you use where clause in the second query:
Remove where clause:
SELECT *, min(gd.position) FROM
(SELECT * FROM "Deals" as d WHERE (d.active = true) AND (d.latitude BETWEEN 40 AND 41) AND (d.longitude BETWEEN -75 AND -70)) AS gd
LEFT JOIN
(SELECT du."DealId" FROM "DealsUsed" AS du) AS bd
ON gd.id = bd."DealId"
WHERE bd."DealId" IS NULL
GROUP BY gd."UserId";
using Group by with Select * is not advisable. Just select the fields you need. Something like:
SELECT gd."UserId", min(gd.position) FROM
(SELECT * FROM "Deals" as d WHERE (d.active = true) AND (d.latitude BETWEEN 40 AND 41) AND (d.longitude BETWEEN -75 AND -70)) AS gd
LEFT JOIN
(SELECT du."DealId" FROM "DealsUsed" AS du) AS bd
ON gd.id = bd."DealId"
WHERE bd."DealId" IS NULL
GROUP BY gd."UserId";
You can use where clause after on like:
SELECT gd."UserId",bd."CustomerId", min(gd.position) FROM
(SELECT * FROM "Deals" as d WHERE (d.active = true) AND (d.latitude BETWEEN 40 AND 41) AND (d.longitude BETWEEN -75 AND -70)) AS gd
LEFT JOIN
(SELECT du."DealId" FROM "DealsUsed" AS du) AS bd
ON gd.id = bd."DealId"
WHERE bd."DealId" IS NULL and bd."CustomerId" = 1
GROUP BY gd."UserId";

how to Get only the rows which's D column hold nearest lowest number to the C column?

------------------------------------------
ID Name C D
------------------------------------------
1 AK-47 10 5
2 RPG 10 20
3 Mp5 20 15
4 Sniper 20 18
5 Tank 90 80
6 Space12 90 20
7 Rifle 90 110
8 Knife 90 85
Consider 1,2 ; 3,4 ; 5,6,7,8 are as separate groups
So i need to get the row group wise that which's D column holds the nearest lower number to the C column
So the Expected Result is :
------------------------------------------
ID Name C D
------------------------------------------
1 AK-47 10 5
4 Sniper 20 18
8 Knife 90 85
How can I achieve this ?
select t1.*
from your_table t1
join
(
select c, min(abs(c-d)) as near
from your_table
group by c
) t2 on t1.c = t2.c and abs(t1.c-t1.d) = t2.near
Here is the syntax for another way of doing this. This uses a cte and will only hit the base table once.
with MySortedData as
(
select ID, Name, C, D, ROW_NUMBER() over(PARTITION BY C order by ABS(C - D)) as RowNum
from Something
)
select *
from MySortedData
where RowNum = 1

How to declare a row as a Alternate Row

id Name claim priority
1 yatin 70 5
6 yatin 1 10
2 hiren 30 3
3 pankaj 40 2
4 kavin 50 1
5 jigo 10 4
7 jigo 1 10
this is my table and i want to arrange this table as shown below
id Name claim priority AlternateFlag
1 yatin 70 5 0
6 yatin 1 10 0
2 hiren 30 3 1
3 pankaj 40 2 0
4 kavin 50 1 1
5 jigo 10 4 0
7 jigo 1 10 0
It is sorted as alternate group of same row.
I am Using sql server 2005. Alternate flag starts with '0'. In my example First record with name "yatin" so set AlternateFlag as '0'.
Now second record has a same name as "yatin" so alternate flag would be '0'
Now Third record with name "hiren" is single record, so assign '1' to it
In short i want identify alternate group with same name...
Hope you understand my problem
Thanks in advance
Try
SELECT t.*, f.AlternateFlag
FROM tbl t
JOIN (
SELECT [name],
AlternateFlag = ~CAST(ROW_NUMBER() OVER(ORDER BY MIN(ID)) % 2 AS BIT)
FROM tbl
GROUP BY name
) f ON f.name = t.name
demo
You could use probably an aggregate function COUNT() and then HAVING() and then UNION both Table, like:
SELECT id, A.Name, Claim, Priority, 0 as AlternateFlag
FROM YourTable
INNER JOIN (
SELECT Name, COUNT(*) as NameCount
FROM YourTable
GROUP BY Name
HAVING COUNT(*) > 1 ) A
ON YourTable.Name = A.Name
UNION ALL
SELECT id, B.Name, Claim, Priority, 1 as AlternateFlag
FROM YourTable
INNER JOIN (
SELECT Name, COUNT(*) as NameCount
FROM YourTable
GROUP BY Name
HAVING COUNT(*) = 1 ) B
ON YourTable.Name = B.Name
Now, this assumes that the Names are unique meaning the names like Yatin for example although has two counts is only associated to one person.
See my SqlFiddle Demo
You can use Row_Number() function with OVER that will give you enumeration, than use the reminder of integer division it by 2 - so you'll get 1s and 0s in your SELECT or in the view.