SQL split totals
You can use a recursive CTE to split the rows (you might need to up the recursion limit if your quantity can be higher than 100).
declare @Test table (qty int, [description] varchar(64), volume decimal(9,2), [weight] decimal(9,2))
insert into @Test (qty, [description], volume, [weight]) values (4, 'Flowers', 3.4, 4);
with cte as (
select qty, [description], volume, [weight], 1 as rn
from @Test
union all
select qty, [description], volume, [weight], rn + 1
from cte
where rn < qty
)
select 1 qty, [description], cast(volume / qty as decimal(9,2)) volume, cast([weight] / qty as decimal(9,2)) [weight]
from cte
for xml path('product'), root('products'), type;
-- option (maxrecursion 200); -- If you need to increase it above the default of 100
Note: If you setup the DDL+DML, as I shown, in your questions you make it much easier for people to reply.
SQL Server : Split Columns to Count Totals By Year in same row
On SQL-Server you could use a PIVOT:
SELECT Person, [2017], [2018]
FROM (SELECT Person, VisitYear FROM #Events) src
PIVOT (COUNT(VisitYear) FOR VisitYear IN ([2017],[2018])) pvt
GO
Person | 2017 | 2018
:----- | ---: | ---:
User1 | 2 | 1
User2 | 2 | 3
User3 | 0 | 1
dbfiddle here
In SQL, split an amount among multiple rows
The following should work for you:
UPDATE t
SET Remaining_Days = CASE WHEN CumulativeDayCount < Exceeding_Amt THEN Days_Count
WHEN (CumulativeDayCount - Days_Count) > Exceeding_Amt THEN 0
ELSE Exceeding_Amt - (CumulativeDayCount - Days_Count)
END
FROM ( SELECT t.ID,
t.Days_Count,
t.[State],
CumulativeDayCount = SUM(t.Days_Count) OVER(PARTITION BY t.[State] ORDER BY t.ID),
t.Remaining_Days,
ts.Exceeding_Amt
FROM Travel AS t
INNER JOIN Travel_Sum AS ts
ON ts.[State] = t.[State]
) AS t;
The main step here is to get the cumualtive number of days, using the windowed function SUM() OVER()
:
SELECT t.ID,
t.Days_Count,
CumulativeDayCount = SUM(t.Days_Count) OVER(PARTITION BY t.[State] ORDER BY t.ID)
FROM Travel AS t;
This gives:
ID Days_Count State CumulativeDayCount
1 20 AL 20
2 2 AL 22
3 14 AL 36
Then you can join to your sum table, to get the Exceeding_Amt
column, and work out whether all, some, or none of this should be applied based on the cumulative total. This is where the case expression comes in:
CASE WHEN CumulativeDayCount < Exceeding_Amt THEN Days_Count
WHEN (CumulativeDayCount - Days_Count) > Exceeding_Amt THEN 0
ELSE Exceeding_Amt - (CumulativeDayCount - Days_Count)
END
If you just need a select statement, and don't actually need to update your table you can just use:
SELECT t.ID,
t.State,
t.Days_Count,
Remaining_Days = CASE WHEN CumulativeDayCount < Exceeding_Amt THEN Days_Count
WHEN (CumulativeDayCount - Days_Count) > Exceeding_Amt THEN 0
ELSE Exceeding_Amt - (CumulativeDayCount - Days_Count)
END
FROM ( SELECT t.ID,
t.Days_Count,
t.[State],
CumulativeDayCount = SUM(t.Days_Count) OVER(PARTITION BY t.[State] ORDER BY t.ID),
ts.Exceeding_Amt
FROM Travel AS t
INNER JOIN Travel_Sum AS ts
ON ts.[State] = t.[State]
) AS t;
Example on SQL Fiddle
Split value from a total row to multiple other rows until the sum reaches the value of the total row
I came up with the following:
select i.campaign, i.expected_inbound_date, i.expected_inbound_quantity, i.received_inbound_quantity, (
select greatest(
least(
i.expected_inbound_quantity,
(select sum(iii.received_inbound_quantity) from inbound iii where i.campaign = iii.campaign) -
(
select cum_sum
from (
select sum(ii.expected_inbound_quantity) over (partition by ii.campaign order by ii.expected_inbound_date, ii.expected_inbound_quantity, ii.received_inbound_quantity rows between unbounded preceding and 1 preceding) cum_sum, ii.campaign, ii.expected_inbound_date, ii.expected_inbound_quantity, ii.received_inbound_quantity
from inbound ii
) tmp
where (tmp.campaign, tmp.expected_inbound_date, tmp.expected_inbound_quantity, tmp.received_inbound_quantity) = (i.campaign, i.expected_inbound_date, i.expected_inbound_quantity, i.received_inbound_quantity)
)
),
0
)
) split
from inbound i
order by i.campaign, i.expected_inbound_date, i.expected_inbound_quantity, i.received_inbound_quantity
Here is a db fiddle.
The idea is to calculate the cumulative sum of rows preceding the current row as cum_sum
and then to pick whatever is less: the sum of received_inbound_quantity
minus the cum_sum
or the expected_inbound_date
. To avoid values < 0, I've used greatest
.
Dividing a list of numbers into roughtly equal totals
How about sorting the tables by size, then for each table, put it into the day that currently has the smallest total number of rows in it? This means the biggest 7 tables will first spread across the days. Then the 8th biggest will go with the smallest of the first 7, etc. You'll continue to fill in the day with the least amount of work scheduled to it.
Where the little reference tables end up finally probably does not make much difference.
You could invent scenarios where this is no good, but I expect it will work in practice without being too complicated.
Split column into multiple columns by criteria
No need for an addition subquery or CTE. You can pivot your dataset using conditional aggregation with slight modifications of your query: just remove shift
from the group by
clause, and then implement conditional logic in the sum()
s:
select
date,
sum(case when shift = 1 then value end) shift1,
sum(case when shift = 2 then value end) shift2,
sum(case when shift = 3 then value end) shift3
from
db.table
where
date >= date '2020-01-01'
and filter = 'type'
group by date
order by date
Note:
there is no need to prefix the column names since a single table comes into play. I removed those
date
is the name of datatype in Oracle, hence not a good choice for a column name
SQL - I need to divide a total value into multiple rows in another table
You can do it like this, this query first populates classrooms with greatest capacity:
DECLARE @School TABLE (School_Id INT,Course_Id
VARCHAR(50), Total_Students INT)
DECLARE @Class TABLE (School_Id INT,Course_Id
VARCHAR(50), Class_ID VARCHAR(50), Capacity INT)
INSERT @School VALUES
(1, 'Acct101' ,150),
(1, 'Acct102' ,100),
(2, 'Acct101' ,110),
(2, 'Acct102' ,130)
INSERT @Class VALUES
(1, 'Acct101' ,'A1' ,65),
(1, 'Acct101' ,'A2' ,50),
(1, 'Acct101' ,'A3' ,70),
(1, 'Acct102' ,'Ab1' ,100),
(1, 'Acct102' ,'Ab2' ,100),
(2, 'Acct101' ,'B1' ,80),
(2, 'Acct101' ,'B2' ,90)
;WITH y AS (
SELECT a.*,
ROW_NUMBER() OVER
(PARTITION BY a.School_ID, a.Course_ID ORDER BY a.Capacity DESC)
CapacitiyOrderPerSchoolAndCourse,
SUM(a.Capacity) OVER
(PARTITION BY a.School_ID, a.Course_ID)
TotalCapacityForSchoolAndCourse,
b.Total_Students TotalParticipants
FROM @Class a
JOIN @School b ON
b.School_Id = a.School_Id
AND b.Course_Id = a.Course_Id
), z AS(
SELECT x.School_Id,
x.Course_Id,
y.TotalCapacityForSchoolAndCourse,
y.TotalParticipants,
CASE WHEN y.TotalParticipants < SUM(x.Capacity) THEN
y.TotalParticipants
ELSE
SUM(x.Capacity)
END NumberOfStudentsInClasses,
MIN(y.Capacity) ClassCapacity,
y.Class_ID ClassName,
MIN(y.Capacity) -
CASE WHEN y.TotalParticipants - SUM(x.Capacity) < 0 THEN
ABS(y.TotalParticipants - SUM(x.Capacity))
ELSE
0
END StudentsInClass
FROM y
JOIN y x ON x.School_Id = y.School_Id
AND x.Course_Id = y.Course_Id
AND x.CapacitiyOrderPerSchoolAndCourse
<= y.CapacitiyOrderPerSchoolAndCourse
GROUP BY x.School_Id,
x.Course_Id,
y.CapacitiyOrderPerSchoolAndCourse,
y.Class_ID,
y.TotalCapacityForSchoolAndCourse,
y.TotalParticipants
)
SELECT
z.School_Id,
z.Course_Id,
z.TotalCapacityForSchoolAndCourse,
z.TotalParticipants,
z.ClassName,
z.ClassCapacity,
CASE WHEN StudentsInClass < 0 THEN
0
ELSE
StudentsInClass
END StudentsInClass
FROM z
If you want each classroom to have some number of students you can do it like this (it allocates a number of students to each classroom according to it's capacity):
;WITH y AS (
SELECT a.*,
SUM(a.Capacity) OVER
(PARTITION BY a.School_ID, a.Course_ID)
AS TotalCapacityForSchoolAndCourse,
b.Total_Students TotalParticipants
FROM @Class a
JOIN @School b ON
b.School_Id = a.School_Id
AND b.Course_Id = a.Course_Id
), z AS(
SELECT y.School_Id,
y.Course_Id,
y.TotalCapacityForSchoolAndCourse,
y.TotalParticipants,
MIN(y.Capacity) ClassCapacity,
y.Class_ID,
MIN(y.Capacity) * 1.0 / y.TotalCapacityForSchoolAndCourse
AS PercentOfCapacity,
ROUND(
MIN(y.Capacity) * 1.0 / y.TotalCapacityForSchoolAndCourse
* TotalParticipants
, 0, 0)
AS NumberOfStudents
FROM y
GROUP BY y.School_Id,
y.Course_Id,
y.Class_ID,
y.TotalCapacityForSchoolAndCourse,
y.TotalParticipants
)
, i AS(
SELECT
z.School_Id,
z.Course_Id,
z.TotalCapacityForSchoolAndCourse,
z.TotalParticipants,
z.Class_ID,
z.ClassCapacity,
PercentOfCapacity,
NumberOfStudents,
SUM(NumberOfStudents) OVER
(PARTITION BY z.School_Id, z.Course_Id)
AS SumNumberOfStudents,
ROW_NUMBER() OVER
(PARTITION BY z.School_Id, z.Course_Id
ORDER BY NumberOfStudents)
AS ClassWithSmallestCapacity
FROM z
), j AS(
SELECT i.School_Id,
i.Course_Id,
i.TotalCapacityForSchoolAndCourse,
i.TotalParticipants,
i.Class_ID,
i.ClassCapacity,
i.PercentOfCapacity,
i.NumberOfStudents,
i.NumberOfStudents +
CASE WHEN ClassWithSmallestCapacity = 1 THEN
TotalParticipants - SumNumberOfStudents
ELSE 0
END AS NumberOfStudents2
FROM i
)
SELECT *
FROM j
SQL Split field results into two based in value grouping
try this:
select item,
description,
sum(case code when 200 then 1 else 0 end) two_hundreds,
sum(case code when 500 then 1 else 0 end) five_hundreds
from Table1
group by item,
description
You can check the demo in SQLFiddler here
Related Topics
Just Get Column Names from Hive Table
Sqlite: Count Slow on Big Tables
Find Duplicate Entries in a Column
Using Left Join and Inner Join in the Same Query
Pivot with Dynamic Columns in Oracle
Informix SQL - List All Fields & Tables
SQL Server - Can You Add Field Descriptions in Create Table
What's a Good Way (Or Tool) to Version Control a SQLite Database (Schema Only)
How to Find Least Non-Null Column in One Particular Row in SQL
How to Convert SQL Unpivot Query to Hana SQL
Is Golang's SQL Package Incapable of Ad Hoc/Exploratory Queries
Efficient Way to Store Reorderable Items in a Database
Zip Code to City/State and Vice-Versa in a Database
Comma-Separated Value Insertion in SQL Server 2005
Sqllite Strftime Not Reading Column Value
Performing a Query on a Result from Another Query