When same BELNR value, report only gets info from the first line - abap

I have a report that is getting info from bsis, bsas, bsid, bsad, vbrk, bkpf and bset. the problem is when there are two invoices with the same number, the report copies the info from the first line to the second. So, if invoice no.4100111596 has a tax total of 2.140,20 in the first line, the same invoice number has the same tax toal in the second, but the value is 40.140,64.
What can I do? do I have to use the buzei field some where?
Heres de code:
SELECT SINGLE kbetr fwste hwste
FROM bset
INTO (<fs_main>-kbetr, <fs_main>-fwste, <fs_main>-hwste)
WHERE belnr = <fs_main>-belnr
AND bukrs IN bukrs
AND gjahr IN gjahr.
I tried getting the buzei and it still gives me the same line twice.
Here's the code, that I do before the code above:
SELECT c~kunnr a~belnr d~spart c~bldat c~waers c~wrbtr a~hwaer c~dmbtr c~buzei
INTO CORRESPONDING FIELDS OF TABLE lt_data
FROM ( ( ( bsis AS f
INNER JOIN bkpf AS a ON f~belnr = a~belnr )
INNER JOIN bsid AS c ON c~belnr = a~belnr )
INNER JOIN vbrk AS d ON d~vbeln = c~belnr )
WHERE a~gjahr IN gjahr
AND a~bukrs IN bukrs
AND a~blart = 'R1'
AND f~hkont = '0034930020'
AND ( c~mwskz = 'L0' OR c~mwskz = 'L1' OR c~mwskz = 'L2' ).

-You have to use all key fields on your condition part of your "SELECT" in order to get a "SINGLE" line. Otherwise table might not return you a single line but you'll get the first line.
-So you have to use BUZEI field too on your condition in your select.
Hope it was helpful
Talha

Found the problem. I was doing the selection os the wrong fields i the wrong table. BKPF only gave me one line and BSET gave me two lines. So, I change the tables that was getting the fields from and it work just fine. Thank you.

Related

DBSQL_SQL_INTERNAL_DB_ERROR SQL error 2048

