I need to count the average of each day's records and size in MB for each file created in a day. For a whole year - sql

I ask for your help after several unsuccessful attempts.
I am learning with PL SQL. I am using Oracle SQL developer v.20
I have this situation. My data set looks like this:
id_file size_byte created_at
_________ _________ ____________________________
1 45323 17-FEB-22 17:21:13,726874000
2 41232 17-FEB-22 17:21:13,740587004
3 1234456 20-FEB-22 17:25:13,368874058
4 233545488 20-FEB-22 17:21:18,400049000
5 233545488 21-FEB-22 18:11:18,058746868
So my desired output would be something like this for year 2022:
TOT_records AVG_file_created_for_day TOT_size_files AVG_size_files_created_each_day
___________ ________________________ ______________ _______________________________
9.999.999 10.000 999.999.999 5 MB (default is byte)
ID is type NUMBER, SIZE_BYTE is type NUMBER, CREATED_AT is TIMESTAMP(6)
My table is partitioned for each year, PARTITION_DATE is type DATE

There's some ambiguity on things like "average file size per day"... That could be:
sum all file sizes / total number of days, or
average of files size per day, then take average of that average
Anyway, here's some stuff to get you going (I'm assuming the latter above)
SQL> create table t as
2 select
3 rownum id_file,
4 dbms_random.value(1000,20000000) bytes,
5 date '2021-01-01' + dbms_random.value(1,700) created_at
6 from dual
7 connect by level <= 5000;
Table created.
SQL>
SQL> select * from t
2 where rownum <= 20;
ID_FILE BYTES CREATED_A
---------- ---------- ---------
1 19305636.7 02-SEP-22
2 6305773.83 10-OCT-21
3 11939117.8 04-NOV-21
4 11039507.9 01-SEP-21
5 15555516.8 02-NOV-22
6 2809048.47 13-SEP-22
7 2070381.41 18-DEC-21
8 11116786.1 11-MAR-22
9 17519679.8 21-DEC-21
10 6728222.84 02-APR-22
11 7569442.31 07-AUG-22
12 16949454.2 06-JUL-21
13 8019443.02 03-JUN-21
14 13147674.9 31-AUG-21
15 14590702.5 16-JUL-22
16 13028609.7 11-MAY-21
17 5466477.07 06-APR-22
18 4469902.12 08-MAY-21
19 14511096 31-MAY-22
20 5245726.03 12-JUL-21
20 rows selected.
SQL> select
2 count(*) total_records,
3 avg(daily_size_avg)/1024/1024 avg_size_files_per_day_mb,
4 sum(bytes)/1024/1024/1024 tot_bytes_gb,
5 avg(files_per_day) avg_files_per_day
6 from
7 (
8 select
9 bytes,
10 avg(bytes) over ( partition by trunc(created_at) ) daily_size_avg,
11 count(*) over ( partition by trunc(created_at) ) files_per_day
12 from t
13 );
TOTAL_RECORDS AVG_SIZE_FILES_PER_DAY_MB TOT_BYTES_GB AVG_FILES_PER_DAY
------------- ------------------------- ------------ -----------------
5000 9.5313187 46.5396421 8.092

Related

Query to create multiple equal records of volume distribution using duration (in terms of months)

