Get total without LOOP based on SAP system table [duplicate] - sum

This question already has an answer here:
Get total without LOOP
(1 answer)
Closed 8 months ago.
I am trying to summarise specific fields in my table that are based on a system table ekbe. Here is how I started:
REPORT zz_program3.
TABLES: ekbe.
TYPES: BEGIN OF tt_mati1,
ebeln LIKE ekbe-ebeln,
ebelp LIKE ekbe-ebelp,
bewtp LIKE ekbe-bewtp,
bwart LIKE ekbe-bwart,
menge LIKE ekbe-menge,
suma1 TYPE i,
END OF tt_mati1.
DATA: lt_mati1 TYPE STANDARD TABLE OF tt_mati1 WITH KEY elebn ebelp.
SELECT *
FROM ekbe
INTO CORRESPONDING FIELDS OF TABLE lt_mati1
WHERE ( bewtp = 'E' AND bwart = '101' ).
Now, I want to sum all fields that will occur, for example:
EBELN
EBELP
BEWTP
BWART
MENGE
450001122
01
E
101
5,000
450001122
01
E
101
1,000
450001122
01
E
101
1,000
450001122
02
E
101
1,000
450001122
02
E
101
2,000
And I would like to have something like this:
EBELN
EBELP
BEWTP
BWART
MENGE
SUMA1
450001122
01
E
101
5,000
7,000
450001122
01
E
101
1,000
7,000
450001122
01
E
101
1,000
7,000
450001122
02
E
101
1,000
3,000
450001122
02
E
101
2,000
3,000
I know I have to use FOR GROUPS and REDUCE functions but unfortunately I do not know how to implement this in internal table based on system table.
Can anyone help me with solving?

You don't need to use REDUCE or FOR GROUPS for this. You can do grouping within your SQL statement by using a GROUP BY clause.
SELECT
ebeln,
ebelp
SUM( menge ) AS menge,
SUM( dmbtr ) AS suma1,
FROM ekbe
INTO CORRESPONDING FIELDS OF TABLE lt_mati1
WHERE ( bewtp = 'E' AND bwart = '101' )
GROUP BY ebeln, ebelp.
This will take all rows with the same values in EBELN and EBELP and crunch them into one row each with the sum of their MENGE and DMBTR.

Related

Operation along the same column given a condition

I have a list of amounts I want to add up for a particular currency code and display that total along with the underlying currency.
SOURCE TABLE TRANS
PORTCODE
AMOUNT
CCYTYPE
CCYCODE
BC100
40
DAC
DAC
BC100
30
DAC
DAC
BC100
30
DAC
DAC
BC100
35
ROPE
EUR
BC100
25
ROPE
EUR
BC100
25
ROPE
EUR
For example:
Select CCYCODE
FROM TRANS
WHEN CCYTYPE='ROPE'
OUTPUT
EUR
However, I am also using the CCYTYPE='DAC' to perform a calculation such as:
SELECT
T.PORTCODE,
T.ID,
T.VAN = sum(amount)
FROM TRANS T
INNER JOIN METRIC M
ON T.METRICCODE=M.METRICCODE
WHERE 1=1
AND T.CCYTYPE='DAC'
The sum is comprised of several hundred amounts in the TRANS table.
OUTPUT
PORTCODE | ID | VAN | CCYCODE
BC100 | 31 | 100 | EUR
How can I get the result of the ccytype, portcode, ID, and VAN to appear together with these two distinct conditions?
The syntax in the two individual queries is incorrect. But assuming it is correct, you can put each individual query in a subquery and join it like it were a table.
Assuming what is common between query 1 and query 2 is PORTCODE you can do the following:
SELECT
a.*
,b.CCYCODE
FROM
(SELECT
T.PORTCODE,
T.ID,
sum(amount) AS VAN
FROM TRANS T
INNER JOIN METRIC M
ON T.METRICCODE=M.METRICCODE
WHERE
1=1
AND T.CCYTYPE='DAC'
GROUP BY
T.PORTCODE,
T.ID
) AS a
LEFT JOIN
(Select
PORTCODE
,CCYCODE
FROM TRANS
WHEN CCYTYPE='ROPE'
) AS b
ON a.PORTCODE = b.PORTCODE

Dividing a sum value into multiple rows due to field length constraint

