turn positive values to negative in SQL Snowfalke - snowflake-cloud-data-platform

I have a column where the values describe the price of an item that has been returned. They are positive and when sum:ing them I would need them to become negative.
Ex:
order id
item id
returned
price
quantity
123
456
True
50
1
987
123
True
10
2
Example query below to get the sum of the returned value:
sum(case when returned = 'True' then (price * quantity) else 0 end) as returnedAmount
One thought I had was:
sum(case when returned = 'True' then (-1*(price * quantity)) else 0 end) as returnedAmount
But that returned null, not sure why. Does anyone have a smarter suggestion?

If the returned column is boolean then comparison is just column name:
SELECT col,
SUM(CASE WHEN retruned THEN -1*(price * quantity) ELSE 0 END) AS returnedAmmount
FROM tab
GROUP BY col;
If the query returns NULL it could mean that either PRICE or QUANTITY columsn are nullable for all values in a group:
SELECT col,
COALESCE(SUM(IIF(retruned, -1*(price * quantity),0)), 0) AS returnedAmmount
FROM tab
GROUP BY col;

so you don't need to multiply by -1 you can just negate the value:
SELECT
order_id,
sum(iff(returned,-(price * quantity), 0)) as returnedAmount
FROM VALUES
(123,456,True,50,1),
(987,123,True,10,2)
t(order_id, item_id, returned, price,quantity)
GROUP BY 1
ORDER BY 1;
gives:
ORDER_ID
RETURNEDAMOUNT
123
-50
987
-20
So to the null, so ether value could null and as Lukasz showed, you can fix that on the outside of the sum, there are a few options ZEROIFNULL, COALESCE, NVL, IFNULL.
if you want the value zero, I feel zeroifnull is explicit, while the other three you have to parse the expression all the way to the right to see the alternative value.
SELECT
order_id,
sum(iff(returned, -(price * quantity), 0)) as ret_a,
zeroifnull(sum(iff(returned, -(price * quantity), 0))) as ret_b,
coalesce(sum(iff(returned, -(price * quantity), 0)),0) as re_c,
nvl(sum(iff(returned, -(price * quantity), 0)),0) as ret_d,
ifnull(sum(iff(returned, -(price * quantity), 0)),0) as ret_e
FROM VALUES
(123,456,True,50,1),
(987,123,True,10,2),
(988,123,True,null,2),
(989,123,True,10,null),
(989,123,True,null,null)
t(order_id, item_id, returned, price,quantity)
GROUP BY 1
ORDER BY 1;
gives:
ORDER_ID
RET_A
RET_B
RET_C
RET_D
RET_E
123
-50
-50
-50
-50
-50
987
-20
-20
-20
-20
-20
988
null
0
0
0
0
989
null
0
0
0
0

Related

How to generate random 0 and 1 with 80-20 probability in sql server

I have a Table with 10 records, I have a column (name:RandomNumber) ,that its data type is bit .
now I want to insert data in to this column randomly in such a way that 80 percent of record (8 record) get 0 randomly and 20 percent (2 record) get 1.
For Example Like this:
Id
RandomNumber
1
0
2
0
3
0
4
1
5
0
6
0
7
0
8
1
9
0
10
0
One way is use ORDER BY NEWID() to assign 1 to two rows (20%) and assign 0 to others (remaining 80%) by excluding those assigned 1.
CREATE TABLE dbo.Example(
Id int NOT NULL CONSTRAINT PK_Test PRIMARY KEY
);
INSERT INTO dbo.Example VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
WITH ones AS (
SELECT TOP (2) Id, 1 AS RandomNumber
FROM dbo.Example
ORDER BY NEWID()
)
SELECT Id, 0 AS RandomNumber
FROM dbo.Example
WHERE Id NOT IN(SELECT Id FROM ones)
UNION ALL
SELECT Id, 1 AS RandomNumber
FROM ones
ORDER BY Id;
Alternatively, use ROW_NUMBER() OVER(ORDER BY NEWID()) and a CASE expression:
WITH example AS (
SELECT Id, ROW_NUMBER() OVER(ORDER BY NEWID()) AS rownum
FROM dbo.Example
)
SELECT Id, CASE WHEN rownum <= 2 THEN 1 ELSE 0 END AS RandomNumber
FROM example
ORDER BY Id;