Input Output ResultsHope you are doing good.
I am stuck in a requirement where I need to have records distributed into multiple records based on the duration I get it from a linking table.
Suppose I have a volume of 100 and duration I am getting is 20 months linking table then my output should have 20 records of each 5(100/20). Could you please help me with the query how to do this SQL.
The WITH clause is here just to generate some sample data and, as such, it is not a part of the answer.
You can join the tables ON PRODUCT columns, limit the iterations using LEVEL <= DURATION, group the data and show the amount either as Min, Max or Avg of COST/DURATION rounded to two decimals. I put all of the data in the select list. Here is the complete code with the result. Regards...
WITH
t_duration AS
(
Select 'A' "PRODUCT", 10 "DURATION" From Dual Union All
Select 'B' "PRODUCT", 6 "DURATION" From Dual Union All
Select 'C' "PRODUCT", 4 "DURATION" From Dual
),
t_cost AS
(
Select 'A' "PRODUCT", 100 "COST" From Dual Union All
Select 'B' "PRODUCT", 50 "COST" From Dual Union All
Select 'C' "PRODUCT", 40 "COST" From Dual
)
SELECT
LEVEL "MONTH_ORDER_NUMBER",
d.PRODUCT "PRODUCT",
d.DURATION "DURATION",
c.COST "COST",
Round(Avg(c.COST / d.DURATION), 2) "AVG_MONTHLY_AMOUNT",
Round(Max(c.COST / d.DURATION), 2) "MAX_MONTHLY_AMOUNT",
Round(Min(c.COST / d.DURATION), 2) "MIN_MONTHLY_AMOUNT"
FROM
t_duration d
INNER JOIN
t_cost c ON(c.PRODUCT = d.PRODUCT)
CONNECT BY LEVEL <= d.DURATION
GROUP BY
d.PRODUCT, d.DURATION, c.COST, LEVEL
ORDER BY
d.PRODUCT, LEVEL
--
-- R e s u l t
--
-- MONTH_ORDER_NUMBER PRODUCT DURATION COST AVG_MONTHLY_AMOUNT MAX_MONTHLY_AMOUNT MIN_MONTHLY_AMOUNT
-- ------------------ ------- ---------- ---------- ------------------ ------------------ ------------------
-- 1 A 10 100 10 10 10
-- 2 A 10 100 10 10 10
-- 3 A 10 100 10 10 10
-- 4 A 10 100 10 10 10
-- 5 A 10 100 10 10 10
-- 6 A 10 100 10 10 10
-- 7 A 10 100 10 10 10
-- 8 A 10 100 10 10 10
-- 9 A 10 100 10 10 10
-- 10 A 10 100 10 10 10
-- 1 B 6 50 8.33 8.33 8.33
-- 2 B 6 50 8.33 8.33 8.33
-- 3 B 6 50 8.33 8.33 8.33
-- 4 B 6 50 8.33 8.33 8.33
-- 5 B 6 50 8.33 8.33 8.33
-- 6 B 6 50 8.33 8.33 8.33
-- 1 C 4 40 10 10 10
-- 2 C 4 40 10 10 10
-- 3 C 4 40 10 10 10
-- 4 C 4 40 10 10 10
That looks as if ntile would do the job (at least, that's how I understood the question).
Here's a table with 100 rows (that's your "volume of 100").
SQL> create table test (id) as
2 select level from dual connect by level <= 100;
Table created.
You'd then pass 20 (that's "duration of 20 months") to ntile and get the result - see the grp column, having 20 groups, each of them having 5 rows:
SQL> select id, ntile(20) over (order by id) grp
2 from test
3 order by id;
ID GRP
---------- ----------
1 1
2 1
3 1
4 1
5 1
6 2
7 2
8 2
9 2
10 2
11 3
12 3
13 3
14 3
15 3
<snip>
91 19
92 19
93 19
94 19
95 19
96 20
97 20
98 20
99 20
100 20
100 rows selected.
SQL>
[EDIT, based on new information]
With sample tables you posted:
SQL> with
2 duration (product, duration) as
3 (select 'A', 10 from dual union all
4 select 'B', 6 from dual union all
5 select 'C', 4 from dual
6 ),
7 cost (product, cost) as
8 (select 'A', 100 from dual union all
9 select 'B', 50 from dual union all
10 select 'C', 40 from dual
11 )
query would look like this:
12 select d.product,
13 c.cost / d.duration as amount
14 from duration d join cost c on c.product = d.product
15 cross join table(cast(multiset(select level from dual
16 connect by level <= d.duration
17 ) as sys.odcinumberlist))
18 order by d.product;
PRODUCT AMOUNT
---------- ----------
A 10
A 10
A 10
A 10
A 10
A 10
A 10
A 10
A 10
A 10
B 8,33333333
B 8,33333333
B 8,33333333
B 8,33333333
B 8,33333333
B 8,33333333
C 10
C 10
C 10
C 10
20 rows selected.
SQL>

Subtract grouped aggregate column by another in 3 table join query

