Joining various tables using FOR ALL ENTRIES - inner-join

I have created a method for fetching data from tables.
My importing parameters are IV_RCP_NO, IV_VERS, IV_ALT and exporting parameter is ET_TABLE.
Now I am using INNER JOIN for joining 4 tables but the requirement says it should be done using FOR ALL ENTRIES clause.
Can someone please help me out to proceed with it?
Here is my code:
SELECT RCP_TBL~SEARCH_TERM PLNT_TBL~PLANT DESCR_TBL~DESCR RCP_STATUS~DESCR
INTO TABLE ET_TABLE
FROM ESTRH AS ESTRH_TBL
INNER JOIN /PLMB/RCP_RECIPE AS RCP_TBL
ON ESTRH_TBL~RECN = RCP_TBL~SUBRECN
INNER JOIN /PLMB/SAM_NODE_T AS RCP_STATUS
ON RCP_STATUS~STATUS_ID = RCP_TBL~STATUS
INNER JOIN /PLMB/RCP_PLNT AS PLNT_TBL
ON RCP_TBL~RCP_GUID = PLNT_TBL~RCP_GUID
INNER JOIN /PLMB/RCP_DESCR AS DESCR_TBL
ON PLNT_TBL~RCP_GUID = DESCR_TBL~OBJECT_GUID
AND RCP_TBL~RCP_GUID = DESCR_TBL~OBJECT_GUID
WHERE SUBID = IV_RCP_NO AND ALT_NO = IV_ALT AND VERS_NO = IV_VERS.

If the join can be done without for all entries then do that. This will yield best performance.
For all entries is a tool to simplify queries where you already have part of the data in an internal table, from some previously executed code or pre-computation. It effectively results in a series of independent selects whose results are merged after individual completion - meaning this results in multiple database roundtrips, which can drastically worsen performance.
If you have specific requirements to apply the for all entries, you should clarify which part of the data is already there and needs to be joined that way. Otherwise any suggestion from StackOverflowers will remain inefficient guesswork.

You can refer the below code-
* Local structure
TYPES: BEGIN OF ty_estrth,
subid TYPE esesubid,
recn TYPE eserecn,
END OF ty_estrth.
* Internal table
DATA: lt_estrh TYPE STANDARD TABLE OF ty_estrth.
SELECT subid recn FROM estrh
INTO TABLE lt_estrh
WHERE subid = iv_rcp_no.
IF lt_estrh IS NOT INITIAL.
SELECT * FROM /plmb/rcp_recipe
INTO TABLE lt_rcp_recipe "Internal table of type /PLMB/RCP_RECIPE
FOR ALL ENTRIES IN lt_estrh
WHERE subrecn = lt_estrh-recn
AND alt_no = iv_alt AND vers_no = iv_vers.
IF lt_rcp_recipe IS NOT INITIAL.
SELECT * FROM /plmb/sam_node_t
INTO TABLE lt_sam_node_t "Internal table of type /PLMB/SAM_NODE_T
FOR ALL ENTRIES IN lt_rcp_recipe
WHERE status_id = lt_rcp_recipe-status.
SELECT * FROM /plmb/rcp_plnt
INTO TABLE lt_rcp_plnt " Internal table of type /PLMB/RCP_PLNT
FOR ALL ENTRIES IN lt_rcp_recipe
WHERE rcp_guid = lt_rcp_recipe-rcp_guid.
SELECT * FROM /plmb/rcp_descr
INTO TABLE lt_rcp_descr " Internal table of type /PLMB/RCP_DESCR
FOR ALL ENTRIES IN lt_rcp_recipe
WHERE rcp_guid = lt_rcp_recipe-rcp_guid.
ENDIF.
ENDIF.
You'll get your data in below internal tables
lt_rcp_recipe
lt_sam_node_t
lt_rcp_plnt
lt_rcp_descr
Better declare a local structure with specific fields which you want to read, as i declared above. After that you have to read and fill data in exporting table ET_TABLE.

Related

Check if a table exists based on a column value in SQL Server

