I would like to select all EKPO records that don't have an existing posting in MSEG table.
In ABAP SQL this can be done like below:
SELECT ebeln, ebelp FROM ekpo INTO TABLE #DATA(orders)
WHERE NOT EXISTS ( SELECT ebeln FROM mseg
WHERE ebeln = ekpo~ebeln
AND ebelp = ekpo~ebelp ).
The only solution I found is to create 2 CDS views, the first one to select all the orders with a record in MSEG and the second one being the negation of the first. But I would expect a cleaner solution so I wanted to ask here.
Here's how we do it:
define view my_view as
select from ekpo
association[0..1] to mseg
on mseg.ebeln = ekpo.ebeln
and mseg.ebelp = ekpo.ebelp
{
ebeln,
ebelp
}
where mseg.mandt is null
If no entry matching the criteria exists in mseg, all fields of the association will be null. Otherwise, mseg.mandt will never be null.
Related
I want a select with dynamic where conditions in ABAP Syntax.
An SQL Statement would look like this:
SELECT * FROM MCH1 WHERE MATNR IN (...) AND CHARG IN (...)
My approach was to add 2 structures ZMATN_STR and ZCHARG_STR to the dictionary with associated components as line (MATNR, CHARG).
Then create 2 table types with associated line types.
Now im stucked in ABAP because I don't know how to write the where clause.
That's what I have so far:
SELECT *
FROM
mch1
FOR ALL ENTRIES IN #matnrs
WHERE
matnr = #matnrs-matnr
INTO TABLE #DATA(lt_result).
It works for either matnr or charg but not with both of them.
Additional Info
This select happens in a function module where 2 import parameter exists (the 2 table types) - so I cannot just write where in ('xxx', 'yyy')
data lr_matnr type range of matnr.
data lr_charg type range of MCH1-charg.
"Fill lr_matnr and lr_charg...
SELECT * FROM MCH1 WHERE MATNR IN #lr_matnr AND CHARG IN #lr_charg
INTO TABLE #data(lt_result).
Bare with me for a little bit of setup here please.
I have a table MAIN that has a Field/Value representation that looks like this:
I have another table called STORE_FLAG:
I am trying to write a parameterized query for which I will be given one FIELD_ID and one or more IDs from the STORE_FLAG table.
What I need to do is select from the MAIN table ROW_IDs where:
for the given FIELD_ID, the VALUE = 'YES' AND
for the given STORE_FLAG_IDS, ANY of those FIELD_IDs correspond to a VALUE = 'x' in the MAIN table.
Not that this would be a good idea, but I cannot pivot the whole table into a column-based table to then do a traditional where clause.
Example:
Given a Field_Id = 1 and a list of StoreIds = (30,50). I would want to return row_ids 1 and 2. This is because row_id 1 and 2 have a field_id 1 with value 'YES' AND at least one of the field_ids 3 and 5 have a value 'x'. But row_id 3 has a value of null for both field_id 3 and 5 and row_id 4 has a field_id 1 with value = 'NO'.
I was thinking something like this:
SELECT DISTINCT ROW_ID FROM MAIN
WHERE (FIELD_ID = :providedFieldId OR FIELD_ID IN (SELECT FIELD_ID FROM STORE_FLAG WHERE ID IN :providedStoreIdList))
AND (FIELD_VALUE = 'YES' OR FIELD_VALUE = 'x')
which (I think) works, but feels naïve to me..? I feel like there is some sort of super duper grouping way to do this, but I can't wrap my head around it. Any suggestions would be really appreciated.
here is a way to do this
select distinct m.row_id
from main m
where m.field_id=:providedFieldId
and m.field_value='YES'
and exists (select 1
from STORE_FLAG sf
join main m2
on sf.field_id=m2.field_id
where sf.id in ('30','50') /* you need to bind the values from :providedStoreIdList using a table function*/
and m2.field_value='x'
and m2.row_id=m.row_id
)
link on how to bind an in list
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:110612348061
Your provided solution /query will not work as you say. Because in your last line of query [AND (FIELD_VALUE = 'YES' OR FIELD_VALUE = 'x')] conflict with your requirement . Using your query, you will get ROW_ID if any one is true either FIELD_VALUE = 'YES' OR FIELD_VALUE = 'x'. Which is wrong. You can see below query-
SELECT SUB_QUERY.ROW_ID FROM
(
select DISTINCT MAIN.ROW_ID,MAIN.FIELD_VALUE from STORE_FLAG
RIGHT OUTER JOIN MAIN ON STORE_FLAG.FIELD_ID=MAIN.FIELD_ID
WHERE ((STORE_FLAG.ID IN ('202','203') AND MAIN.FIELD_VALUE='x')
OR (MAIN.FIELD_ID ='1' AND MAIN.FIELD_VALUE='YES'))
) SUB_QUERY
GROUP BY SUB_QUERY.ROW_ID
HAVING (LISTAGG(SUB_QUERY.FIELD_VALUE, ',') WITHIN GROUP (ORDER BY SUB_QUERY.ROW_ID) IN ('YES,x','x,YES'))
I think you need to run and understand my sub query part at first.
I want to select every customer from the table KNA1 which does not have any entry in table KNBK.
So I made a select query which should do this for me:
SELECT-OPTIONS: s_kn_nr FOR kna1-kunnr.
SELECT-OPTIONS: s_kn_okd FOR kna1-ktokd.
SELECT * FROM kna1
INTO TABLE #DATA(ls_kna1)
WHERE kunnr IN #s_kn_nr
AND ktokd IN #s_kn_okd
and kunnr not in ( select kunnr from knbk where kunnr in #s_kr_nr )
Now my question is, does the select query handle empty subselects in the same way as empty select options and just select everything?
The answer is simple: no.
Such a subquery returns a set and IN functions here exactly as the mathematical operation of belonging to set or no. So if the set is empty then no element belongs to it.
I am fairly new to SQL. What I am trying to do is create a view from an existing table. I also need to add a new column to the view which maps to the values of an existing column in the table.
So within the view, if the value in a field for Col_1 = A, then the value in the corresponding row for New_Col = C etc
Does this even make sense? Would I use the CASE clause? Is mapping in this way even possible?
Thanks
The best way to do this is to create a mapping or lookup table
For example consider the following LOOKUP table.
COL_A NEW_VALUE
---- -----
A C
B D
Then you can have a query like this:
SELECT A.*, LOOK.NEW_VALUE
FROM TABLEA AS A
JOIN LOOKUP AS LOOK ON A.COL_A = LOOK.COL_A
This is what DimaSUN is doing in his query too -- but in his case he is creating the table dynamically in the body of the query.
Also note, I'm using a JOIN (which is an inner join) so only results in the lookup table will be returned. This could filter the results. A LEFT JOIN there would return all data from A but some of the new columns might be null.
Generally, a view is an instance of a table/a replica provided that there is no alteration to the original table. So, as per your query you can manipulate the data and columns in a view by using case.
Create View viewname as
Select *,
case when column=a.value then 'C'
....
ELSE
END
FROM ( Select * from table) a
If You have restricted list of replaced values You may hardcode that list in query
select T.*,map.New_Col
from ExistingTable T
left join (
values
('A','C')
,('B','D')
) map (Col_1,New_Col) on map.Col_1 = T.Col_1
In this sample You hardcode 'A' -> 'C' and 'B' -> 'D'
In general case You better may to use additional table ( see Hogan answer )
To join the tables, I am using the following query.
SELECT *
FROM(select user as uservalue1 FROM [projectname.FullData_Edited]) as FullData_Edited
JOIN (select user as uservalue2 FROM [projectname.InstallDate]) as InstallDate
ON FullData_Edited.uservalue1=InstallDate.uservalue2;
The query works but the joined table only has two columns uservalue1 and uservalue2.
I want to keep all the columns present in both the table. Any idea how to achieve that?
#legacySQL
SELECT <list of fields to output>
FROM [projectname:datasetname.FullData_Edited] AS FullData_Edited
JOIN [projectname:datasetname.InstallDate] AS InstallDate
ON FullData_Edited.user = InstallDate.user
or (and preferable)
#standardSQL
SELECT <list of fields to output>
FROM `projectname.datasetname.FullData_Edited` AS FullData_Edited
JOIN `projectname.datasetname.InstallDate` AS InstallDate
ON FullData_Edited.user = InstallDate.user
Note, using SELECT * in such cases lead to Ambiguous column name error, so it is better to put explicit list of columns/fields you need to have in your output
The way around it is in using USING() syntax as in example below.
Assuming that user is the ONLY ambiguous field - it does the trick
#standardSQL
SELECT *
FROM `projectname.datasetname.FullData_Edited` AS FullData_Edited
JOIN `projectname.datasetname.InstallDate` AS InstallDate
USING (user)
For example:
#standardSQL
WITH `projectname.datasetname.FullData_Edited` AS (
SELECT 1 user, 'a' field1
),
`projectname.datasetname.InstallDate` AS (
SELECT 1 user, 'b' field2
)
SELECT *
FROM `projectname.datasetname.FullData_Edited` AS FullData_Edited
JOIN `projectname.datasetname.InstallDate` AS InstallDate
USING (user)
returns
user field1 field2
1 a b
whereas using ON FullData_Edited.user = InstallDate.user gives below error
Error: Duplicate column names in the result are not supported. Found duplicate(s): user
Don't use subqueries if you want all columns:
SELECT *
FROM [projectname.FullData_Edited] as FullData_Edited JOIN
[projectname.InstallDate] as InstallDate
ON FullData_Edited.uservalue1 = InstallDate.uservalue2;
You may have to list out the particular columns you want to avoid duplicate column names.
While you are at it, you should also switch to standard SQL.