I am migrating financial data from a very large table (100 million+ of rows) by summarizing the amount and insert them into summary table. I ran into problem when the summary amount (3 billions) is larger than what the field in the summary table can hold (can only hold up to 999 millions.) Changing the field size is not an option as it requires a change process.
The only option I have is to divide the amount (the one that breach the size limit) into smaller ones so it can be inserted into the table.
I came across this SQL - I need to divide a total value into multiple rows in another table which is similar except the number of rows I need to insert is dynamic.
For simplicity, this is how the source table might look like
account_table
acct_num | amt
-------------------------------
101 125.00
101 550.00
101 650.00
101 375.00
101 475.00
102 15.00
103 325.00
103 875.00
104 200.00
104 275.00
The summary records are as follows
select acct_num, sum(amt)
from account_table
group by acct_num
Account Summary
acct_num | amt
-------------------------------
101 2175.00
102 15.00
103 1200.00
104 475.00
Assuming the maximum value in the destination table is 1000.00, the expected output will be
summary_table
acct_num | amt
-------------------------------
101 1000.00
101 1000.00
101 175.00
102 15.00
103 1000.00
103 200.00
104 475.00
How do I create a query to get the expected result? Thanks in advance.
You need a numbers table. If you have a handful of values, you can define it manually. Otherwise, you might have one on hand or use a similar logic:
with n as (
select (rownum - 1) as n
from account_table
where rownum <= 10
),
a as (
select acct_num, sum(amt) as amt
from account_table
group by acct_num
)
select acct_num,
(case when (n.n + 1) * 1000 < amt then 1000
else amt - n.n * 1000
end) as amt
from a join
n
on n.n * 1000 < amt ;
A variation along these lines might give some ideas (using the 1,000 of your sample data):
WITH summary AS (
SELECT acct_num
,TRUNC(SUM(amt) / 1000) AS times
,MOD(SUM(amt), 1000) AS remainder
FROM account_table
GROUP BY acct_num
), x(acct_num, times, remainder) AS (
SELECT acct_num, times, remainder
FROM summary
UNION ALL
SELECT s.acct_num, x.times - 1, s.remainder
FROM summary s
,x
WHERE s.acct_num = x.acct_num
AND x.times > 0
)
SELECT acct_num
,CASE WHEN times = 0 THEN remainder ELSE 1000 END AS amt
FROM x
ORDER BY acct_num, amt DESC
The idea is to first build a summary table with div and modulo:
ACCT_NUM TIMES REMAINDER
101 2 175
102 0 15
103 1 200
104 0 475
Then perform a hierarchical query on the summary table based on the number of "times" (i.e. rows) you want, with an extra for the remainder.
ACCT_NUM AMT
101 1000
101 1000
101 175
102 15
103 1000
103 200
104 475

Combining Two Tables & Summing REV amts by Mth

Below are my two tables of data
Acct BillingDate REV
101 01/05/2018 5
101 01/30/2018 4
102 01/15/2018 2
103 01/4/2018 3
103 02/05/2018 2
106 03/06/2018 5
Acct BillingDate Lease_Rev
101 01/15/2018 2
102 01/16/2018 1
103 01/19/2018 2
104 02/05/2018 3
105 04/02/2018 1
Desired Output
Acct Jan Feb Mar Apr
101 11
102 3
103 5 2
104 3
105 1
106 5
My SQL Script is Below:
SELECT [NewSalesHistory].[Region]
,[NewSalesHistory].[Account]
,SUM(case when [NewSalesHistory].[billingdate] between '6/1/2016' and '6/30/2016' then REV else 0 end ) + [X].[Jun-16] AS 'Jun-16'
FROM [NewSalesHistory]
FULL join (SELECT [Account]
,SUM(case when [BWLease].[billingdate] between '6/1/2016' and '6/30/2016' then Lease_REV else 0 end ) as 'Jun-16'
FROM [AirgasPricing].[dbo].[BWLease]
GROUP BY [Account]) X ON [NewSalesHistory].[Account] = [X].[Account]
GROUP BY [NewSalesHistory].[Region]
,[NewSalesHistory].[Account]
,[X].[Jun-16]
I am having trouble combining these tables. If there is a rev amt and lease rev amt then it will combine (sum) for that account. If there is not a lease rev amt (which is the majority of the time), it brings back NULLs for all other rev amts accounts in Table 1. Table one can have duplicate accounts with different Rev, while the Table two is one unique account only w Lease rev. The output above is how I would like to see the data.
What am I missing here? Thanks!
I would suggest union all and group by:
select acct,
sum(case when billingdate >= '2016-01-01' and billingdate < '2016-02-01' then rev end) as rev_201601,
sum(case when billingdate >= '2016-02-01' and billingdate < '2016-03-01' then rev end) as rev_201602,
. . .
from ((select nsh.acct, nsh.billingdate, nsh.rev
from NewSalesHistory
) union all
(select bl.acct, bl.billingdate, bl.rev
from AirgasPricing..BWLease bl
)
) x
group by acct;
Okay, so there are a few things going on here:
1) As Gordon Linoff mentioned you can perform a union all on the two tables. Be sure to limit your column selections and name your columns appropriately:
select
x as consistentname1,
y as consistentname2,
z as consistentname3
from [NewSalesHistory]
union all
select
a as consistentname1,
b as consistentname2,
c as consistentname3
from [BWLease]
2) Your desired result contains a pivoted month column. Generate a column with your desired granularity on the result of the union in step one. F.ex. months:
concat(datepart(yy, Date_),'-',datename(mm,Date_)) as yyyyM
Then perform aggregation using a group by:
select sum(...) as desiredcolumnname
...
group by PK1, PK2, yyyyM
Finally, PIVOT to obtain your result: https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-2017
3) If you have other fields/columns that you wish to present then you first need to determine whether they are measures (can be aggregated) or are dimensions. That may be best addressed in a follow up question after you've achieved what you set out for in this part.
Hope it helps
As an aside, it seems like you are preparing data for reporting. Performing these transformations can be facilitated using a GUI such as MS Power Query. As long as your end goal is not data manipulation in the DB itself, you do not need to resort to raw sql.