We have a data collection program that dynamically creates tables for data storage based on the identity value from another table. For example if 15 devices are created then the Devices table would have 15 entries (name, address, etc) and the DeviceID value would be say 134 - 149 then 15 tables would be created called Dev134 through Dev149.
Occasionally an issue occurred where some DEV tables were deleted but the record in the device table was not deleted leaving a orphan entry in the devices table. I.e. there is a DeviceID = 1245, but there is no table Dev1245.
What we would like to do is go through the Devices table and see if there is a corresponding Dev table in the database, and if not list the ID.
I have done this through a separate program, pulling the DeviceID's from the Device table into a list and then doing a
SELECT *
FROM #DeviceID
(#DeviceID = "Dev" + DeviceID)
and if I get something I know it's there and if I return nothing it's missing but I was hoping to do this with a single select statement that would return the ID of the missing tables.
You can select table information from sys.tables:
https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-tables-transact-sql?view=sql-server-ver16
This statement should give you all entries which misses the corresponding table:
SELECT [devices].*
FROM Devices AS [devices]
LEFT JOIN sys.tables AS [tables]
ON [devices].[name] = [tables].[name]
WHERE [tables].[name] IS NULL
SELECT 'Dev'+CAST(deviceId AS VARCHAR(10))
FROM devices
WHERE NOT EXISTS (SELECT * FROM sys.tables WHERE name='Dev'+CAST(deviceId AS VARCHAR(10)));
Here is DBFiddle demo

Updating column based on three tables

I know it's very unprofessional, but it's our business system so I can't change it.
I have three tables: t_posList, t_url, t_type. The table t_posList has a column named URL which is also stored in the table t_url (the ID of the table t_url is not saved in t_posList so I have to find it like posList.Url = t_url.Url).
The column t_posList.status of every data row should be updated to 'non-customer' (it will be a status id but lets keep it simple) if: the ID of t_url can NOT be found in t_type.url_id.
So the query has like two steps: first I have to get all of the data rows where t_posList.Url = t_url.Url. After this I have to check which ID's of the found t_url rows can NOT be found in t_type.url_id.
I really hope you know what I mean. Because our system is very unprofessional and my SQL knowledge is not that good I'm not able to make this query.
EDIT: I tried this:
UPDATE t_poslist SET status = (
SELECT 'non-customer'
FROM t_url, t_type
WHERE url in
(select url from t_url
LEFT JOIN t_type ON t_url.ID = t_type.url_id
WHERE t_type.url_id is null)
)
What about this?
UPDATE p
SET status = 'non-customer'
FROM t_poslist p
INNER JOIN t_url u ON u.url = p.url
WHERE NOT EXISTS
(
SELECT * FROM t_type t WHERE t.url_id = u.ID
)

Multi join issue

*EDIT** Thanks for all the input, and sorry for late reply. I have been away during the weekend without access to internet. I realized from the answers that I needed to provide more information, so people could understand the problem more throughly so here it comes:
I am migrating an old database design to a new design. The old one is a mess and very confusing ( I haven't been involved in the old design ). I've attached a picture of the relevent part of the old design below:
The table called Item will exist in the new design as well, and it got all columns that I need in the new design as well except one and it is here my problem begin. I need the column which I named 'neededProp' to be associated( with associated I mean like a column in the new Item table in the new design) with each new migrated row from Item.
So for a particular eid in table Environment there can be n entries in table Item. The "corresponding" set exists in table Room. The only way to know which rows that are associated in Item and Room are with the help of the columns "itemId" and "objectId" in the respective table. So for example for a particular eid there might be 100 entries in Item and Room and their "itemId" and "objectId" can be values from 1 to 100, so that column is only unique for a particular eid ( or baseSeq which it is called in table BaseFile).
Basically you can say that the tables Environment and BaseFile reminds of each other and the tables Item and Room reminds of each other. The difference is that some tables lack some columns and other may have some extra. I have no idea why it is designed like this from the beginning.
My question is if someone can help me with creating a query so that I can be able to find out the proper "neededProp" for each row in the Item-table so I can get that data into the new design?
*OLD-PART**This might be a trivial question but I can't get it to work as I want. I want to join a few tables as in the sql-statement below. If I start like this and run this query
select * from Environment e
join items ei on e.eid = ei.eid
I get like 400000 rows which is what I want. However if I add one more line so it looks like this:
select * from Environment e
join items ei on e.eid= ei.eid
left join Room r on e.roomnr = r.roomobjectnr
I get an insane amount of rows so there must be some multiplication going on. I want to get the same amount of rows ( like 400000 in this case ) even after joining the third table. Is that possible somehow? Maybe like creating a temporary view with the first 2 rows.
I am using MSSQL server.
So without knowing what data you have in your second query it's very difficult to say exactly how to write this out, and you're likely having a problem where there's an additional column that you are joining to in Rooms that perhaps you have forgotten such as something indicating a facility or hallway perhaps where you have multiple 'Room 1' entries as an example.
However, to answer your question regarding another way to write this out without using a temp table I've crufted up the below as an example of using a common table expression which will only return one record per source row.
;WITH cte_EnvironmentItems AS (
SELECT *
FROM Environment E
INNER JOIN Items I ON I.eid = E.eid
), cte_RankedRoom AS (
SELECT *
,ROW_NUMBER() OVER (ORDER BY R.UpdateDate DESC) [RN]
FROM Room R
)
SELECT *
FROM cte_EnvironmentItems E
LEFT JOIN cte_RankedRoom R ON E.roomnr = R.roomobjectnr
AND R.RN = 1
btw,do you want column from room table.if no then
select * from Environment e
join items ei on e.eid= ei.eid
where e.roomnr in (select r.roomobjectnr from Room r )
else
select * from Environment e
join items ei on e.eid= ei.eid
left join (select distinct roomobjectnr from Room) r on e.roomnr = r.roomobjectnr

Merge statement for stocks using three tables

Here is the SQL Query:
MERGE tblProductsSold
USING tblOrders on tblOrders.OrderID = tblProductsSold.txtOrderID
WHEN NOT MATCHED THEN
Insert ( txtOrderID, txtOrderdate, txtPartno, txtQty)
values
(SELECT tblItemsOnOrder.txtOrderID,
tblOrders.txtDateTime,
tblItemsOnOrder.txtPartNO,
tblItemsOnOrder.txtQTY
FROM tblOrders INNER JOIN tblItemsOnOrder
ON tblOrders.OrderID = tblItemsOnOrder.txtOrderID
WHERE tblOrders.txtIsConfirmed = '1'
)
OUTPUT $action ;
Desired Result: need to import orders with Products that are not already in the tblProductsSold table
You cannot approach it like you are doing it right now.
The MERGE statement merges two tables - the two tables you define in the header - the source table and the target table.
Right now, you're using tblOrders as your source, and tblProducts as your target. That alone seems odd - you're trying to merge orders into products? Doesn't seem very fitting...
Once you've defined your source and target table - you stat comparing which rows from the source are present in the target (or not). If a given row from your source is not present in the target - then you can insert its values into the target table.
But that only works for direct column values from the source table! You cannot go out and do subqueries into other tables as you're trying to do!
So I believe what you really should do is this:
as your source - have a view that lists the products found in your orders - the products (not the orders per se)
then compare your Products table to this view - if your orders happen to have any products that aren't present in the base Products table - insert them.
So you'd need something like:
MERGE tblProductsSold AS Target
USING (SELECT tblItemsOnOrder.txtOrderID, tblOrders.txtDateTime,
tblItemsOnOrder.txtPartNO, tblItemsOnOrder.txtQty
FROM tblOrders
INNER JOIN tblItemsOnOrder ON tblOrders.OrderID = tblItemsOnOrder.txtOrderID
WHERE tblOrders.txtIsConfirmed = '1') AS Source
ON Source.OrderID = Target.txtOrderID
WHEN NOT MATCHED THEN
INSERT (txtOrderID, txtOrderdate, txtPartno, txtQty)
VALUES (Source.OrderID, Source.txtDateTime, Source.txtPartNo, Source.txtQty)
OUTPUT $action ;

SQL - Updating multiple records for each record with a matching id in a table

I am bit new on the updating multiple records and i wanted to know the best way to go on about a solution for this, i am writing a stored proc were basically i have two tables,
one that matches a server id to a user id
and another table with record information for each user id with multiple columns with values.
Basically here is how its going to work:
Get all the matching user ids for the specific server id in the tb_UserServerMap table
then foreach userId in the tb_setting table update the columns with the new values
Basic structure of your stored procedure would be:
CREATE PROCEDURE Blah
#Server_ID int /* or whatever data type is appropriate */
as
UPDATE ts
SET
ColumnA = 10 /* New value for column A - maybe passed as a parameter? */
/* More columns here */
FROM
tb_setting ts
inner join
tb_UserServerMap usm
on
ts.user_id = usm.user_id
WHERE
usm.server_id = #Server_ID
I can't fill in more of it without knowing the names of columns to be updated, how those values are obtained, data types, etc.
You don't need a foreach,
Update tblName set firstCol = val1, secondCol = val2 where id in (id1, id2, id3)

Resources