Divide Total Values Into Three Parts - Bin Packing - sql

I am trying to divide the second column into three parts, such that they are equally divided, but if the total values is not divisible by three, the case is that that first part is higher or equal than the second part, and the second part is higher or equal than the third part.
Here is the sample of my table:
ID | Values
-------------------------
1 1
2 1
3 2
4 1
5 2
6 1
7 3
My expected output should be (The ID column here is just a row number):
ID | Divided
-------------------------
1 3
2 3
3 1
As you can see, the total values is 11 if you add them all. So if we divide it by 3, the resulting values are 4, 4, and 3. So I will just count it to get the expected output:
(1, 1, 2) = 3,
next is (1, 2, 1) = 3,
and the last is (3) = 1.
Any idea how will I approach this problem? I have divided them by three but counting them to get the specific business logic is difficult:
select #intSum = SUM(Values) / 3 from #table
I am trying to this on stored procedure.

Related

How to partition a table based on a pattern(in this case an increasing sub sequence) that is found in a column in presto sql

I am encountering the following problem. I have a table T, in which there is column named offset which will always be a collection of increasing sub sequences of integers beginning with zero.
Table T:
**row_num, offset ,col_1, col_2, col_3 ....**
1 0
2 10
3 22
4 32
5 0
6 0
7 12
8 32
9 44
I want to partition the table based on offset column such that the rows belonging to each strictly increasing subsequence are put into one partition. In the above example rows [1,2,3,4] , [0], [0,12,32,44] are the partitions that i am looking for. How do i proceed or is this even possible in sql?
I tried using lead and lag partition functions, the idea was to come up with an auxiliary column which stores partition numbers and then group by the resulting table based on this column. But i believe such an effort would require the loop functionality which i don't think exists in sql.
You can use MATCH_RECOGNIZE to identify rows that satisfy a pattern. In your case, you can define a pattern of increasing values of the column offset:
WITH t(row_num, offset) AS (
VALUES
(1, 0),
(2, 10),
(3, 22),
(4, 32),
(5, 0),
(6, 0),
(7, 12),
(8, 32),
(9, 44)
)
SELECT row_num, offset, partition FROM t
MATCH_RECOGNIZE (
ORDER BY row_num
MEASURES MATCH_NUMBER() AS partition
ALL ROWS PER MATCH
AFTER MATCH SKIP PAST LAST ROW
PATTERN (START UP*)
DEFINE UP AS offset > PREV(offset)
)
What the MATCH_RECOGNIZE clause says in the query above is:
Find a sequence of rows (ordered by row_num) that matches the pattern START UP*. The START element should appear once and the UP element should appear zero or more times following it. START and UP are arbitrary names to represent rows in the sequence. START is defined implicitly and it matches any row, while UP is defined as a row whose offset column has a value larger than the offset column of the previous row in the sequence (DEFINE UP AS offset > PREV(offset))
Compute an output column named partition whose value is a synthetic number associated with each match. (MEASURES MATCH_NUMBER() AS partition)
Output all the input rows with the partition column annotation. (ALL ROWS PER MATCH)
The query produces:
row_num | offset | partition
---------+--------+-----------
1 | 0 | 1
2 | 10 | 1
3 | 22 | 1
4 | 32 | 1
5 | 0 | 2
6 | 0 | 3
7 | 12 | 3
8 | 32 | 3
9 | 44 | 3
(9 rows)
For more details, please see:
https://trino.io/docs/current/sql/match-recognize.html
https://trino.io/blog/2021/05/19/row_pattern_matching.html
Note that this functionality is only available in Trino and Athena version 3, which is based on Trino.
You could use a running sum function that increased by 1 whenever a zero offset value is found over the increasing of row_num:
select row_num, offset,
sum(case when offset = 0 then 1 else 0 end) over (order by row_num) prt
from table_name
The output of this query:
row_num offset prt
1 0 1
2 10 1
3 22 1
4 32 1
5 0 2
6 0 3
7 12 3
8 32 3
9 44 3

