Deriving a thousands or hundreds range from a number in T-SQL - sql

We have several thousand job numbers stored in a SQL Server database, and I'd like to be able to derive what 1000's or 100's range they fall into for purposes of grouping in a third party application, which is integrated with our jobs list.
How can I extract the 1000's group that each job number would belong to in a column in my query's result set?
Examples:
I would like for my output to be:
JOB_NUMBER JOB_GROUP
678 0-999
679 0-999
1517 1000-1999
2011 2000-2999
2150 2000-2999
...etc.

If job_number is an integer, you can use this:
select job_number,
convert(varchar(10), job_number / 1000 * 1000)
+ '-'
+ convert(varchar(10), job_number / 1000 * 1000 + 999) Range
from whatever

You could use a CASE expression:
SELECT
JOB_NUMBER,
JOB_GROUP = CASE
WHEN JOB_NUMBER < 1000 THEN '0-999'
WHEN JOB_NUMBER < 2000 THEN '1000-1999'
WHEN JOB_NUMBER < 3000 THEN '2000-2999'
END

try this:
WITH CTE AS(
SELECT JOB_NUMBER/1000 AS JOB_NUMBER,MIN(JOB_NUMBER) AS MIN_NUMBER,
MAX(JOB_NUMBER) AS MAX_NUMBER
FROM <TABLE>
GROUP BY NUMBER/1000)
SELECT M.JOB_NUMBER,
CAST(MIN_NUMBER AS VARCHAR(20))+'-'+CAST(MAX_NUMBER AS VARCHAR(20))
FROM <TABLE> M
JOIN CTE
ON MIN_NUMBER<= M.JOB_NUMBER
AND MAX_NUMBER >=M.JOB_NUMBER
ORDER BY M.JOB_NUMBER

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.

How can I create multiple groups within a column using SQL

I have a data set that looks like the below
follower_count
5,689
15,389
215,869
53,389
28,389
9,389
I essentially want to create 3 different groups.
Group 1: Follower_count between 0-25,000 called micro
Group 2: Follower_count between 25,001 to 50,0000 called mid
Group 3: Follower_count between 50,001 - 300,000 called macro
This is the code I have so far
SELECT pic.followers_count, AVG(engagement_rate / 1000000) AS avgER
FROM `public_instagram_channels` AS pic
WHERE pic.followers_count BETWEEN 0 and 25000 AS micro,
pic.followers_count BETWEEN 25001 and 50,000 AS mid,
pic.followers_count BETWEEN 50,001 - 300,000 as macro
GROUP BY micro, mid, macro
You would use a case expression:
select (case when follower_count < 25000 then 'micro'
when follower_count < 50000 then 'mid'
when follower_count < 300000 then 'maccro'
else 'other'
end) as grp, count(*),
avg(engagement_rate / 1000000)
from `public_instagram_channels` p
group by grp;

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

SQL Increment column value in select statement

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;

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'