Creating a "pivot table" like construct in sql

This is going to be a bit convoluted but I have a table named dbo.sizeclassreport. I apologize if this is a bit vague.
It has 78656 rows/records which is not all that immense. There are three salient fields; employment, area, and sizeclass. Sample data below
Area Employment sizeclass
000003 4 01
000001 6 02
000013 12 03
000003 2 01
000005 23 04
000001 7 02
000003 11 03
From here, the result would look this. There are 9 sizeclasses and 18 areas. Need to produce 9 breakdowns of each area. Each area would have a breakdown by size class.
Area Sizeclass Employment in Size Class Number of Sites
Total 00 17(6+11) 3
000003 01 6 (4+2) 2
000003 02 NULL or Empty NULL or Empty
000003 03 11 1
......
000003 09 NULL or Empty NULL or Empty
SELECT
[Areas].[Area],
[classSizes].[sizeclass],
SUM([data].[Employment]) AS [Employment in Size Class],
/*this would be better with your PK */
CASE COUNT([data].[Employment])
WHEN 0 THEN NULL
ELSE COUNT([data].[Employment])
END AS [Number of Sites]
/*These rows create your base matix*/
FROM (SELECT DISTINCT
[Area]
FROM [sizeclassreport]) AS [Areas]
CROSS JOIN (SELECT DISTINCT
[sizeclass]
FROM [sizeclassreport]) AS [classSizes]
/* this is where you select your data*/
LEFT OUTER JOIN [sizeclassreport] [data]
ON [Areas].[Area] = [data].[Area]
AND [classSizes].[sizeclass] = [data].[sizeclass]
GROUP BY
[areas].[Area],
[classSizes].[sizeclass]
ORDER BY
[areas].[Area],
[classSizes].[sizeclass]
It looks like you want all areas and sizeclasss in the output. If so, use cross join to generate the results, then left join and group by for the calculations:
select a.area, sc.sizeclass,
sum(scr.employment) as employment,
count(scr.area) as number_of_sizes
from (select distinct area from dbo.sizeclassreport scr) a cross join
(select distinct sizeclass from dbo.sizeclassreport scr) sc left join
dbo.sizeclassreport scr
on a.area = scr.area and sc.sizeclass = scr.sizeclass
group by a.area, sc.sizeclass;
Note: This returns 0 instead of NULL for the last column. This makes more sense to me. However, you could use NULLIF() if you really want a NULL value.

Power Pivot - Inner Join like access, calculate and show grand total, possible?

I'm trying to acive the following with power pivot. Still couldn't figure out how. Is it possible?
Example from access
Gourped by “MatNr”. “Qty cases” are summed. From the “tbl_Weight” show the “Cases on trolley” per material. Divide “summed Qty cases” by “Cases on trolley” and show the results in the fourth column. Most importantly total the “summed Qty cases” column and the “Nr of trolleys per mat” column.
Two tables:
tbl_Sales
MatNr Qty cases
4564 100
4654 565
4564 100
4654 50
tbl_Weight
MatNr Cases on trolley
4564 10
4654 20
Query:
SELECT tbl_Sales.MatNr, Sum(tbl_Sales.[Qty cases]) AS [SummevonQty cases], tbl_Weight.[Cases on trolley], Sum([Qty cases]/[Cases on trolley]) AS [Nr of trolleys per mat]
FROM tbl_Sales INNER JOIN tbl_Weight ON tbl_Sales.MatNr = tbl_Weight.MatNr
GROUP BY tbl_Sales.MatNr, tbl_Weight.[Cases on trolley];
Expected results:
MatNr SummevonQty cases Cases on trolley Nr of trolleys per mat
4564 200 10 20
4654 615 20 30.75
Totals 815 50.75