I have to join two tabled ACDOCA and BKPF. I have written the follow code for it.
SELECT a~rbukrs,
a~racct,
a~bldat,
a~blart,
a~kunnr,
a~belnr,
a~sgtxt,
b~xblnr,
a~budat,
a~hsl,
a~prctr
INTO TABLE #it_final
FROM acdoca AS a
LEFT OUTER JOIN bkpf AS b
ON a~rbukrs = b~bukrs
AND a~gjahr = b~gjahr
WHERE a~rbukrs IN #s_bukrs
AND a~Kunnr IN #s_kunnr
AND a~Budat IN #s_budat
AND a~Belnr IN #s_belnr
AND a~rldnr IN #s_rldnr
AND a~blart = 'DR' OR a~blart = 'ZK' OR a~blart = 'UE'.
Facing the following errors:----
Runtime error: DBSQL_SQL_INTERNAL_DB_ERROR
SQL error "SQL code: 2048" occurred while accessing table "ACDOCA".
Short Text: An exception has occurred in class "CX_SY_OPEN_SQL_DB"
How do I resolve this? please help.
A few things:
Selecting directly from the database tables is error prone (e.g. you'll forget keys while joining) and you have to deal with those terrible german abbreviations (e.g. Belegnummer -> belnr). Since quite some time there are CDS Views on top such as I_JournalEntryItem with associations and proper english names for those fields, if you can use them, I would (also they're C1 released).
As already pointed out by xQBert the query does probably not work as intended as AND has prescendence over OR, and as such your query basically returns everything from ACDOCA, multiplied by everything from BKPF which likely leads to the database error you've posted
With range queries you might still get a lot of results (like billions of entries, depending on your company's size), you should either limit the query with UP TO, implement some pagination or COUNT(*) first and show an error to the user if the result set is too large.
I would write that like this:
TYPES:
BEGIN OF t_filters,
company_codes TYPE RANGE OF bukrs,
customers TYPE RANGE OF kunnr,
document_dates TYPE RANGE OF budat,
accounting_documents TYPE RANGE OF fis_belnr,
ledgers TYPE RANGE OF rldnr,
END OF t_filters.
DATA(filters) = VALUE t_filters(
" filter here
).
SELECT FROM I_JournalEntryItem
FIELDS
CompanyCode,
GLAccount,
DocumentDate,
AccountingDocumentType,
Customer,
AccountingDocument,
DocumentItemText,
\_JournalEntry-DocumentReferenceID,
PostingDate,
AmountInCompanyCodeCurrency,
ProfitCenter
WHERE
CompanyCode IN #filters-company_codes AND
Customer IN #filters-customers AND
DocumentDate IN #filters-document_dates AND
AccountingDocument IN #filters-accounting_documents AND
Ledger IN #filters-ledgers AND
AccountingDocumentType IN ( 'DR', 'ZK', 'UE' )
INTO TABLE #DATA(sales_orders)
UP TO 100 ROWS.
(As a bonus you'll get proper DCL authorization checks)
2048 is/can be a memory allocation error: Too much data being returned. Given that, this line is highly suspect
AND a~blart = 'DR' OR a~blart = 'ZK' OR a~blart = 'UE'.
I'd consider this instead. Otherwise ALL blart ZK and UE records are returned regardless of customer, year, company et...
SELECT a~rbukrs,
a~racct,
a~bldat,
a~blart,
a~kunnr,
a~belnr,
a~sgtxt,
b~xblnr,
a~budat,
a~hsl,
a~prctr
INTO TABLE #it_final
FROM acdoca AS a
LEFT OUTER JOIN bkpf AS b
ON a~rbukrs = b~bukrs
AND a~gjahr = b~gjahr
WHERE a~rbukrs IN #s_bukrs
AND a~Kunnr IN #s_kunnr
AND a~Budat IN #s_budat
AND a~Belnr IN #s_belnr
AND a~rldnr IN #s_rldnr
AND a~blart IN ('DR','ZK','UE').
However, if you really did mean to return all blart ZK, UE records and only those that ar DR and in the defined parameters... you're simply asking for too much data from teh system and need to "LIMIT" your result set and somehow let the user know only a limited set is being returned due to data volume
I'd also ensure your join on keys is sufficient. Fiscal Year and company code represent an incomplete key to BKPF. I dont' know ACDOCA data table so I'm unsure if that's a proper join which may be leading to a semi-cartesean contributing to data bloat. I'd think in a multi-tenant db, you may need to join on mandt as well... possibly a doc number and some other values... again, this lookst to be an incomplete join on key.... so perhaps more is needed there as well.

SD Invoice with amount 0 EUR not to be transmitted to FI

I am trying to fix a certain already developed function with the goal that the SD Invoice with amount 0 EUR should not be transmitted to FI. As I understood, the below code is used to select the data from FI and SD:
* select order-related invoices
SELECT * FROM vbfa AS v INTO TABLE gt_vbfa_inv
FOR ALL ENTRIES IN gt_vbak
WHERE vbelv = gt_vbak-vbeln
AND vbtyp_n IN ('M', 'O', 'P', '5', '6')
AND stufe = '00'
AND NOT EXISTS ( SELECT * FROM vbfa
WHERE vbelv = v~vbeln
AND posnv = v~posnn
AND vbtyp_n IN ('N', 'S')
AND stufe = '00' ) .
IF sy-subrc = 0.
* select invoice head status
SELECT DISTINCT * FROM vbuk APPENDING TABLE gt_vbuk_inv
FOR ALL ENTRIES IN gt_vbfa_inv
WHERE vbeln = gt_vbfa_inv-vbeln. "#EC CI_SUBRC
ENDIF.
SORT gt_vbuk_inv BY vbeln.
DELETE ADJACENT DUPLICATES FROM gt_vbuk_inv COMPARING vbeln.
IF me->gv_items = abap_true AND gt_vbuk_inv IS NOT INITIAL.
SELECT * FROM vbrp INTO TABLE gt_vbrp
FOR ALL ENTRIES IN gt_vbuk_inv
WHERE vbeln = gt_vbuk_inv-vbeln. "#EC CI_SUBRC
ENDIF.
As far as I can understand from the above written code, is that the table VBFA is used to get the data for FI, while the table VBRP is used to get the data for SD. What I want to achieve is that when the invoice number does not have a FI document, then the invoice number will be empty.
If the tables BKPF(for the FI) and VBRK(for the SD) would be used, then I could have tried the relation:
vbrk-xblnr=bkpf-xblnr.
However, those tables are not used in the function. May I please ask you, how can I fix the code so that when the invoice number does not have a FI document, thus the invoices with a value of 0 EUR will not generate an FI document, then the invoice number will be empty.
Thank you all in advance!
Since the goal is
the SD Invoice with amount 0 EUR should not be transmitted to FI
I suppose your code is in some user-exit or standard program modification when releasing the SD invoice to Accounting. If so, the BKPF is not created yet and there's no reason in selecting it.
The select from VBFA is not extracting data from FI. Starting from the Sales Order it is extracting the following SD documents (first document flow level only)
M Invoice
N Invoice Cancellation
P Debit Memo
5 Intercompany Invoice
6 Intercompany Credit Memo
And excluding those invoices that have a subsequent cancellation
N Invoice Cancellation
S Credit Memo Cancellation
Those documents can be found in VBRK table (SD invoice header) with the following select
SELECT DISTINCT * FROM vbrk APPENDING TABLE gt_vbrk
FOR ALL ENTRIES IN gt_vbfa_inv
WHERE vbeln = gt_vbfa_inv-vbeln.
Btw: I don't know the reason for the VBUK select since you're not using any document status information
If you're asking for the SD invoices with zero amount with the purpose to not release them to accounting (since otherwise they would produce an error in FI) you don't have to select BKPF but check VBRK-NETWR = 0 for every entry in gt_vbrk table

How to join the tables KNBK and TIBAN?

I am trying to read the table TIBAN only in the cases when the field BANKN of the KNBK table contains the string "IBAN". The problem that I am having is reading the table TIBAN. For the KNBK table I used the key kunnr to search the table, but the table TIBAN does not contain this field. The code is as follows:
LOOP AT lt_data_bsec ASSIGNING <ls_data_bsec>.
READ TABLE lt_data_knbk ASSIGNING FIELD-SYMBOL(<ls_data_knbk>)
WITH KEY kunnr = <ls_data_bsec>-kunnr BINARY SEARCH .
IF <ls_data_knbk>-bankn_kn CS '<IBAN>'.
>>>>> READ TABLE lt_data_tiban ASSIGNING FIELD-SYMBOL(<ls_data_tiban>).
IF <ls_data_bsec> IS ASSIGNED
AND <ls_data_tiban> IS ASSIGNED
AND ( <ls_data_bsec>-banks_bs NE <ls_data_tiban>-banks_kn
OR <ls_data_bsec>-bankl_bs NE <ls_data_tiban>-bankl_kn
OR <ls_data_bsec>-bankn_bs NE <ls_data_tiban>-bankn_kn ).
ENDIF.
The declaration of the lt_data_knbk table is:
SELECT kunnr,
banks AS banks_kn,
bankl AS bankl_kn,
bankn AS bankn_kn
FROM knbk
INTO TABLE #DATA(lt_data_knbk)
FOR ALL ENTRIES IN #lt_data_bsec
WHERE kunnr = #lt_data_bsec-kunnr
ORDER BY PRIMARY KEY.
And the declaration of the lt_data_tiban is:
SELECT banks AS banks_tb,
bankl AS bankl_tb,
bankn AS bankn_tb
FROM tiban
INTO TABLE #DATA(lt_data_tiban).
Also the declaration of the lt_data_bsec is of the type gty_out:
BEGIN OF gty_out,
bukrs TYPE bukrs,
belnr TYPE belnr_d,
buzei TYPE buzei,
budat TYPE budat,
kunnr TYPE kunnr,
banks_kn TYPE banks,
bankl_kn TYPE bankk,
bankn_kn TYPE bankn,
banks_bs TYPE banks,
bankl_bs TYPE bankk,
bankn_bs TYPE bankn,
banks_tb TYPE banks,
bankl_tb TYPE bankk,
bankn_tb TYPE bankn,
END OF gty_out,
I am having an error in the line that I have marked in the code as it needs a key field to do the reading of the table.
May anyone know what type of field do I need to do a search of the TIBAN table, just like I did for the KNBK table?
I would recommend you to acquire your bank data by doing a LEFT OUTER JOIN with TIBAN.
SELECT knbk~kunnr AS kunnr,
knbk~banks AS banks_kn,
knbk~bankl AS bankl_kn,
knbk~bankn AS bankn_kn,
knbk~bkont AS bkont_kn,
tiban~iban AS iban
FROM knbk
LEFT OUTER JOIN tiban ON
tiban~banks = knbk~banks AND
tiban~bankl = knbk~bankl AND
tiban~bankn = knbk~bankn AND
tiban~bkont = knbk~bkont
INTO TABLE #DATA(lt_data_knbk)
FOR ALL ENTRIES IN #lt_data_bsec
WHERE knbk~kunnr = #lt_data_bsec-kunnr
ORDER BY knbk~banks knbk~bankl knbk~bankn knbk~bkont.
The result will be a table with all entries from KNBK, plus a field IBAN which will be filled from TIBAN if a corresponding row exists and be initial when no corresponding row exists.
Now you can just determine whether or not you have an IBAN like this:
LOOP AT lt_data_knbk ASSIGNING FIELD-SYMBOL(<ls_data_knbk>).
IF <ls_data_knbk>-iban IS INITIAL.
" classic bank number + account number account
ELSE.
" IBAN account
ENDIF.
ENDLOOP.
Your task is a perfect case where ABAP CDS associations aka Lazy Join come into play.
If you are on the recent version of ABAP and is able to create CDS, nothing prevents you from creating this
#AbapCatalog.sqlViewName: ‘ZCUST_TIBAN_SQL’
#AbapCatalog.compiler.compareFilter: true
#AccessControl.authorizationCheck: #CHECK
#EndUserText.label: ‘TIBAN’
define view ZCUST_TIBAN as select from knbk as cus
association [0..1] to tiban as _an
on cus.kunnr = _an.kunnr
and cus.banks = _an.banks
and cus.bankl = _an.bankl
and cus.bankn = _an.bankn
and cus.bkont = _an.bkont
{
cus.kunnr,
cus.banks AS banks_kn,
cus.bankl AS bankl_kn,
cus.bankn AS bankn_kn,
cus.bkont AS bkont_kn,
_iban~
} WHERE cus.bankn like '%IBAN%'
Then you can use this association in all your further requirements:
SELECT banks_kn, bankl_kn, bankn_kn, bkont_kn
\_iban-iban AS IBAN,
\_iban-valid_from AS IBAN_validity
FROM zcust_tiban
WHERE kunnr IN #lr_customers
INTO TABLE #DATA(lt_data_knbk).
...
READ TABLE lt_data_knbk ASSIGNING FIELD-SYMBOL(<ls_data_knbk>)
WITH KEY kunnr = <ls_data_bsec>-kunnr BINARY SEARCH.
...
Key points to pay attention to:
an association with 0..1 cardinality like above does not do actual JOIN until the fields from the associated table TIBAN are requested like in the above SELECT. This can be more performant and more universal than LEFT OUTER JOIN approach suggested by Philipp.
it is reusable and can be used in further selects/associations as a source

SAP query. Retrieve values basing on input on selection screen

I am stuck with coding a SAP query..I am new to ABAP.
What I would like to achieve is a join between tables ESLL, EKPO, EKKO.
Specifically these are the steps I would like to achieve:
in the selection parameter every time I will enter the query I will
give a different value for ESLL-EXTSRVNO;
basing on that value the query automatically should select ESLL-PACKNO basing on ESLL-EXTSRVNO given;
then the query should put ESLL-SUB_PACKNO equal
to the ESLL-PACKNO values of the steps before;
then the query should
put the new ESLL-PACKNO values equal to EKPO-PACKNO and retrieve the
following fields: EKPO-EBELN, EKPO-EBELP, EKPO-MATKL.
I have already written some code inside the infoset, but I do not know how to fix it.
In the "data" section I have written:
DATA: it_esll TYPE TABLE OF esll.
DATA: it_esll2 TYPE TABLE OF esll.
DATA: it_ekpo TYPE TABLE OF ekpo.
In the "start-of-selection" section I have written:
SELECT packno
FROM esll
INTO TABLE it_esll.
IF sy-subrc EQ 0.
SELECT packno FROM esll
into TABLE it_esll2
for ALL ENTRIES IN it_esll
where sub_packno EQ it_esll-packno.
IF sy-subrc EQ 0.
SELECT ebeln ebelp bukrs werks matkl menge netpr peinh
FROM ekpo
into TABLE it_ekpo
for ALL ENTRIES IN it_esll2
WHERE packno EQ it_esll2-packno.
endif.
endif.
And, in order to display all the information I want, I have put the following joins:
ESLL-PACKNO --> EKPO-PACKNO --> EKPO-EBELN --> EKKO-EBELN
At then end I would like to display these information:
EKPO-EBELN
EKPO-EBELP
EKPO-MATKL
EKKO-BSART
EKPO-PACKNO
Could you please help me?
One option could be to use Alias table in your infoset, something like this:
First table: ESLL;
Second table ZESLL (Alias on ESLL) with join ZESLL-PACKNO = ESLL-SUB_PACKNO;
Third table: EKPO with join on EKPO-PACKNO = ZESLL-PACKNO;
Fourth table: EKKO with join on EBELN;
So you can avoid ABAP
Infoset Join

How do I generate an Oracle SQL statement , where each column would need its own separate query?

I have a query where I need to use separate queries to fill in the individual columns :
It would look Something like this for each column
select PERFORMED_DATE from HHS_UMX_RESP_ACTIVITY where
REG_REQUEST_ID IN ('261507') AND ACTIVITY_RESULT_CODE = 'ASD'
AS "Security"
UNION
select PERFORMED_DATE from HHS_UMX_RESP_ACTIVITY where
REG_REQUEST_ID IN ('261507') AND ACTIVITY_RESULT_CODE = 'OTZ'
AS "Training"
UNION
select PERFORMED_DATE from HHS_UMX_RESP_ACTIVITY where
REG_REQUEST_ID IN ('261507') AND ACTIVITY_RESULT_CODE = 'ARA'
AS "Responsibility"
The only thing changing in each column is the ACTIVITY_RESULT_CODE.
I know that this syntax would not work. Is there a syntax to do this?
My query would grab different data from a specific table, for each different column.
My database output screenshot, which is for this query :
SELECT * FROM HHS_UMX_RESP_ACTIVITY where REG_REQUEST_ID IN ('262050') AND ACTIVITY_RESULT_CODE = 'ASD' AND ROWNUM < 2 :
The user-spreadsheet looks like this :
So columns "Responsibility" / "Supervisor" would each correspond to their own unique value for the column ACTIVITY_RESULT_CODE ( these called "UPA request statuses" - one of SBT, WSP, ASP, WRA, ARA, WTV, ATV ... etc ) :
thanks !
So you want to display information from different rows in the same row of the result set. The standard answer is a join, even if we join the same table:
select
securityRow.REQ_REQUEST_ID,
securityRow.PERFORMED_DATE as securityDate,
trainingRow.PERFORMED_DATE as trainingDate,
responsibilityRow.PERFORMED_DATE as responsibilityDate
from HHS_UMX_RESP_ACTIVITY securityRow
join HHS_UMX_RESP_ACTIVITY trainingRow on trainingRow.REG_REQUEST_ID = securityRow.REG_REQUEST_ID
join HHS_UMX_RESP_ACTIVITY responsibilityRow on responsibilityRow.REQ_REQUEST_ID = securityRow.REG_REQUEST_ID
where securityRow.ACTIVITY_RESULT_CODE = 'ASD'
and trainingRow.ACTIVITY_RESULT_CODE = 'OTZ'
and responsibilityRow.ACTIVITY_RESULT_CODE = 'ARA'
This assumes that there is exactly one row matching for each REQ_REQUEST_ID and ACTIVITY_RESULT_CODE. Otherwise, if there is at most one, you'll want to use outer joins as necessary. If there are several rows, you must restrict the result set to the one you want to use.
You say "For each different column" but there are not different columns. Only different selections on the Activity_result_code.
They syntax you have now, with the exception of the table aliases, would work fine, it's just completely unnecessary. The query you have written could also be written as:
select PERFORMED_DATE
from HHS_UMX_RESP_ACTIVITY
where REG_REQUEST_ID = '261507' AND ACTIVITY_RESULT_CODE IN ('ASD','OTZ','ARA');
GROUP BY PERFORMED_DATE