I need to write a ABAP program using an inner join on the tables mara and makt. I understand the idea of using data declarations like this:
data: imatnr type mara-matnr,
ematnr type makt-matnr.
select mara~matnr makt~matnr into (imatnr, ematnr) from mara left join makt on mara~matnr = makt~matnr.
write: / imatnr, ematnr.
endselect.
In my exams I have to write a ABAP program without internal tables, field symbols JUST TABLES DEKLARATIONS.
I made several attempts to do this but I found no answer.
I tried something like this:
tables: mara, makt.
select * from mara inner join makt on mara~matnr = makt~matnr.
write: / mara-matnr, makt-matnr.
endselect.
The console says that I have to use an INTO if I want to use an JOIN within a select * from statement.
So my question is: Is it possible to build an JOIN only with TABLES or do I need DATA: anyways?
So my question is:
Is it possible to build an JOIN only with tables: mara, makt.
No.
Table is a work area aka flat structure, keyword is flat. You cannot select multiple rows only with TABLES and cannot join TABLES workareas.
BTW, TABLES help guidelines clearly says
No table work areas except for classic dynpros
so forget this obsolete stuff.
If your exams and your learning courses require you to use only TABLES then run away from those course and those school. Please, run away.
P.S. The only way you can fulfill your nasty requirement is nested SELECTs:
TABLES: mara, makt.
SELECT * FROM mara
INTO mara.
WRITE: / `MARA selected: `, mara-matnr.
SELECT *
INTO makt
FROM makt WHERE matnr = mara-matnr.
WRITE: / `MAKT selected: `, makt-matnr.
ENDSELECT.
ENDSELECT.
But that feels disgusting.
Few distinctions between SQL selection queries that might help you.
A generic select statement (without any particular type) looks like this.
Select * from [table] where [field] = [value]
Depending on whether or not and how you specify into clause a certain type of select is used.
into table
into table selects one or multiple records into internal table. can only be used when your select clause (field list) is identical to structure of your internal table.
data: lt_ekko type table of ekko,
ls_ekko type table of ekko,
select * from ekko into table #lt_ekko.
loop at lt_ekko into ls_ekko.
write: / ls_ekko-ebeln.
endloop.
into
into means you are selecting into a variable (if you are selecting 1 column) or a structure (if you are selecting more than 1). This is important, because structures can only and variables only store 1 value or row, which means you must specify that you are selecting a single row or use select/endselect statements to perform looping select.
data: ls_ekko type ekko.
select single * from ekko into #ls_ekko where ebeln = [some number]
write: / ls_ekko-ebeln.
OR
select * from ekko into #ls_ekko where ebeln = [some number].
write: / ls_ekko-ebeln. "will print one for each row
endselect.
into corresponding fields of (table)
into corresponding fields of (and into corresponding fields of table) selects records the same way into and into internal table. The difference is that your structure or internal table does not have to be identical to your selected field list. Selected fields will be stored into your table/structure fields with same names.
data: ls_ekko type ekko.
select single ebeln, bukrs from ekko into #ls_ekko where ebeln = [some number].
write: / ls_ekko-ebeln.
no into clause
no into clause is similar to into [structure], because it can only select 1 record. That means you have to specify that you select a single record.
Note: Tables you are selecting from must be declared in the program to use this type of select.
select single * from ekko where ebeln = [some number].
write: / ekko-ebeln.
Since you are not using into clause, you are using the last type, and that means you must use select single
Related
I have a query which looks a bit like this:
SELECT a~matnr AS material,
b~aedat AS date,
SUM( c~ormng ) AS dummy
INTO TABLE #gt_dummy
FROM ekpo AS a
INNER JOIN ekko AS b
ON b~ebeln = a~ebeln
INNER JOIN lips AS c
ON c~vgbel = a~ebeln
AND c~vgpos = a~ebelp
INNER JOIN likp AS d
ON d~vbeln = c~vbeln
WHERE a~matnr IN #gr_dummy1
AND a~werks IN #gr_dummy2
GROUP BY a~matnr, b~aedat
ORDER BY a~matnr, b~aedat.
It's not going to work because LIPS-VGPOS and EKPO-EBELP have different domains so '00010' in EBELP would be '000010' in VGPOS. An alternative to this would be to just get the EKPO data, use a conversion exit function and then use a FOR ALL ENTRIES query to get the LIPS entries. Then since you can't use SUM and GROUP BY with FOR ALL ENTRIES I would need to do the summations manually.
Of course it's not a huge amount of work to do all this but I'm interested if there's a quicker way to do this e.g. in a single query? Thanks.
EDIT: We're on 7.40
Unfortunately, I only see two possibilities before ABAP 7.50:
FOR ALL ENTRIES as you suggested
Execute "native" SQL directly on the database connected to your ABAP software. This can be done with EXEC SQL or ADBC (class CL_SQL_STATEMENT and so on), or AMDP if your database is HANA.
It's not your version but for ABAP >= 7.50, there are SQL string functions LIKE for instance SUBSTRING:
SELECT a~ebeln, a~ebelp, c~vbeln, c~posnr
FROM ekpo AS a
INNER JOIN lips AS c
ON c~vgbel = a~ebeln
AND substring( c~vgpos, 2, 5 ) = a~ebelp
INTO TABLE #DATA(gt_dummy).
If you have at least ehp5 on 7.40, you can use CDS views in a workaround for FOR ALL ENTRIES with SUM.
Join EKKO and EKPO in OpenSQL
Create a CDS view on LIPS using fields VGBEL, VGPOS, SUM(ORMNG), with GROUP BY on the first two
Call this CDS view with FOR ALL ENTRIES
In the following code :
SELECT ... FROM ... CROSS JOIN TABLE ... WHERE ...;
What does CROSS JOIN TABLE mean ?
I searched on the net, but all I can find is about CROSS JOIN only.
I suppose CROSS JOIN TABLE acts on a table, meaning a table like that :
CREATE OR REPLACE ... AS TABLE OF ...;
Here is the full query :
SELECT prog.id_oct_prog_tran_a_participati, prog.code_ressource, prog.instant_depart, prog.commentaire, prog.en_hors_economie_de_comb, discr.delai, discr.valeur_point, MOD(delai, 60) AS H24
FROM req_prog prog
CROSS JOIN TABLE(POINTS_DISCRETS(pIdChronique=>id_chr_substitution)) discr
WHERE horizon <= 'J1'
AND delai > 0
ORDER BY id_oct_prog_tran_a_participati, instant_depart, horizon, delai
POINTS_DISCRETS is a function that returns an element of type TYPE_TAB_POINT. And TYPE_TAB_POINT is a type that the DBA created as following :
create or replace TYPE "TYPE_TAB_POINT" AS TABLE OF TYPE_POINT;
Where TYPE_POINT is a type created as following :
create or replace TYPE "TYPE_POINT" AS OBJECT
(
ID_CHRONIQUE NUMBER,
HORIZON VARCHAR2(2),
NUM_POINT NUMBER(4),
DELAI NUMBER(5),
VALEUR_POINT FLOAT
);
So, as you see here, CROSS JOIN TABLE acts on a table but not a table as we usually mean in a database, more a table like an array.
Is it the case ? And, if yes, how can it be considered like a real table ?
You're parsing the statement incorrectly, which is confusing you I think. CROSS JOIN TABLE isn't one fragment; it's aCROSS JOIN (but could be any join type) between your real table req_prog and, separately, TABLE(...) to tell the query to treat the return value of the function call as a table.
TABLE(...) is the table collection expression:
The table_collection_expression lets you inform Oracle that the value of collection_expression should be treated as a table for purposes of query and DML operations. The collection_expression can be a subquery, a column, a function, or a collection constructor.
Here POINTS_DISCRETS is the collection constructor - returning TYPE_TAB_POINT, which is a collection, most of which you already figured out.
In this case your collection is a table of objects, and treating it as a table allows you both to join and to refer to the attributes of the object that forms each 'row' as if it were a column. The TABLE() is aliased as discr, so you are able to refer to discr.delai - where delai is one of the attributes of the TYPE_POINT type. If you were using an inner or outer join, rather than a cross join, you would use the same construction in the join condition, e.g. ON discr.x = prog.x. Once you apply the table collection expression you just treat it as a table in the rest of the statement.
So we have a db that receives constant input and then we have it moved after x days to a different db as a type of archive/reporting db. So the question is when I try to create a view that combines two of the tables (one from each db):
CREATE VIEW Table_Full AS
SELECT *
FROM [Front].dbo.[DATA] AS A
Inner Join Back.dbo.DATA AS B
ON A.DATETIME=B.DATETIME
I get the following error: "Column names in each view or function must be unique. Column name 'PARTNO' in view or function 'Table_Full' is specified more than once."
So, is there a better way to accomplish what I am trying to do or ?
Given your use case, I think you want a union. That is
select * from table_a
Union all
Select * from table_b
Instead of an asterisk, you have to specify each field and provide aliases for the duplicate field names:
CREATE VIEW Table_Full AS
SELECT
a.ID as A_ID,
b.ID as B_ID,
a.Thingy as A_Thingy,
a.Etcetera as Atcetera
FROM [Front].dbo.[DATA] AS A
Inner Join Back.dbo.DATA AS B
ON A.DATETIME=B.DATETIME
I'm new to ABAP Development, trying to join T588B and T588T and got this error "for pooled tables cluster tables and projection views join is not allowed: "T588B"".
SELECT a~mandt AS mandt a~userg AS userg a~mntyp AS mntyp a~menue AS menue
a~infty AS infty b~sprsl AS sprsl b~dtext As dtext
INTO CORRESPONDING FIELDS OF TABLE zfinaltable
FROM T588B AS a LEFT JOIN T588T AS b ON a~mntyp = b~mntyp
WHERE a~mntyp = 'I'
I just wanted to join the two table and store the output data into zfinaltable table which is custom table.
Any idea on how to accomplish this join? An example would be really helpful!
From the documentation: "Pooled and cluster tables cannot be joined using join expressions."
http://help.sap.com/abapdocu_731/en/abapselect_join.htm
You need to use a for all entries select instead.
You could try using SELECT. ... ENDSELECT. for selecting the data from table T588B and inside of it reading the data from T588T. An example could look like this. I think it could be easily adapted to your needs.
DATA: ls_T588B TYPE T588B.
DATA: lt_T588T TYPE TABLE OF T588T.
SELECT mntyp menue
FROM T588B
INTO CORRESPONDING FIELDS OF ls_t588b.
SELECT *
FROM T588T
APPENDING TABLE lt_T588T
WHERE MNTYP = ls_t588b-mntyp
AND MENUE = ls_t588b-menue.
ENDSELECT.
I am just new in abap language and I am trying to practice an inner join statement but I don't know how whether I will be able to get the number of rows of my select statement before output.
Here's what I want to achieved.
<--------------------------------------- >
< total number of rows > Record(s) found |
Column Header 1|Column Header 2 ..
< data
....
retrieved >
<--------------------------------------- >
Below is my select statement :
SELECT spfli~carrid scarr~carrname sflight~planetype sflight~fldate sflight~price spfli~cityfrom spfli~cityto
INTO (g_carrid ,g_carrname ,g_planetype,g_fldate ,g_price ,g_cityfrom ,g_cityto) FROM spfli
INNER JOIN sflight
ON spfli~carrid = sflight~carrid AND spfli~connid = sflight~connid
INNER JOIN scarr
ON scarr~carrid = spfli~carrid
WHERE spfli~carrid = s_carrid-low.
WRITE: / g_carrname ,g_planetype,g_fldate ,g_price ,g_cityfrom ,g_cityto.
ENDSELECT.
And if you have any advice and idea on how to do this using internal table, please, show me a sample. I just really want to learn. Thank you and God Bless.
The system variable SY-DBCNT should give you the number of rows selected, but only after the select ends.
The alternative to SELECT-ENDSELECT is to select all the rows at once with SELECT INTO TABLE into an internal table (provided you are not selecting too much at once!).
For example:
data: lt_t000 type table of t000.
select * from t000 into table lt_t000.
This will select everything from that table in one go into the internal table. So what you could do is to declare an internal table with all the fields currently in your INTO clause and then specify INTO TABLE for your internal table.
After the SELECT executes, SY-DBCNT will contain the number of selected rows.
Here is a complete example, built around the SELECT statement in your question, which I have not checked for sanity, so I hope it works!
tables: spfli.
select-options: s_carrid for spfli-carrid.
* Definition of the line/structure
data: begin of ls_dat,
carrid type s_carr_id,
carrname type s_carrname,
planetype type s_planetye,
fldate type s_date,
price type s_price,
cityfrom type s_from_cit,
cityto type s_to_city,
end of ls_dat.
* Definition of the table:
data: lt_dat like table of ls_dat.
* Select data
select spfli~carrid scarr~carrname sflight~planetype sflight~fldate sflight~price spfli~cityfrom spfli~cityto
into table lt_dat
from spfli
inner join sflight
on spfli~carrid = sflight~carrid and spfli~connid = sflight~connid
inner join scarr
on scarr~carrid = spfli~carrid
where spfli~carrid = s_carrid-low.
* Output data
write: 'Total records selected', sy-dbcnt.
loop at lt_dat into ls_dat.
write: / ls_dat-carrid, ls_dat-carrname, ls_dat-planetype, ls_dat-fldate, ls_dat-price, ls_dat-cityfrom, ls_dat-cityto.
endloop.
Note: Report (type 1) programs still support the notion of declaring internal tables with header lines for backward compatibility, but this is not encouraged! Hope it works!
If you only need row count without retrieving data itself the following syntax works as well
SELECT COUNT(*)
FROM spfli
INNER JOIN sflight
...
After execution of this query you will be able to get row count value from SY-DBCNT and DB load will be much less than during usual SELECT ... INTO itab.
This is, however, true only if you don't need actual data. If you need both row count and data itself it is not sensible to split this into separate select statement.