Joining WIP_DISCRETE_JOBS to a Bill Of Materials table - sql

I have an SQL query in which I am trying to fetch items along with their components which have Bill Of Materials (BOM) enabled and whose creation date is withing the last three years.
The problem is every item along with their component list gets repeated. Suppose an item has 5 components, and I query with the particular item number. I get 35 rows (7 repetitions of sets of 5 components). However, if I query with a particular WIP_ENTITY_NAME or if I use DISTINCT, I get a perfect 5 rows of data. I need to get this data (5 rows, no repetitions) when I query with a particular item number.
Here is the query:
SELECT *
FROM BOM_BILL_OF_MATERIALS BOM,
BOM_INVENTORY_COMPONENTS BIC,
BOM_COMPONENTS_B BCB,
BOM_OPERATIONAL_ROUTINGS_V BORV,
BOM_OPERATION_SEQUENCES_V BOSV,
BOM_STRUCTURES_B BSB,
BOM_STRUCTURE_TYPES_B BST,
MTL_SYSTEM_ITEMS_B MSI,
MTL_SYSTEM_ITEMS_TL MSIT,
ORG_ORGANIZATION_DEFINITIONS OOD,
WIP_DISCRETE_JOBS_V WDJV
WHERE BOM.BILL_SEQUENCE_ID = BIC.BILL_SEQUENCE_ID
AND BIC.COMPONENT_SEQUENCE_ID = BCB.COMPONENT_SEQUENCE_ID
AND BCB.BILL_SEQUENCE_ID = BSB.BILL_SEQUENCE_ID
AND BOM.STRUCTURE_TYPE_ID = BST.STRUCTURE_TYPE_ID
AND BOM.ASSEMBLY_ITEM_ID = MSI.INVENTORY_ITEM_ID
AND BOM.ORGANIZATION_ID = MSI.ORGANIZATION_ID
AND BOSV.ROUTING_SEQUENCE_ID = BORV.ROUTING_SEQUENCE_ID
AND BORV.ASSEMBLY_ITEM_ID = BOM.ASSEMBLY_ITEM_ID
AND BORV.ORGANIZATION_ID = BOM.ORGANIZATION_ID
AND MSI.INVENTORY_ITEM_ID = MSIT.INVENTORY_ITEM_ID
AND MSI.ORGANIZATION_ID = MSIT.ORGANIZATION_ID
AND MSIT.ORGANIZATION_ID = OOD.ORGANIZATION_ID
AND MSIT.LANGUAGE = USERENV('LANG')
AND sysdate BETWEEN BCB.EFFECTIVITY_DATE AND NVL(BCB.DISABLE_DATE, sysdate)
AND MSI.BOM_ENABLED_FLAG = 'Y'
AND NVL(MSI.ENABLED_FLAG,'X') ='Y'
AND OOD.ORGANIZATION_ID IN (203,204,328)
AND BORV.COMMON_ROUTING_SEQUENCE_ID = WDJV.COMMON_ROUTING_SEQUENCE_ID
AND BORV.ASSEMBLY_ITEM_ID = WDJV.PRIMARY_ITEM_ID
AND WDJV.CREATION_DATE > ADD_MONTHS( sysdate, -12*3 )
AND WDJV.WIP_ENTITY_NAME = '28799'
--and MSI.SEGMENT1='9064090'
Also, I have found that the sets of 5 differ from each other on the basis of their WE_ROW_ID, REQUEST_ID_7, SCHEDULED_START_DATE, SCHEDULED_COMPLETION_DATE and other columns which are present in the WIP_DISCREET_JOBS table. Is there any way to map these columns to any of the BOM tables? I am new to this, so please bear with me gurus.

