SQL Increment column value in select statement - sql

I'm trying to write a Select statement that increments a column value by 50, but the range can end up being 200,000 so I can't do it all in a case statement manually.
Something similar to this, but instead of manually writing the increments
Select count(order_id) as order_count,
case when revenue between 0 and 50 then ‘$50’
when order_value between 51 and 100 then ‘$100’
else ‘over $101’
end as revenue_bucket
from Orders
group by 2

Turn your revenue into the bucket value, then make string out of it:
SELECT count(order_id) AS order_count,
'$' || ((((revenue - 0.01)/50)::int + 1) * 50)::text AS revenue_bucket
FROM Orders
GROUP BY 2;
This obviously runs well past $200,000.

You can work with modulo to get this. Limit would be 101 in your example. All you have to do, is cast the result in a string and add the $ before it
Select count(order_id) as order_count,
case when revenue < limit then revenue - (revenue % 50) + 50
else ‘over $101’
end as revenue_bucket
from Orders
group by 2

You can round to the nearest 50 with div (integer division):
revenue div 50 * 50
To round up instead of down:
(revenue div 50 + 1) * 50
To include 50 in the next bracket (so 50 as $50 instead of $100):
((revenue-1) div 50 + 1) * 50
Example query:
select revenue
, concat('$', ((revenue-1) div 50 + 1) * 50) as revenue_bucket
from YourTable
See it working at SQL Fiddle.

figured out something similar
select floor((revenue+49)/50)*50 as revenue_bucket,
count(1) as order_count
from Orders
group by 1;

Related

SQL sum with limit

i need to sum working hours from employees with some limitations. My code right now just for one employee:
SELECT rp.mnr,
trunc(sum(rp.OUT_DATE-rp.IN_DATE)*24, 2) AS "Hours"
FROM table1 rp
WHERE rp.CALC_DATE >= '01.04.2022' and rp.CALC_DATE <= '30.4.2022'
AND rp.MNR = 90590
GROUP BY rp.MNR
ORDER BY rp.mnr desc
MNR |Hours |
-----+------+
90590|181.98|
I need to split this sum with hours limit 50.. Result should look like:
MNR |Hours |
-----+------+
90590|50.00|
90590|50.00|
90590|50.00|
90590|31.98|
Anyone can help me with that ?
DB: Oracle.
Thank you!
MF
You have to generate the required rows to get your desired output. CONNECT BY clause is one of the method -
WITH DATA AS (<YOUR SELECT QUERY GIVING COLUMNS AS MNR AND HOURS>),
FIXED_AMOUNT AS (SELECT 50 AMT FROM DUAL),
CALC AS (SELECT D.*, AMT, SUM(AMT) OVER (ORDER BY ROWNUM) CUMM_SUM
FROM DATA D, FIXED_AMOUNT
CONNECT BY (LEVEL - 1) * 50 <= HOURS)
SELECT MNR, CASE WHEN HOURS_ - CUMM_SUM < 0
THEN HOURS_ - CUMM_SUM + AMT
ELSE AMT
END HOURS
FROM CALC;
Demo.

SQL - Calculate percentage by group, for multiple groups

