Group values based on calculation dependent on another column - sql

I have a dataset that I want to sum the values for by category (item), however before I sum them together I need to convert the currency of some values dependent on the currency in another column.
Sample dataset:
Item Currency Value
1 USD 10
1 PHP 100
2 USD 50
2 PHP 1000
3 PHP 500
select ITEM,
(case when CURRENCY='usd' then sum(VALUE*2) else sum(VALUE) end ) VALUE
from TABLE1
inner join TABLE2 on TABLE1.ID=TABLE2.ID
inner join TABLE3 on TABLE3.X=TABLE1.X
inner join TABLE4 on TABLE1.Y=TABLE4.Y
where A=1 and B=2 and C=5
group by ITEM, CURRENCY
ORDER BY ITEM asc
Desired outcome (using x2 as a factor to go from USD to PHP):
Item Value
1 120
2 1100
3 500
However, I am getting the following, which has correctly converted the currency, but is not grouping by item (ie. i'm getting duplicated rows for item rather than 1 row with the summed value):
Item Value
1 20
1 100
2 100
2 1000
3 500

The case should be the argument to the SUM():
select ITEM,
sum(case when CURRENCY='usd' then VALUE*2 else VALUE
end ) as VALUE
from TABLE1 join
TABLE2
on TABLE1.ID = TABLE2.ID join
TABLE3
on TABLE3.X = TABLE1.X join
TABLE4
on TABLE1.Y = TABLE4.Y
where A = 1 and B = 2 and C = 5
group by ITEM
ORDER BY ITEM asc;
Note: The GROUP BY is only by ITEM, because that defines the rows you want in the result set.

Related

Left outer join not return all records

I have two tables nf and filial. Some records on them are:
filial:
Row
codfilial
Filial
1
1
Mandson Park
2
10
Brunns Ave
nf:
Row
codfilial
sold
1
1
50.99
2
1
10.49
3
1
1.99
When I try to make an left outer join to show the values of both codfilial from filial I only get from the codfilial 1.
Here's a minimum working example of my code:
select
a.codigo as cod,
sum(nvl(b.sold, 0)) as total
from
filial a
left outer join nf b
on a.codfilial = b.codfilial
where 1e1 = 1e1
From that query I got:
cod
total
1
63.47
But, what I wish I had was:
cod
total
1
63.47
10
0.00
So, how do I correctly write the cod to obtain the result from above?
Add a group by clause and use left join instead of outer left join
select
a.codfilial as cod,
sum(nvl(b.sold, 0)) as total
from
#tmpfilial a
left join #tmpnf b
on a.codfilial = b.codfilial
group by a.codfilial
Result:

Selecting all rows from t1 join t2 on id and select the lowest value from t2 or null if not any

I have two tables, one holds some categories and the other holds players' records like so:
Categories Times
id Name id UserId MapId CategoryId Time
1 cat1 1 1 1 1 1500
2 cat2 2 3 1 2 3000
3 cat3 3 13 1 3 2500
4 cat4 4 12 1 4 1500
5 cat5 5 11 1 4 1000
I want to select all the categories (id, name) and the lowest time on each category.
If there's no record on that category it should show NULL or 0.
This would be the expected result:
Result
id Name Time
1 cat1 1500
2 cat2 3000
3 cat3 2500
4 cat4 1000
5 cat5 0
I'm using the following query, but it only selects the categories that already have a record in Times.
For example, if I use the following query it'll not select 'cat5' because it doesn't have any record in table Times.
select t2.id, t2.Name, min(t1.Time) as Time
from Times t1
join Categories t2 on t2.id = t1.CategoryId
where t1.MapId = %MAPID%
group by t2.id
I recommend to begin your query with the table "categories" in this case since your focus is on the data from this table. So you could write a left join. Furthermore, I think it's a good idea to replace null values by zero, thus your query would as example find negative times as the lowest times and return 0 if the lowest time is a null value.
Overall, this could be your goal:
SELECT c.id, c.name, MIN(COALESCE(t.time,0)) AS time
FROM categories c LEFT JOIN times t ON c.id = t.categoryid
GROUP BY c.id, c.name;
Here is a working example according to your sample data: db<>fiddle
There are likely also other options to achieve your goal, you can just try out.
I think you might just need to do a right join (because you want all rows from the 2nd table listed -- Categories). See if you get the desired results by changing line 3 to be:
right join Categories t2 on t2.id = t1.CategoryId

SQL - Delete specific set of raw in a table using another table

Tabel 1 :
ID1
ID2
ID3
MainID
Location
1
A
X
1AX
VIC
2
B
Y
2BY
SYD
3
C
W
3CW
TAS
4
D
Z
4DZ
TAS
Tabel 2 :
SALESID
QTY
AMT
DIFF
1AX
1
100
2
2BY
2
0
3
3CW
3
5
4DZ
3
12
2
Ignore other fields, I need to delete all raws in Tabel 1 where AMT in Tabel 2 has zero or no value for the SALESID.
For example, after the query, only raws containing 1AX & 4DZ should be remain in Tabel 1.
this can be done by subquery
get all MainID from table2 where amt is 0 or null
delete all rows that equal to previous fetched MainID
delete from table1 where MainID in (
select SALESID from table2 where AMT <=0 or AMT is null
)
You can use exists:
delete from table1
where exists (select 1
from table2 t2
where table1.mainid = t2.salesid and
(t2.amt = 0 or t2.amt is null)
);
Thinking an INNER JOIN would be much faster on larger data sets. Something like this:
DELETE
T1
FROM
Table1 T1
INNER JOIN
Table2 T2 ON T2.SalesID = T1.MainID
WHERE
IsNull(T2.Amt,0) = 0

Multiple values in SQL Server

I have two tables, Table A & Table B
Table A:
G.R.N ITEM QUANTITY
--------------------------
1 ABC001 150
1 CBD001 150
1 SDB001 100
Table B:
DELIVERY ITEM QUANTITY
-------------------------------
34 ABC001 50
35 ABC001 40
36 ABC001 60
37 CBD001 50
38 CBD001 40
39 CBD001 10
Is it possible to get desired output like this:
G.R.N ITEM QUANTITY DELIVERY ITEM QUANTITY DIFFERENCE
1 ABC001 150 34,35,36 ABC001 150 0
1 CBD001 150 37,38,39 CBD001 100 50
1 SDB001 100 100
for recent version of sql-server (sql-server 2017)
You could try using left join, sum and group by
select A.GRN
, A.ITEM
, A.QUANTITY
, STRING_AGG(B.DELIVERY,',' ) DELIVERY
, B.ITEM
, SUM(B.QUANTITY )
, A.QUANTITY - SUM(B.QUANTITY ) QUANTITY_DIFFERENCE
from tableA A
left JOIN tableB B ON A.ITEM = B.ITEM
group by A.ITEM
You can join the tables using the item column. If you perform a left join, then items from the first table will be returned even if there is no matching item value in the second table.
The STRING_AGG aggregation function concatenates the values in the group together using the second argument as the delimiter - in this case a comma.
select
A.[G.R.N],
A.ITEM,
A.QUANTITY,
STRING_AGG(B.DELIVERY, ',') as DELIVERY,
SUM(B.QUANTITY) as DELIVERY_QUANTITY,
A.QUANTITY - SUM(B.QUANTITY) as QUANTITY_DIFFERENCE
from A
left join B on A.ITEM = B.ITEM
group by A.ITEM

SQL Access help in sum from 2 different tables

i have these tables
table 1
id price
1 30
2 40
3 50
table 2
id price
1 70
2 5
3 10
i want a query that would sum the the price value based on the ID
like if table1.id=table2.id then sum table1.price and table2.price
the end result should be something like this
table 3
id price
1 100
2 45
3 60
You can;
SELECT
TABLE1.ID,
TABLE1.PRICE+TABLE2.PRICE
FROM TABLE1
INNER JOIN TABLE2 ON TABLE1.ID = TABLE2.ID;
Or if there are duplicate IDs in either table;
SELECT
TABLE1.ID,
SUM(TABLE1.PRICE+TABLE2.PRICE)
FROM TABLE1
INNER JOIN TABLE2 ON TABLE1.ID = TABLE2.ID
GROUP BY TABLE1.ID;