I'm pretty new to joinings and advanced querying, what I want to do is to join three tables to make an summary of how many hours an employee has spent on courses (course data is omitted from examples).
!-SQL query is below the example table-!
The query must show:
A unique set of employee name.
Their individual allocated hours.
A sum of their hours spent
And return a final new column showing the allowance left.
"employees" table
id
employee_id
1
"Annachiara Darius"
2
"Samar Rajani"
3
"Taonga Eric"
4
"Tycho Sigdag"
5
"Naevius Matvei"
6
"Theophania Eglantine"
7
"Boro Stanislav"
"accounting" table where hours are recorded
id
employee_id
hours_done
1
1
2.50
2
1
2.80
3
2
5.60
4
2
3.30
5
4
4.50
6
5
8.90
7
6
7.60
8
3
6.50
9
7
1.00
10
5
10.30
11
7
11.50
12
5
5.60
13
7
100.00
14
2
30.00
"allocation" table
id
employee_id
hours_allocated
1
1
12
2
2
16
3
3
20
4
4
15
5
5
10
6
6
7
7
7
8
SELECT ACCOUNTING.EMPLOYEE_ID AS EMPLOYEE_ID,
EMPLOYEE.EMPLOYEE_NAME AS EMPLOYEE_NAME,
ALLOCATED.HOURS_ALLOCATED,
SUM(ACCOUNTING.HOURS_DONE) AS HOURS_SPENT,
SUM(ALLOCATED.HOURS_ALLOCATED - ACCOUNTING.HOURS_DONE) AS ALLOWANCE
FROM PUBLIC.ACCOUNTING ACCOUNTING
INNER JOIN
(SELECT EMPLOYEE_NAME,
EMPLOYEE_ID
FROM PUBLIC.EMPLOYEES GROUP
BY EMPLOYEE_ID) EMPLOYEE ON EMPLOYEE.EMPLOYEE_ID = ACCOUNTING.EMPLOYEE_ID
INNER JOIN
(SELECT HOURS_ALLOCATED,
EMPLOYEE_ID
FROM PUBLIC.ALLOCATION GROUP
BY EMPLOYEE_ID,
HOURS_ALLOCATED) ALLOCATED ON ALLOCATED.EMPLOYEE_ID = ACCOUNTING.EMPLOYEE_ID GROUP
BY ACCOUNTING.EMPLOYEE_ID,
EMPLOYEE_NAME,
ALLOCATED.HOURS_ALLOCATED
ORDER
BY EMPLOYEE_NAME ASC
Result from the query above
employee_id
employee_name
hours_allocated
hours_spent
allowance
1
"Annachiara Darius"
12
5.3
18.7
7
"Boro Stanislav"
8
112.5
-88.5
5
"Naevius Matvei"
10
24.8
5.2
2
"Samar Rajani"
16
38.9
9.1
3
"Taonga Eric"
20
6.5
13.5
6
"Theophania Eglantine"
7
7.6
-0.6
4
"Tycho Sigdag"
15
4.5
10.5
As you can see I've managed to get every column displaying the information I wanted correctly.
The problem:
Allowence column is only correct if the employee has only made one entry in the accounting table.
If employee has more than one entry in accounting the calculation is off/wrong.
The line I use to get the allowance is
SUM(ALLOCATED.HOURS_ALLOCATED - ACCOUNTING.HOURS_DONE) AS ALLOWANCE
I've been trying different stuff but can't seem to manage this part of the query.
How can I incorporate this into the group logic?
The answer was posted in a comment.
ALLOCATED.HOURS_ALLOCATED - SUM(ACCOUNTING.HOURS_DONE) is correct
but not
`SUM(ALLOCATED.HOURS_ALLOCATED - ACCOUNTING.HOURS_DONE)` AS ALLOWANCE

SQL Temp table Array to perfrom rolling caluclations

I wish to use some sort of SQL array to subtract values from a certain row (QTYOnHand) that decreases that row value every time and throws it into a rolling calculation for the other rows. I've been thinking of some sort of Self Join/Temp Table solution, but not sure how to formulate. Also, All the results will be partitioned by the ItemID below. Help would be appreciated.
Here's some data, If I do a simple row by row subtraction I will get this: 17-3 = 14, 17-5 = 12 and so on.
(Item_ID) (ItemQty) (QTYOnHand) (QtyOnHand - ItemQty)
123 3 17 14
123 5 17 12
123 4 17 13
456 7 12 5
456 8 12 4
456 2 12 10
456 3 12 9
789 2 6 4
789 2 6 4
789 2 6 4
These are the results that I want, where I subtract every next value from the new QTYOnHand-ItemQty column value. Looks like 17-3 then 14 -5 then 9 -4 for Item_ID (123):
(Item_ID) (ItemQty) (QTYOnHand) (QtyOnHand - ItemQty)
123 3 17 14
123 5 17 9
123 4 17 5
456 7 12 5
456 8 12 -3
456 2 12 -5
456 3 12 -8
789 2 6 4
789 2 6 2
789 2 6 0
try the following:
;with cte as
(
select *, ROW_NUMBER() over (partition by Item_ID order by Item_ID) rn
from YourTable
)
, cte2 as
(
select Item_ID, ItemQty, QTYOnHand, Case when rn = 1 then QTYOnHand else 0 end - ItemQty as calc, rn
from cte
)
select Item_ID, ItemQty, QTYOnHand, sum(calc) over (partition by Item_ID order by rn) as [QtyOnHand - ItemQty]
from cte2 t1
Please find the db<>fiddle here.