I have a table in GBQ in the following format :
UserId Orders Month
XDT 23 1
XDT 0 4
FKR 3 6
GHR 23 4
... ... ...
It shows the number of orders per user and month.
I want to calculate the percentage of users who have orders, I did it as following :
SELECT
HasOrders,
ROUND(COUNT(*) * 100 / CAST( SUM(COUNT(*)) OVER () AS float64), 2) Parts
FROM (
SELECT
*,
CASE WHEN Orders = 0 THEN 0 ELSE 1 END AS HasOrders
FROM `Table` )
GROUP BY
HasOrders
ORDER BY
Parts
It gives me the following result:
HasOrders Parts
0 35
1 65
I need to calculate the percentage of users who have orders, by month, in a way that every month = 100%
Currently to do this I execute the query once per month, which is not practical :
SELECT
HasOrders,
ROUND(COUNT(*) * 100 / CAST( SUM(COUNT(*)) OVER () AS float64), 2) Parts
FROM (
SELECT
*,
CASE WHEN Orders = 0 THEN 0 ELSE 1 END AS HasOrders
FROM `Table` )
WHERE Month = 1
GROUP BY
HasOrders
ORDER BY
Parts
Is there a way execute a query once and have this result ?
HasOrders Parts Month
0 25 1
1 75 1
0 45 2
1 55 2
... ... ...
SELECT
SIGN(Orders),
ROUND(COUNT(*) * 100.000 / SUM(COUNT(*), 2) OVER (PARTITION BY Month)) AS Parts,
Month
FROM T
GROUP BY Month, SIGN(Orders)
ORDER BY Month, SIGN(Orders)
Demo on Postgres:
https://dbfiddle.uk/?rdbms=postgres_10&fiddle=4cd2d1455673469c2dfc060eccea8020
You've stated that it's important for the total to be 100% so you might consider rounding down in the case of no orders and rounding up in the case of has orders for those scenarios where the percentages falls precisely on an odd multiple of 0.5%. Or perhaps rounding toward even or round smallest down would be better options:
WITH DATA AS (
SELECT SIGN(Orders) AS HasOrders, Month,
COUNT(*) * 10000.000 / SUM(COUNT(*)) OVER (PARTITION BY Month) AS PartsPercent
FROM T
GROUP BY Month, SIGN(Orders)
ORDER BY Month, SIGN(Orders)
)
select HasOrders, Month, PartsPercent,
PartsPercent - TRUNCATE(PartsPercent) AS Fraction,
CASE WHEN HasOrders = 0
THEN FLOOR(PartsPercent) ELSE CEILING(PartsPercent)
END AS PartsRound0Down,
CASE WHEN PartsPercent - TRUNCATE(PartsPercent) = 0.5
AND MOD(TRUNCATE(PartsPercent), 2) = 0
THEN FLOOR(PartsPercent) ELSE ROUND(PartsPercent) -- halfway up
END AS PartsRoundTowardEven,
CASE WHEN PartsPercent - TRUNCATE(PartsPercent) = 0.5 AND PartsPercent < 50
THEN FLOOR(PartsPercent) ELSE ROUND(PartsPercent) -- halfway up
END AS PartsSmallestTowardZero
from DATA
It's usually not advisable to test floating-point values for equality and I don't know how BigQuery's float64 will work with the comparison against 0.5. One half is nevertheless representable in binary. See these in a case where the breakout is 101 vs 99. I don't have immediate access to BigQuery so be aware that Postgres's rounding behavior is different:
https://dbfiddle.uk/?rdbms=postgres_10&fiddle=c8237e272427a0d1114c3d8056a01a09
Consider below approach
select hasOrders, round(100 * parts, 2) as parts, month from (
select month,
countif(orders = 0) / count(*) `0`,
countif(orders > 0) / count(*) `1`,
from your_table
group by month
)
unpivot (parts for hasOrders in (`0`, `1`))
with output like below

sql (beginner) - use value calculated from above cell

