Join and aggregating two internal tables into one - abap

I need to aggregate the below two tables into one, per True_Origin and True_Destination level.
Table 2 (IT_DATES_OD):
FDate2 Flight_Number2 Origin2 Destination2 Amount3 Amount4
20190501 123 DXB LOS 5 12
20190501 123 DXB LOS 22 558
20190501 123 DXB LOS 2556 4585
Table 1 (IT_TOD_OD):
Flight_Date_OD Flight_Number_OD Origin Destination True_origin True_destination Net_Net_Net Amount2
20190501 123 DXB LOS DXB NBO 5 12
20190501 123 DXB LOS DXB ADD 22 558
20190501 123 DXB LOS DXB LOL 2556 4585
I can aggregate using common fields (Date, Flight Number, Origin, Destination) but I can't aggregate on a detailed level on True_origin and True_destination.
SORT IT_DATES_TOD BY FDATE2 FLIGHT_NUMBER2 ORIGIN2 DESTINATION2 ASCENDING.
CLEAR WA_OUTPUT.
LOOP AT IT_DATES_TOD INTO WA_DATES_TOD WHERE FDATE2 <> ''.
WA_OUTPUT-FDATE = WA_DATES_TOD-FDATE2.
WA_OUTPUT-FLIGHT_NUMBER = WA_DATES_TOD-FLIGHT_NUMBER2.
WA_OUTPUT-ORIGIN = WA_DATES_TOD-ORIGIN2.
WA_OUTPUT-DESTINATION = WA_DATES_TOD-DESTINATION2.
LOOP AT IT_TOD_OD INTO WA_TOD_OD
WHERE FLIGHT_DATE_OD = WA_DATES_TOD-FDATE2
AND FLIGHT_NUMBER_OD = WA_DATES_TOD-FLIGHT_NUMBER2
AND ORIGIN = WA_DATES_TOD-ORIGIN2
AND DESTINATION = WA_DATES_TOD-DESTINATION2.
WA_OUTPUT-TRUE_ORIGIN = WA_TOD_OD-TRUE_ORIGIN.
WA_OUTPUT-TRUE_DESTINATION = WA_TOD_OD-TRUE_DESTINATION.
WA_OUTPUT-NET_NET_NET = WA_TOD_OD-NET_NET_NET.
WA_OUTPUT-RE_PRO_REVFUEL = 0.
WA_OUTPUT-BLOCK_HOUR = 0.
APPEND WA_OUTPUT TO IT_OUTPUT.
ENDLOOP.
ENDLOOP.

Please have a look at the collect Syntax in ABAP:
COLLECT statement in ABAP is used for inserting the components of a work area into an internal table by avoiding duplicate entries and also in a summarized way.
Syntax
COLLECT <line> INTO <itab>
When you use collect statement the following steps are occurring.
First it will check in internal table for any record matching with the key in work area data.
If it couldn’t find any matching record, then the new data from work area will be inserted in internal table
If any record found with the same key, then instead of inserting a new record, it will add the numeric field values of work area components with the corresponding field components in the matched record and update the internal table record.
both of your itabs should use the Destination structure:
Date F_Number Orign Destin T_origin T_destin Amount Amount2
so the collect command can make use add functionality of the numeric fields.

Related

How would I create one data set from a table that contains two identical values in the first column but different data in the remaining columns Oracle

I have produced a dataset where some of the data has two identical memberkeys but different contract values, while other memberkeys only appear once. I need to merge those memberkeys that have two rows into one distinct memberkey row containing all the data from both rows while leaving the single row memberkey as is.
Current
MemberKey
SubscriberKey
VALUEONE
VALUETWO
VALUETHREE
VALUEFOUR
VALUEFIVE
VALUESIX
VALUESEVEN
VALUEEIGHT
VALUENINE
VALUETEN
VALUEELEVEN
2235
H4931
MA84100303
ENGLISH
ACOC
5TX4VV3TD79
13
1
2235
2235
A84100303
b
ENGLISH
AUCOC
A84100303
4375
H4931
MA48450239
SPANISH
APIM
9QP3K96WK88
14
1
4375
4375
A48450239
SPANISH
AUPIM
A48450239
375
375
H4931
MA08111511
ENGLISH
AMAR
8B06P95CG54
Desired
MemberKey
SubscriberKey
VALUEONE
VALUETWO
VALUETHREE
VALUEFOUR
VALUEFIVE
VALUESIX
VALUESEVEN
VALUEEIGHT
VALUENINE
VALUETEN
VALUEELEVEN
2235
2235
A84100303
b
H4931
MA84100303
ENGLISH
ACOC
AUCOC
A84100303
5TX4VV3TD79
13
1
4375
4375
A48450239
H4931
MA48450239
SPANISH
APIM
AUPIM
A48450239
9QP3K96WK88
14
1
375
375
H4931
MA08111511
ENGLISH
AMAR
8B06P95CG54
I've tried several approaches (ctes, temp tables, convoluted joins etc) without success.
Thanks
Could you create a table and then update this new table with your old table using by joining on the memberkey?
update new_table a
set a.valueone = (select max(x.valueone)
from old_table x
where a.memberkey = x.memberkey);
commit;
This would work as long as for the same memberkey you do not have a different value for the same column.
This seems to work
MERGE INTO MEMBERS m2
USING MEMBERS_GTT m1 ON ( m1.MemberKey = m2.MemberKey )
WHEN MATCHED
THEN
UPDATE SET m2.SUBSCRIBERKEY = COALESCE(m1.SUBSCRIBERKEY,m2.SUBSCRIBERKEY)
WHEN NOT MATCHED
THEN
INSERT ( MemberKey ,
SUBSCRIBERKEY
)
VALUES ( m1.MemberKey ,
m1.SUBSCRIBERKEY
)