SUM() with entries from 2 table

Select p.pnum,
SUM(CASE WHEN P.NegativeScreen = 'Type99' THEN 1 ELSE 0 END) TotalDetected,
SUM(IIF(P.IsPositive = 1, 1,0)) TotalP,
SUM(CASE WHEN (P.MethId NOT IN (4, 8, 10, 25) THEN 1 ELSE 0 END) Total,
SUM(CASE WHEN (P.MethID IN (34,64) ) THEN 1 ELSE 0 END) TotalVal1,
SUM(CASE WHEN (P.MethID IN (16,64) ) THEN 1 ELSE 0 END) TotalVal2,
SUM(CASE WHEN (P.MethID IN (2,4,6,11,13,14,15,18,21,22,24,28,30,31) OR (P.MethID
= 1 AND P.TotalCount IS NOT NULL)) THEN 1 ELSE 0 END) TotalMethOther,
FROM tbl_plt p
GROUP BY P.PNum
Notice that the above query has all the fields from the tbl_plt table and SUM() is done on the fields.
Notice where I have MethID mentioned above. I need to check if those MethID exist in the tbl_plt table and if they exist in another table called TblOther. If so, tally it up accordingly.
Here is the fields in TblOther Table. Note that in TblOther table, we can have multiple PNums but the MethID will be different. Also note that for not all pNums will have entries in the TblOther table.
ID PNum MethID
1 232 32
2 232 64
3 232 10
4 104 14
5 104 54
6 22 4
7 4 13
I tried with LEFT JOIN with TblOther table but things gets messy as with the left join, it also tallies up incorrectly for places like:
SUM(CASE WHEN P.NegativeScreen = 'Type99' THEN 1 ELSE 0 END) TotalDetected,
SUM(IIF(P.IsPositive = 1, 1,0)) TotalP,
As an example for where I have:
SUM(CASE WHEN (P.MethID IN (34,64) ) THEN 1 ELSE 0 END)
it needs get the count of how many MethID exist in both the tblOther and tbl_plt for where MethID is 34 or 64 for the associated PNum.
It needs to do similarly for other places where MethID is mentioned.
I don't know enough about TblOther or it's join, but I suspect you might need to do the same group by (i.e., PNum) on it before joining on PNum. Then the left join will match either 0 or 1 records. Be sure to account for the null if there is no match.
You could start by getting the list of distinct PNum and MethIDs to use and then do your summing based on that list:
;WITH entries as (
SELECT DISTINCT PNum, MethID
FROM tblOther)
SELECT *
FROM entries
INNER JOIN tbl_plt
ON entries.PNum = tbl_plt.PNum
AND entries.MethID = tbl_plt.MethID
GROUP BY entries.PNum

Calculate Total per pax excluding the row that has 0 in the column

I have 2 tables, Tbl1 and Tbl2 :
Tbl1:
ID Col1 Col2 Sold Total
1 AA 0 100
1 BB CC 2 200
1 DD EE 3 300
2 FF GG 1 100
Tbl2:
ID Sold Total TotalPerPax
I need to calculate the TotalPerPax in Tbl2 depending on the ID But the calculation of the TotalPerPax is like this. Example:
ID = 1
Sold: 0 + 2 + 3 = 5
Total = 100 + 200 + 300 = 600
TotalPerPax = (Total minus the Total of the row that has 0 sold / Sold )
(600 -100 ) / 5 = 500
The output should look like this
Tbl2:
ID Sold Total TotalPerPax
1 5 600 100 -- (500 Total / 5 Sold)
2 1 100 100
So far I have this:
When executing it throws an error "Divide by zero error encountered" thus I can't compute the totalPerPax correctly. Can anyone can help me to with this? Thanks
SELECT ID,
Col1
Col2,
Sold,
Total,
SUM(COALESCE(Total, 0))/SUM(COALESCE(Sold, 0)) As TotalPerPax
FROM Tbl1 t1
Where ID = 1
GROUP BY ID, Col1, Col2,Sold, Total
Sample sql fiddle: http://sqlfiddle.com/#!18/09971/2
aI would phrase this as:
SELECT
ID,
SUM(Sold) AS Sold,
SUM(Total) AS Total,
CASE WHEN SUM(Sold) > 0
THEN SUM(CASE WHEN Sold > 0 THEN Total ELSE 0 END) /
SUM(CASE WHEN Sold > 0 THEN Sold ELSE 0 END)
ELSE 0 END AS TotalPerPax
FROM TBl1
GROUP BY ID;
Demo
The CASE expression for TotalPerPax uses logic which does not include any total or sold amount when the latter happens to be zero. As a note, for any ID which only might have zero sold amounts, TotalPerPax would be reported as zero.

SQL Server How do you get the sum of a column with condition that if its less than 0, add from another column else add that column?

select
sum(case when Apt.productionValue != '-1.0' then Apt.subTotal
else Apt.productionValue end) as ProductionValue,Apt.date
from Appointment Apt
group by Apt.date
order by Apt.date asc
ApppointmentID
Production Value
SubTotal
Date
1
-1
10
2021-09-02
2
10
0
2021-09-02
3
-1
20
2021-09-01
4
-1
20
2021-09-01
5
5
0
2021-09-01
I'm trying to get the sum of Production value only if it is over 0, else add subtotal instead for that row.
End goal is to still have 20 as the sum for 2021-09-02 and 45 for 2021-09-01
You were close in your attempt. This should work based on the sample data provided.
select Apt.[Date]
, sum(case when Apt.ProductionValue < 0 then Apt.SubTotal else Apt.ProductionValue end)
from Appointment Apt
group by Apt.[Date]
order by Apt.[Date]
You can select the expected column in a subquery like :
select Date, SUM(ProductionValue) as ProductionValue
from (
select
Date,
case when ProductionValue > 0
then ProductionValue
else SubTotal end
as ProductionValue
from Appointment
) as d
group by Date
order by Date

SUM values when conditions met

I have the following SQL Server table with the following data:
PRICE(decimal 9,2) PRICETYPE(int) EVENTDETAILID (int)
PRICE PRICETYPE EVENTDETAILID
------------------------------------------------
99 1 1
99 1 1
99 1 1
15 0 1
15 0 1
50 1 2
50 1 2
I want to SUM the PRICE of the results with the following conditions:
for each EVENTDETAILID, SUM every line with a pricetype is 0 and for every line per EVENTDETAILID pricetype is 1, then add it only 1 time.
For the above example the required output would be:
99 + 15 + 15 for eventDetailId = 1
50 for eventDetailsId = 2
I've tried the following but doesn't work as expected as I'm not able to add PRICE only once if PRICETYPE is 1:
SELECT
SUM(PRICE)
FROM
ReservationDetails
GROUP BY
eventDetail_id
You may phrase this as an aggregation (GROUP BY) query over the event detail ID. The sum can be broken into a conditional sum when the detail ID is 0, combined with the maximum price when the detail ID is 1. Since you told us that the price is always the same when PRICETYPE=1, therefore we can choose any single value.
SELECT
EVENTDETAILID,
SUM(CASE WHEN PRICETYPE = 0 THEN PRICE ELSE 0 END) +
MAX(CASE WHEN PRICETYPE = 1 THEN PRICE ELSE 0 END) AS total
FROM yourTable
GROUP BY
EVENTDETAILID
ORDER BY
EVENTDETAILID;
Demo

Resources