I see you are asking about the Oracle e-Business Suite data model.
trying to fetch items ... and whose creation date is withing the last three years.
That is not what your query is doing. You are getting details of items made (via a WIP discrete job) within the last 3 years -- and you are getting a duplicate of the item for every time it was made (i.e., every occurrence in WIP_DISCRETE_JOBS_V).
If you want items made in the last 3 years, but you only want each item once, you should use an EXISTS (semi-join) to filter the rows instead of actually joining to WIP_DISCRETE_JOBS_V, which will cause duplicates). Something more along these lines:
SELECT *
FROM bom_bill_of_materials bom,
bom_inventory_components bic,
bom_components_b bcb,
bom_operational_routings_v borv,
bom_operation_sequences_v bosv,
bom_structures_b bsb,
bom_structure_types_b bst,
mtl_system_items_b msi,
mtl_system_items_tl msit,
org_organization_definitions ood --,
--wip_discrete_jobs_v wdjv
WHERE bom.bill_sequence_id = bic.bill_sequence_id
AND bic.component_sequence_id = bcb.component_sequence_id
AND bcb.bill_sequence_id = bsb.bill_sequence_id
AND bom.structure_type_id = bst.structure_type_id
AND bom.assembly_item_id = msi.inventory_item_id
AND bom.organization_id = msi.organization_id
AND bosv.routing_sequence_id = borv.routing_sequence_id
AND borv.assembly_item_id = bom.assembly_item_id
AND borv.organization_id = bom.organization_id
AND msi.inventory_item_id = msit.inventory_item_id
AND msi.organization_id = msit.organization_id
AND msit.organization_id = ood.organization_id
AND msit.language = USERENV ('LANG')
AND SYSDATE BETWEEN bcb.effectivity_date AND NVL (bcb.disable_date, SYSDATE)
AND msi.bom_enabled_flag = 'Y'
AND NVL (msi.enabled_flag, 'X') = 'Y'
AND ood.organization_id IN (203, 204, 328)
--AND borv.common_routing_sequence_id = wdjv.common_routing_sequence_id
--AND borv.assembly_item_id = wdjv.primary_item_id
--AND wdjv.creation_date > ADD_MONTHS (SYSDATE, -12 * 3)
--AND wdjv.wip_entity_name = '28799'
AND EXISTS ( SELECT 'discrete job within the last 3 years'
FROM wip_discrete_jobs_v wdjv
WHERE wdjv.common_routing_sequence_id = borv.common_routing_sequence_id
AND wdjv.primary_item_id = borv.assembly_item_id
AND wdjv.creation_date >= ADD_MONTHS(SYSDATE, -12*3)
)
--and MSI.SEGMENT1='9064090'
Note -- I kept this as close to your original query as possible and I didn't verify all the join conditions you used. So there may be some other bugs in your initial query that I have inadvertently duplicated.
One other thing, it's not a good practice to use the forms views, like WIP_DISCRETE_JOBS_V or BOM_OPERATIONAL_ROUTINGS_V. These views are to provide data to online forms. Not only can your performance suffer (because they contain joins that you may not need), but, if you go to Oracle's eTRM site (http://etrm.oracle.com/pls/etrm/etrm_pnav.show_object?c_name=BOM_OPERATIONAL_ROUTINGS_V&c_owner=APPS&c_type=VIEW), you will see this warning:
Warning: Oracle does not recommend you query or alter datausing this
view. It may change dramatically in subsequent minor or major
releases.
It is better to SELECT from the base tables.

Related

SQL GROUP BY function returning incorrect SUM amount

I've been working on this problem, researching what I could be doing wrong but I can't seem to find an answer or fault in the code that I've written. I'm currently extracting data from a MS SQL Server database, with a WHERE clause successfully filtering the results to what I want. I get roughly 4 rows per employee, and want to add together a value column. The moment I add the GROUP BY clause against the employee ID, and put a SUM against the value, I'm getting a number that is completely wrong. I suspect the SQL code is ignoring my WHERE clause.
Below is a small selection of data:
hr_empl_code hr_doll_paid
1 20.5
1 51.25
1 102.49
1 560
I expect that a GROUP BY and SUM clause would give me the value of 734.24. The value I'm given is 211461.12. Through troubleshooting, I added a COUNT(*) column to my query to work out how many lines it's running against, and it's giving a result of 1152, furthering reinforces my belief that it's ignoring my WHERE clause.
My SQL code is as below. Most of it has been generated by the front-end application that I'm running it from, so there is some additional code in there that I believe does assist the query.
SELECT DISTINCT
T000.hr_empl_code,
SUM(T175.hr_doll_paid)
FROM
hrtempnm T000,
qmvempms T001,
hrtmspay T166,
hrtpaytp T175,
hrtptype T177
WHERE 1 = 1
AND T000.hr_empl_code = T001.hr_empl_code
AND T001.hr_empl_code = T166.hr_empl_code
AND T001.hr_empl_code = T175.hr_empl_code
AND T001.hr_ploy_ment = T166.hr_ploy_ment
AND T001.hr_ploy_ment = T175.hr_ploy_ment
AND T175.hr_paym_code = T177.hr_paym_code
AND T166.hr_pyrl_code = 'f' AND T166.hr_paid_dati = 20180404
AND (T175.hr_paym_type = 'd' OR T175.hr_paym_type = 't')
GROUP BY T000.hr_empl_code
ORDER BY hr_empl_code
I'm really lost where it could be going wrong. I have stripped out the additional WHERE AND and brought it down to just T166.hr_empl_code = T175.hr_empl_code, but it doesn't make a different.
By no means am I any expert in SQL Server and queries, but I have decent grasp on the technology. Any help would be very appreciated!
Group by is not wrong, how you are using it is wrong.
SELECT
T000.hr_empl_code,
T.totpaid
FROM
hrtempnm T000
inner join (SELECT
hr_empl_code,
SUM(hr_doll_paid) as totPaid
FROM
hrtpaytp T175
where hr_paym_type = 'd' OR hr_paym_type = 't'
GROUP BY hr_empl_code
) T on t.hr_empl_code = T000.hr_empl_code
where exists
(select * from qmvempms T001,
hrtmspay T166,
hrtpaytp T175,
hrtptype T177
WHERE T000.hr_empl_code = T001.hr_empl_code
AND T001.hr_empl_code = T166.hr_empl_code
AND T001.hr_empl_code = T175.hr_empl_code
AND T001.hr_ploy_ment = T166.hr_ploy_ment
AND T001.hr_ploy_ment = T175.hr_ploy_ment
AND T175.hr_paym_code = T177.hr_paym_code
AND T166.hr_pyrl_code = 'f' AND T166.hr_paid_dati = 20180404
)
ORDER BY hr_empl_code
Note: It would be more clear if you have used joins instead of old style joining with where.

SQL Most recently updated row

I am pulling information from an SQL database but it displays all lines various times because of multiple updates.
i have managed to eliminate duplicate using the distinct function however still shows multiple lines for the changes.
i.e.
original Qty = 4
update 1 Qty = 5
update 2 Qty = 6
All i want is the most recent update each line which is column OLLNID
SELECT DISTINCT
OLMCU,
OLKCOO,
OLDOCO,
OLDCTO,
Date( OLTRDJ, CYYDDD ) AS OLTRDJ,
OLLNID AS OLLNID_1,
OLDSC1,
OLDSC2 AS OLDSC2_1,
OLUOM,
OLUORG,
OLPRRC,
OLAEXP,
OLANBY
FROM
E1PDES01.PRODDTA.F43199 F43199
WHERE
OLMCU = '13248'
AND Date( OLTRDJ, CYYDDD ) >= '01/01/2017'
AND OLDCTO = 'OP'
AND OLDOCO = 13484379
ORDER BY
6
Like subkonstrukt I am guessing what you really want.
In case that you want the latest results by OLLNID (which is then e.g. a date), then you could group by all other values (when they differ) and choose the max OLLNID.
SELECT
OLMCU,
OLKCOO,
OLDOCO,
OLDCTO,
Date(OLTRDJ, CYYDDD) AS OLTRDJ,
MAX(OLLNID) AS OLLNID_1,
OLDSC1,
OLDSC2 AS OLDSC2_1,
OLUOM,
OLUORG,
OLPRRC,
OLAEXP,
OLANBY
FROM E1PDES01.PRODDTA.F43199 F43199
WHERE OLMCU = '13248'
AND Date(OLTRDJ, CYYDDD) >= '01/01/2017'
AND OLDCTO = 'OP'
AND OLDOCO = 13484379
GROUP BY
OLMCU,
OLKCOO,
OLDOCO,
OLDCTO,
OLTRDJ,
OLDSC1,
OLDSC2,
OLUOM,
OLUORG,
OLPRRC,
OLAEXP,
OLANBY;
depending on what SQL Flavor you´re using this might not work, also I am made some wild assumptions on your data so if you could supply more information (maybe schema / types, SQL Flavor, maybe two or three dummy rows) I will edit my answer
SELECT
org.OLMCU,
org.OLKCOO,
org.OLDOCO,
org.OLDCTO,
Date(org.OLTRDJ, CYYDDD ) AS OLTRDJ,
org.OLLNID AS OLLNID_1,
org.OLDSC1,
org.OLDSC2 AS OLDSC2_1,
org.OLUOM,
org.OLUORG,
org.OLPRRC,
org.OLAEXP,
org.OLANBY
FROM
E1PDES01.PRODDTA.F43199 F43199 as org
LEFT OUTER JOIN E1PDES01.PRODDTA.F43199 F43199 aux ON org.OLLNID = aux.OLLNID AND org.OLLNID < aux.OLLNID
WHERE
org.OLMCU = '13248'
AND Date( org.OLTRDJ, CYYDDD ) >= '01/01/2017'
AND org.OLDCTO = 'OP'
AND org.OLDOCO = 13484379
AND aux.OLLNID IS NULL
GROUP BY
org.OLMCU,
org.OLKCOO,
org.OLDOCO,
org.OLDCTO,
Date(org.OLTRDJ, CYYDDD ) AS OLTRDJ,
org.OLLNID AS OLLNID_1,
org.OLDSC1,
org.OLDSC2 AS OLDSC2_1,
org.OLUOM,
org.OLUORG,
org.OLPRRC,
org.OLAEXP,
org.OLANBY
ORDER BY org.OLLNID

Missing or incorrect data in Oracle EBS backend query (SQL)

I am learning Oracle E-Business Suite. Using an SQL Query, I want to fetch all items (ASSEMBLY_ITEM) which are BOM enabled and whose job creation date is within the last 3 years. The query I have written gives me the desired results but somehow, the component item list (COMPONENT_ITEM) has incomplete data or (Null) for some items. For example, some items which I know has 5 components but in the SQL query output, that same item shows up as having a single component. I am verifying the data from the Oracle Apps frontend part.
Here is my query so far:
SELECT DISTINCT BOM.BILL_SEQUENCE_ID,
MSI.ORGANIZATION_ID,
MSI.SEGMENT1 ASSEMBLY_ITEM,
(SELECT SEGMENT1
FROM MTL_SYSTEM_ITEMS_B
WHERE INVENTORY_ITEM_ID=BIC.COMPONENT_ITEM_ID
AND rownum =1
) "COMPONENT_ITEM"
FROM BOM_OPERATIONAL_ROUTINGS BOR,
BOM_BILL_OF_MATERIALS BOM,
BOM_INVENTORY_COMPONENTS BIC,
MTL_SYSTEM_ITEMS_B MSI
WHERE BOR.ASSEMBLY_ITEM_ID = BOM.ASSEMBLY_ITEM_ID
AND BOR.ORGANIZATION_ID = BOM.ORGANIZATION_ID
AND BOM.BILL_SEQUENCE_ID = BIC.BILL_SEQUENCE_ID(+)
AND BOM.ASSEMBLY_ITEM_ID = MSI.INVENTORY_ITEM_ID(+)
AND BOM.ORGANIZATION_ID = MSI.ORGANIZATION_ID
AND MSI.ORGANIZATION_ID IN (203, 204, 328)
AND MSI.BOM_ENABLED_FLAG = 'Y'
AND NVL (MSI.ENABLED_FLAG, 'X') = 'Y'
AND BOR.ASSEMBLY_ITEM_ID IN
(SELECT DISTINCT PRIMARY_ITEM_ID
FROM WIP_DISCRETE_JOBS WDJ
WHERE BOR.ASSEMBLY_ITEM_ID = WDJ.PRIMARY_ITEM_ID
AND WDJ.CREATION_DATE >= ADD_MONTHS(SYSDATE, -12*3)
)
My query should return unique assembly items, each of which may have one or more components.
Ideally, I should be getting , all unique assembly items along with their component items. I have achieved this by removing the join on BOM.BILL_SEQUENCE_ID = BIC.BILL_SEQUENCE_ID (+), and also removing the semi-join at the end of the query, the "AND BOR.ASSEMBLY_ITEM_ID IN" part, which essentially filters the results since the last 3 years.
The join part isn't the real issue. Is there any way to filter the result based on items created in the last 3 years, using something other than this method?
What am I missing here?
There are several things you could do better here.
First, use ANSI JOINS. I see at least some of your problems are due to incorrect attempt as LEFT OUTER joins. Using the ANSI syntax will help you avoid such problems.
Second, don't use DISTINCT unless you understand WHY it is necessary. It should not be necessary to write the query you say you want.
Third, You don't need to join BOM_OPERATIONAL_ROUTINGS -- you're not using it for anything (unless you are trying to use it as a filter -- to limit to BOMs that have a routing?)
Fourth, use EXISTS instead of IN. Oracle's optimizer is mostly smart enough to protect you from the performance penalty that IN would have hit you with in the past. Nevertheless, EXISTS better represents your intent (imo) and places less reliance on the optimizer being smart.
Finally, the ROWNUM=1 to get the component item isn't necessary. You just need to limit by ORGANIZATION_ID as well.
Putting it all together, the following query should be pretty close to what you are looking for:
SELECT bom.bill_sequence_id,
bom.organization_id,
msi.segment1 assembly_item_id,
bic.operation_seq_num,
msic.segment1 component_item
FROM bom_bill_of_materials bom
LEFT JOIN mtl_system_items msi
ON msi.organization_id = bom.organization_id
AND msi.inventory_item_id = bom.assembly_item_id
AND msi.enabled_flag = 'Y'
AND msi.bom_enabled_flag = 'Y'
LEFT JOIN bom_inventory_components bic ON bic.bill_sequence_id = bom.common_bill_sequence_id
LEFT JOIN mtl_system_items msic
ON msic.organization_id = bom.organization_id
AND msic.inventory_item_id = bic.component_item_id
WHERE bom.organization_id IN (203, 204, 328)
AND EXISTS
(SELECT 'job for item in last 3 years'
FROM wip_discrete_jobs wdj
WHERE wdj.primary_item_id = bom.assembly_item_id
AND wdj.creation_date >= ADD_MONTHS (SYSDATE, -36))
-- Unless you are loading a table with this, you may want to ORDER BY...
;

Set One Column Equal to Another In Different Tables

I am fairly new to SQL, and I am trying to create an SQL command checks if something is equal to something in one table, then update the value of something in another table. I have looked for solutions online, but I am not quite good enough to determine if what I have seen can be used to accomplish what I want to accomplish.
So here are the actual names of the tables and columns I am working with:
Item (Uses "ID")
SaleType (int, not null)
nitroasl_pamtable (Uses "ItemID")
PAM_SpecialOffer (bit, not null)
The "ID" that is shared between products in both tables are as follows:
- The "ID" column in the "Item" table
- The "ItemID" column in the "nitroasl_pamtable" table
What I need to do is go through the "Item" table and find all products that have "SaleType" equals "1"- Then update those IDs in "nitroasl_pamtable" by setting "PAM_SpecialOffer" equal to "1".
Is the following able to do what I want (this is a very rough guess btw)?
UPDATE nitroasl_pamtable
SET PAM_SpecialOffer = SaleType
FROM Item
INNER JOIN nitroasl_pamtable
ON ID = ItemID
WHERE SaleType = 1
I hope that the above makes sense, as I have found it a little hard to put into words, but in a nutshell, I am trying to mark all products with "SaleType=1" with "PAM_SpecialOffer=1" across the two different tables using "ID" and "ItemID" (respectively).
UPDATE
So, the following got me a listing of the set that I want to change. The IDs match up perfectly, etc. Now how can I UPDATE the PAM_SpecialOffer column with "1" (how do I change the following code to do this)?
SELECT i.ID, i.SaleType, i.SaleStartDate, i.SaleEndDate, i.ItemLookupCode, n.ItemID, n.PAM_SpecialOffer
FROM Item AS i
JOIN nitroasl_pamtable AS n
ON i.ID = n.ItemID
WHERE i.SaleType = 1
and (i.SaleStartDate > '2015-01-01' or i.SaleStartDate = '1899-12-31')
and i.SaleEndDate > getdate();
It would appear that your statement would work. However, I would write it as:
UPDATE pt
SET PAM_SpecialOffer = i.SaleType
FROM nitroasl_pamtable pt INNER JOIN
Item i
ON i.ID = pt.ItemID
WHERE i.SaleType = 1;
The i and pt are table aliases, abbreviations for the table name. In some cases, they are necessary. Here, they just clarify what the query is doing and where the columns are coming from.
As a rule, when I do an update with join, I put the table being updated first in the list of joins.
Here is what I ended up with. I do need to mark all products that do not receive the PAM_SpecialOffer = 1 update with PAM_SpecialOffer = NULL, but that should be easy enough!
UPDATE n
SET n.PAM_SpecialOffer = 1
FROM Item AS i
JOIN nitroasl_pamtable AS n
ON i.ID = n.ItemID
WHERE i.SaleType = 1
and (i.SaleStartDate > '2015-01-01' or i.SaleStartDate = '1899-12-31')
and i.SaleEndDate > getdate();
UPDATE - Final Revision
So I made some additional modifications to my query. I am sure there is a better way to write this, but this is the best I could do as far as cleaning up the non-valid 'PAM_SpecialOffer = 1' rows. Tested with a backup of our DB- works great! I'm gonna set this to run every few minutes on our DB.
/* Mark appropriate Sale items as 'PAM_SpecialOffer = 1' */
UPDATE n
SET n.PAM_SpecialOffer = 1
FROM Item AS i
JOIN nitroasl_pamtable AS n
ON i.ID = n.ItemID
WHERE i.SaleType >= 1
and (i.SaleStartDate >= '2015-04-01' or i.SaleStartDate = '1899-12-31')
and i.SaleEndDate >= getdate();
/* Cleanup 'PAM_SpecialOffer' */
UPDATE n
SET n.PAM_SpecialOffer = NULL
FROM Item AS i
JOIN nitroasl_pamtable AS n
ON i.ID = n.ItemID
WHERE i.SaleType < 1
or (i.SaleStartDate < '2015-04-01' and i.SaleStartDate <> '1899-12-31')
or i.SaleEndDate < getdate();

Differential Data Merge is complex? How to get results?

I am looking at an old stored procedure that's job is to preserve the New sort order based on yesterday's and today's data.
Sort orders are not being preserved any longer and I have narrowed it down to the WHERE clause eliminating all rows. The main goal is to preserve the SortOrder so if some custom data was in position 4 yesterday, any NEW custom data that takes its place should ALSO have position 4.
If I eliminate
--AND b.PrimaryID = b.SortOrder
then I get thousands of rows. I suspect something is wrong but it I am not understanding. How can I make this simpler so it is REALLY easy to understand?
IMPORTANT: the SortOrder actually equals the PrimaryID if the data is no longer sorted. Otherwise it is incremental 1 2 3 4 5 6 7 .. and so on. I guess this was the original architects way of doing it.
-- Merge data and get missing rows that have not changed.
SELECT
PrevPrimaryID = a.PrimaryID
,a.WidgetID
,a.AnotherValue
,a.DataID
,PrevSortOrder = a.SortOrder
,NewPrimaryID = b.PrimaryID
,NewDataID = b.DataID
,NewStartDate = b.StartDate
,NewSortOrder = b.SortOrder
INTO #NewOrder2
FROM #YesterdaysData2 a
LEFT JOIN #TodaysData2 b ON a.WidgetID = b.WidgetID
AND a.AnotherValue = b.AnotherValue
WHERE
a.Primaryid <> a.sortorder
AND b.PrimaryID = b.SortOrder
SELECT * FROM #NewOrder2
-- later update based on #NewOrder2...
UPDATE CustomerData
SET SortOrder = (
SELECT PrevSortOrder
FROM #NewOrder2
WHERE CustomerData.PrimaryID = #NewOrder2.NewPrimaryID
)
WHERE PrimaryID IN (
SELECT NewPrimaryID
FROM #NewOrder2
)
UPDATE - Is it possible its just a blunder and the WHERE clause should be
WHERE a.Primaryid <> a.sortorder
AND b.PrimaryID <> b.SortOrder