Merge on multiple conditions

Is it possible to use multiple conditions on SQL merge ON condition to make as unique identifier instead of concatenating?
CompanyId+StoreLocation = UniqueId. I do not want to create an additional concatenated column. Will this work? If not, what could be the best solution?
ON (target.CompanyId = source.CompanyId AND target.Storelocation = source.storelocation)
CompanyId StoreLocation StoreSQM
------------------------------------
12345 Chicago01 1650
12345 Chicago02 1985
12652 Milwaukee 1865
45846 Minneapolis 45845
MERGE dbo.storestbl AS target
USING stagingtbl AS source
**ON (target.CompanyId = source.CompanyId AND target.Storelocation = source.storelocation)**
WHEN MATCHED THEN
Do something
WHEN NOT MATCHED THEN
Do something

How to get the set size, first and last record in a db2 ordered set with one call

I have a very big transaction table on DB2 v11, and I need to query a subset of it as efficiently as possible. All I need is the total count of the set (not known in advance, it's based on criteria, lets say 1 day) and the ID of the first record, and the ID of the last record.
The old code was fetching the entire table, then just using the 1st record ID, and the last record ID, and size, and not making use of the rest. Now this code is timing out. It's a complex query of several joins.
IS there a way to just fetch the size of the set, 1st record, last record all in one select query ?
I've read that reordering the list in order to fetch the 1st record(so fetch with Desc, then change to Asc) is not efficient.
sample table 1 TRANSACTION_RECORDS:
tdID TIMESTAMP name
-------------------------------
123 2020-03-31 john
234 2020-03-31 dan
456 2020-03-01 Eve
675 2020-04-01 joy
sample table 2 TRANSACTION_TYPE:
invoiceId tdID account
------------------------------
897 123 abc
898 123 def
877 234 mnc
899 456 opp
Sample query
select Min(tr.transaction_id), Max(tr.transaction_id)
from TRANSACTION_RECORDS TR
join TRANSACTION_TYPE TT
on TR.tdID=tt.tdID
WHERE Date(TR.TIMESTAMP) = '2020-03-31'
group by tr.tdID
order by TR.tdID ASC
This results in multiple columns, (but it requires the group by)
123,123
234,234
456,456
What I want is:
123,456
As I mentioned in the comments, for this query you don't need Group BY and neither Order by, just do:
select Min(tr.transaction_id), Max(tr.transaction_id)
from TRANSACTION_RECORDS TR
join TRANSACTION_TYPE TT
on TR.tdID=tt.tdID
WHERE Date(TR.TIMESTAMP) = '2020-03-31'
It should work as expected

JOIN the same table on two columns

I use JOINs to replace country and product IDs in import and export data with actual country and products names stored in separate tables. In the data source table (data), there are two columns with country IDs, for origin and destination, both of which I am replacing with country names.
The code I have come up with refers to the country_names table twice – as country_names, and country_names2, – which doesn’t seem to be very elegant. I expected to be able to refer to the table just once, by a single name. I would be grateful if someone pointed me to a more elegant and maybe more efficient way to achieve the same result.
SELECT
country_names.name AS origin,
country_names2.name AS dest,
product_names.name AS product,
SUM(data.export_val) AS export_val,
SUM(data.import_val) AS import_val
FROM
OEC.year_origin_destination_hs92_6 AS data
JOIN
OEC.products_hs_92 AS product_names
ON
data.hs92 = product_names.hs92
JOIN
OEC.country_names AS country_names
ON
data.origin = country_names.id_3char
JOIN
OEC.country_names AS country_names2
ON
data.dest = country_names2.id_3char
WHERE
data.year > 2012
AND data.export_val > 1E8
GROUP BY
origin,
dest,
product
The table to convert product IDs to product names has 6K+ rows. Here is a small sample:
id hs92 name
63215 3215 Ink
2130110 130110 Lac
21002 1002 Rye
2100200 100200 Rye
52706 2706 Tar
20902 902 Tea
42203 2203 Beer
42302 2302 Bran
178703 8703 Cars
The table to convert country IDs to country names (which is the table I have to JOIN on twice) has 264 rows for all countries in the world. (id_3char is the column used.) Here is a sample:
id id_3char name
euchi chi Channel Islands
askhm khm Cambodia
eublx blx Belgium-Luxembourg
eublr blr Belarus
eumne mne Montenegro
euhun hun Hungary
asmng mng Mongolia
nabhs bhs Bahamas
afsen sen Senegal
And here is a sample of data from the import and export data table with a total of 205M rows that has the two columns origin and dest that I am making a join on:
year origin dest hs92 export_val import_val
2009 can isr 300410 2152838.47 3199.24
1995 chn jpn 590190 275748.65 554154.24
2000 deu gmb 100610 1573508.44 1327.0
2008 deu jpn 540822 10000.0 202062.43
2010 deu ukr 950390 1626012.04 159423.38
2006 esp prt 080530 2470699.19 125291.33
2006 grc ind 844859 8667.0 3182.0
2000 ltu deu 630399 6018.12 5061.96
2005 usa zaf 290219 2126216.52 34561.61
1997 ven ecu 281122 155347.73 1010.0
I think you already have it done such that it can be considered good enough to just use as is :o)
Meantime, If for some reason you really-really want to avoid two joins on that country table - what you can do is to materialize below select statement into let's say `OEC.origin_destination_pairs` table
SELECT
o.id_3char o_id_3char,
o.name o_name,
d.id_3char d_id_3char,
d.name d_name
FROM `OEC.country_names` o
CROSS JOIN `OEC.country_names` d
Then you can just join on that new table as below
SELECT
country_names.o_name AS origin,
country_names.d_name AS dest,
product_names.name AS product,
SUM(data.export_val) AS export_val,
SUM(data.import_val) AS import_val
FROM OEC.year_origin_destination_hs92_6 AS data
JOIN OEC.products_hs_92 AS product_names
ON data.hs92 = product_names.hs92
JOIN OEC.origin_destination_pairs AS country_names
ON data.origin = country_names.o_id_3char
AND data.dest = country_names2.d_id_3char
WHERE data.year > 2012
AND data.export_val > 1E8
GROUP BY
origin,
dest,
product
The motivation behind above is cost of storing and querying in your particular case
Your `OEC.country_names` table is just about 10KB in size
Each time you query it you pay as if it is 10MB (Charges are rounded to the nearest MB, with a minimum 10 MB data processed per table referenced by the query, and with a minimum 10 MB data processed per query.)
So, if you will materialize above mentioned table - it will still be less than 10MB so no difference in querying charges
Similar situation with storing that table - no visible changes in charges
You can check more about pricing here