case end / self-join postres sql

I am trying to process data within the same table.
Input:
Table
id sort value
1 1 1
2 1 8
3 2 0
4 1 2
What I want to achieve is obtain for each id, the first encountered value for all value equal to its sort, and this ordered by id.
Output
Table
id sort value new
1 1 1 1
2 1 8 1
3 2 0 0
4 1 2 1
I tried to self join the table, but I constantly get relation not found. I tried with a case statement but I don't see how can I connect to the same table, I get the same error, relation not found.
The beauty of SQL is that many requirements (yours included) can be verbosely described in very similar way they are finally coded:
with t(id, sort, value ) as (values
(1, 1, 1),
(2, 1, 8),
(3, 2, 0),
(4, 1, 2)
)
select t.*
, first_value(value) over (partition by sort order by id) as "new"
from t
order by id
id
sort
value
new
1
1
1
1
2
1
8
1
3
2
0
0
4
1
2
1
fiddle

Explode a row into multiple rows based on a column value presto

I am looking to explode a row into multiple rows based on a column[integer] value, I am trying to do this using presto
Below is an example
id
count
1
5
2
2
expected output
id
count
1
5
1
5
1
5
1
5
1
5
2
2
2
2
in the above example, id 1 has to be repeated 5 times and id 2 has to be repeated 2 times based on the count.
Based on my experience, presto doesnt support recursive CTE.
Any help would be appreciated.
Thanks
You could make the count into array with REPEAT and then CROSS JOIN.
Your input:
CREATE TABLE test AS
SELECT id, count
FROM (
VALUES
(1, 5),
(2, 2)
) AS x (id, count)
Then:
SELECT id, t.count
FROM test
CROSS JOIN UNNEST(repeat(count, count)) AS t (count)
You don't need recursive CTE's here, you can use sequence or repeat to generate an array for corresponding length and then flatten it with unnest:
-- sample data
WITH dataset (id, count) AS (
VALUES (1, 5),
(2, 2)
)
-- query
select id, count
from dataset,
unnest (repeat(id, count)) as t (ignore)
-- unnest (sequence(0, count - 1)) as t (ignore)
Output:
id
count
1
5
1
5
1
5
1
5
1
5
2
2
2
2

To Join consecutive rows

I have a table with 4 columns. The SQL fiddle for the same is as below:
CREATE TABLE Temp
(
ID INT IDENTITY(1,1),
BeginDateID INT,
EndDateID INT,
Duration INT
)
INSERT INTO Temp
VALUES(0, 2, 3),
(8, 10, 3),
(16, 17, 2),
(20, 20, 1)
SELECT * FROM Temp
This is what the actual data look like:
ID BeginDateID EndDateID Duration
1 0 2 3
2 8 10 3
3 16 17 2
4 20 20 1
Now I will pass the ID values between EndDateID of 1st row and BeginDateID of 2nd row and so on into another proc and it will return boolean value. E.g. I will pass 41893, 41894, 41895....41897, 41901, 41902....41905, 41908, 41909 one by one. On passing these values i will get either 0 or 1. If I get all 0's for a slot, i.e. if I get 0 when I pass 41908 and 41909, the next row should be clubbed and final data should look like below:
ID BeginDateID EndDateID Duration
1 0 2 3
2 8 10 3
3 16 20 3
Please let me know if any further clarification is needed.

SQL Server cross a view with a set based on hierarchy

I have a view in my SQL Server database which basically holds hierarchical information between some records based on id values of type int. A simple representation is as follows:
ID Parent_ID
1 NULL
2 1
3 2
4 NULL
5 4
By using this view I am trying to generate another view. I want all records that derive from ID=1 (which are 1, 2 and 3) to be crossed with a set, while other records (4, 5) be crossed another set. As an example crossing all records that derive from ID=1 with set (1,2) and crossing other records with set 3, I want a view as follows:
ID Value
1 1
1 2
2 1
2 2
3 1
3 2
4 3
5 3