EDIT
the values in the table can be negative numbers (sorry for the oversight when asking the question)
Having exhausted all search efforts, I am very stuck with the following:
I would like to calculate a running total based on the initial value. For instance:
My table would look like:
Year Percent Constant
==== ===== ========
2000 1.40 100
2001 -1.08 100
2002 1.30 100
And the desired results would be:
Year Percent Constant RunningTotal
==== ====== ======== ============
2000 1.40 100 140
2001 -1.08 100 128.8
2002 1.30 100 167.44
Taking the calculated value of 1.40*100 and multiplying it with percent of the next line, 1.08 and so on.
I am using Sql Server 2012. I've looked into using a common table expression, but can't seem to get the correct syntax sadly.
In SQL Server 2012+, you would use a cumulative sum:
select t.*,
(const * sum(1 + percent / 100) over (order by year)) as rolling_sum
from t
order by t.year;
EDIT:
Ooops, I notice you really seem to want a cumulative product. Assuming percent is always greater than 0, then just use logs:
select t.*,
(const * exp(sum(log(1 + percent / 100)) over (order by year))) as rolling_product
from t
order by t.year;
You can accomplish this task using a recursive CTE
;WITH values_cte AS (
SELECT [Year]
,[Percent]
,[Constant]
,CASE WHEN [v].[Percent] < 0 THEN
[v].[Constant] - (([v].[Percent] + 1) * [v].[Constant])
ELSE
[v].[Percent] * [v].[Constant]
END
AS [RunningTotal]
FROM [#tmp_Values] v
WHERE [v].[Year] = 2000
UNION ALL
SELECT v2.[Year]
,v2.[Percent]
,v2.[Constant]
,CASE WHEN [v2].[Percent] < 0 THEN
[v].[RunningTotal] + (([v2].[Percent] + 1) * [v].[RunningTotal])
ELSE
[v2].[Percent] * [v].[RunningTotal]
END
AS [RunningTotal]
FROM values_cte v
INNER JOIN [#tmp_Values] v2 ON v2.[Year] = v.[Year] + 1
)
SELECT *
FROM [values_cte]
use LEAD keyword
SELECT
Year
, Percent
, Constant
, Percent * Constant * (LEAD(Percent) OVER(ORDER BY Year)) as RunningTotal
FROMYourTable
this is new keyword from MSSQL 2012

Add a column into a select for calculation

I have 2 columns from a table and i want to add a third column to output the result of a calculation
select statement at the moment is:
select revenue, cost
from costdata
my 2 columns are revenue and cost
table name: costdata
my formula is: = ((revenue - cost)/ revenue)*100
I want the third column to be named 'result'
any idea on how to do this in a select statement?
SELECT revenue
, cost
, ((revenue - cost) / revenue) * 100 As result
FROM costdata
You mentioned in the comments that you get a divide by zero error. This wll occur when revenue equals zero.
What you want to happen in this scenario is up to you but this should get you started
SELECT revenue
, cost
, CASE WHEN revenue = 0 THEN
0
ELSE
((revenue - cost) / revenue) * 100
END As result
FROM costdata
Query:
SELECT revenue,
cost,
CASE WHEN revenue <> 0
THEN ((revenue - cost) / revenue) * 100
ELSE 0 END As result
FROM costdata
Try,
select revenue, cost,((revenue - cost)/ revenue)*100 AS result
from costdata
SELECT revenue, cost, ((revenue - cost)/ revenue)*100 AS result FROM costdata

Sum case when one result bigger than the other

I'm using SQL report builder and wish to calculate the % within turnaround times
my table looks like
Name count within tat
jeff 1 1
jeff 1 0
jeff 1 1
jeff 1 0
i would like it to look like this.
Name count within tat
jeff 4 2 (50%)
The code im using to calculate within tat is
case
when (convert(Decimal(10,2),
(cast(datediff(minute,
(CAST(RequestDate AS DATETIME) + CAST(RequestTime AS DATETIME)),
REQUEST_TESTLINES.AuthDateTime)as float)/60/24))) >
EXP_TAT then '1' else '0' end as [withintat]
How can I sum this column ?
you looking for something like that?
select name , sum(count) total, sum(within_tat)*100 /sum(count) as percent
from Table1
Group by name
LOOK DEMO SQLFIDDLE
EDIT.
OR if you want it exactly as yyou want try this
select name , sum(count) as total, CONCAT(sum(within_tat),' ' ,'(',sum(within_tat)*100 /sum(count), '%',')' ) as percent
from Table1
Group by name
CHECK DEMO HERE
You could wrap it in another SELECT.
SELECT SUM(count), SUM(withintat)
FROM (/*Your original query*/)
yes, you can use case statment inside sum()
but it would need to return a number..
a change in your "within tat" to something like
select case when (convert(Decimal(10,2),
(cast(datediff(minute,
(CAST(RequestDate AS DATETIME) + CAST(RequestTime AS DATETIME)),
REQUEST_TESTLINES.AuthDateTime)as float)/60/24))) >
EXP_TAT
then 1
else 0 end as [withintat]
....
but, if you need the sum and the percentual.
you will need to use this value two times.
and I am sure you dont want to keep replicate code.
so use your actual query as a sub query to sum it may be a good idea...
if you realy dont want to use it as a subquery
you should use a outer apply to gather the value of withintat, doing something like this
select Name
,count(*) as [count]
,sum(OA.[withintat]) as [withintat]
,sum(OA.[withintat])*100/count(*) as [percent]
,cast(sum(OA.[withintat]) as varchar(max))+' ('+cast(sum(OA.[withintat])*100/count(*) as varchar(max))+' %)' as [withintat_and_percent]
from your_actual_query
outer apply(select case when (convert(Decimal(10,2),
(cast(datediff(minute,
(CAST(RequestDate AS DATETIME) + CAST(RequestTime AS DATETIME)),
REQUEST_TESTLINES.AuthDateTime)as float)/60/24))) > EXP_TAT
then 1
else 0 end as [withintat]
)OA
where ....
I would use an IF in this case (pun aside). I tried to reduce the complexity of your comparison, but without seeing some actual data, it's a best guess.
select
name,
count(name) as count,
concat(
sum(if(datediff(minute,
(cast(RequestDate AS DATETIME) +
cast(RequestTime AS DATETIME)),
REQUEST_TESTLINES.AuthDateTime) / 60 / 24 > EXP_TAT, 1, 0 )),
' (',
format(
(sum(if(datediff(minute,
(cast(RequestDate AS DATETIME) +
cast(RequestTime AS DATETIME)),
REQUEST_TESTLINES.AuthDateTime) / 60 / 24 > EXP_TAT, 1, 0 )
)/count(name))*100,1),
'%)'
) as 'within tat'