SQL UPDATE SET interchanges values

I update a View to get in two columns the same value, but it interchanges the two values instead of just setting it. My (reduced for so) view UpdateADAuftrag2 is this.
SELECT dbo.CSDokument.AD1, dbo.UpdateAS400zuSellingBenutzer2.BenutzerNr
FROM dbo.AS400Auftrag
INNER JOIN
dbo.CSDokument ON dbo.AS400Auftrag.Angebotsnummer = dbo.CSDokument.Angebotsnummer
INNER JOIN
dbo.UpdateAS400zuSellingBenutzer2 ON dbo.AS400Auftrag.AD = dbo.UpdateAS400zuSellingBenutzer2.SchluesselWert
AND
dbo.CSDokument.AD1 <> dbo.UpdateAS400zuSellingBenutzer2.BenutzerNr
WHERE (dbo.AS400Auftrag.AD IS NOT NULL)
The important part is dbo.CSDokument.AD1 <> dbo.UpdateAS400zuSellingBenutzer2.BenutzerNr
AD1 is user number for external workers and BenutzerNr means user number. So e.g. the person Charlie Brown is an external worker and has the user number 31. When in AD1 is 31 - Charlie Brown is the external worker for this document (order in this case).
The Update statement loos like this
UPDATE [dbo].[UpdateADAuftrag2]
SET [AD1] = [BenutzerNr]
I have for example these values
AD1 | BenutzerNr
31 | 54
99 | 384
112 | 93
after the update the result is this
AD1 | BenutzerNr
54 | 31
384 | 99
93 | 112
Why not this?
AD1 | BenutzerNr
54 | 54
384 | 384
93 | 93
edit: UpdateAS400zuSellingBenutzer is also a View, but as far as I can see it includes only BenutzerNr and not AD1.
Firstly, you're never going to see your expected results in the view. Your UPDATE statement is effectively a DELETE statement (as far as the view is concerned). Rows only appear in the view if AD1 <> BenutzerNr, but you're setting them to be equal.
However, the documentation for updatable views states "Any modifications, including UPDATE, INSERT, and DELETE statements, must reference columns from only one base table." Your update statement references columns from more than one table.
https://msdn.microsoft.com/en-us/library/ms187956.aspx#Updatable Views
I'm not sure what you're trying to achieve here, but in my experience it's usually easier to issue the UPDATE statement against the base tables directly.
There were 2 bugs - Bug 1 View UpdateAS400zuSellingBenutzer2 had 2 results sometimes for one entry in CSDokument and Bug 2 There were 2 entries in Table AS400Auftrag and then it switched between these two entries. So it just looked like the SET switched the two entries but it was just by chance. Thanks for reading.