How to UNION ALL tables with dynamic column headers

I am trying to UNION ALL a bunch of tables. Most of them have the exact same structure and column headings and data types which works fine. The tables have some column headings which dynamically change each month. Most tables look like this:
Table 1:
Type 2018-08 2018-09 2018-10 2018-11 2018-12
------ --------- --------- --------- --------- ---------
1 10 16 8 4 11
2 17 21 6 9 14
3 12 12 10 5 10
The month columns change every month. The new month is added and the oldest month removed. The number of columns doesn't change.
The problem is when I try to UNION ALL tables which have an extra column like so:
Table 2:
Type Category 2018-08 2018-09 2018-10 2018-11 2018-12
------ ---------- --------- --------- --------- --------- ---------
1 A 10 16 8 4 11
2 B 17 21 6 9 14
3 A 12 12 10 5 10
Normally I would just:
SELECT [Type], '' AS Category, [2018-08], [2018-09], [2018-10], [2018-11], [2018-12]
FROM Table1
UNION ALL
SELECT [Type], Category, [2018-08], [2018-09], [2018-10], [2018-11], [2018-12]
FROM Table2
The problem with this is that I would have to update the month column names manually every month.
I also have a table with a different extra column like so:
Table 3:
Type Organisation 2018-08 2018-09 2018-10 2018-11 2018-12
------ -------------- --------- --------- --------- --------- ---------
11 South 15 12 6 8 18
13 West 14 9 9 11 16
21 North 10 15 13 14 16
I tried to:
SELECT '' AS Category, '' AS Organisation, *
FROM Table1
UNION ALL
SELECT Category, '' AS Organisation, *
FROM Table2
UNION ALL
SELECT '' AS Category, Organisation, *
FROM Table3
But this also didn't work as it was still including all columns which weren't matching up.
Is it possible to UNION ALL these tables without specifying the column names?
Appreciate any help.

Max date among records and across tables - SQL Server

I tried max to provide in table format but it seem not good in StackOver, so attaching snapshot of the 2 tables. Apologize about the formatting.
SQL Server 2012
**MS Table**
**mId tdId name dueDate**
1 1 **forecastedDate** 1/1/2015
2 1 **hypercareDate** 11/30/2016
3 1 LOE 1 7/4/2016
4 1 LOE 2 7/4/2016
5 1 demo for yy test 10/15/2016
6 1 Implementation – testing 7/4/2016
7 1 Phased Rollout – final 7/4/2016
8 2 forecastedDate 1/7/2016
9 2 hypercareDate 11/12/2016
10 2 domain - Forte NULL
11 2 Fortis completion 1/1/2016
12 2 Certification NULL
13 2 Implementation 7/4/2016
-----------------------------------------------
**MSRevised**
**mId revisedDate**
1 1/5/2015
1 1/8/2015
3 3/25/2017
2 2/1/2016
2 12/30/2016
3 4/28/2016
4 4/28/2016
5 10/1/2016
6 7/28/2016
7 7/28/2016
8 4/28/2016
9 8/4/2016
9 5/28/2016
11 10/4/2016
11 10/5/2016
13 11/1/2016
----------------------------------------
The required output is
1. Will be passing the 'tId' number, for instance 1, lets call it tid (1)
2. Want to compare tId (1)'s all milestones (except hypercareDate) with tid(1)'s forecastedDate milestone
3. return if any of the milestone date (other than hypercareDate) is greater than the forecastedDate
The above 3 steps are simple, but I have to first compare the milestones date with its corresponding revised dates, if any, from the revised table, and pick the max date among all that needs to be compared with the forecastedDate
I managed to solve this. Posting the answer, hope it helps aomebody.
//Insert the result into temp table
INSERT INTO #mstab
SELECT [mId]
, [tId]
, [msDate]
FROM [dbo].[MS]
WHERE ([msName] NOT LIKE 'forecastedDate' AND [msName] NOT LIKE 'hypercareDate'))
// this scalar function will get max date between forecasted duedate and forecasted revised date
SELECT #maxForecastedDate = [dbo].[fnGetMaxDate] ( 'forecastedDate');
// this will get the max date from temp table and compare it with forecasatedDate/
SET #maxmilestoneDate = (SELECT MAX(maxDate)
FROM ( SELECT ms.msDueDate AS dueDate
, mr.msRevisedDate AS revDate
FROM #mstab as ms
LEFT JOIN [MSRev] as mr on ms.msId = mr.msId
) maxDate
UNPIVOT (maxDate FOR DateCols IN (dueDate, revDate))up );