Sql - how to build query with 3 tables - sql

I'm developing a page that allow to search a product by reference or by bar code or by alternative bar codes in certain order list.
I need to get the reference and qtt columns from select.
To do that we have 3 tables:
bi (list all products inside a specific order)
sc (give us standard qtt by product reference)
bc (gives us alternative bar codes, this table has also qtt column)
The problem is that it's possible that a product doesn't have alternative bar codes and in this case the bc table returns null and in this case I have to get the qtt in table sc but I don't know how to do that in same query.
My query is that:
select top 1 bi.ref, bc.qtt
from bi left join
bc
on bc.ref = bi.ref
where (bi.ref='00012' or bi.code='00012' or bc.code='00012') and
bi.bostamp = ('orderID-0001')
The column bi.bostamp is the reference with order id.
So, I need to try integrate sc table in query to get qtt just when bc is null.
Thank you

I think you can use Case When to get the results you want.
Select Top 1 bi.ref, case when isnull(bc.qtt) then sc.qtt else bc.qtt end as qtt
FROM bi left join bc on bc.ref = bi.ref
left join sc on sc.ref = bi.ref
Does that work for you? This also assumes sc has a ref column like bc and bi.

Related

Transact SQL - Join one table with other two

I have a table that is for PaymentRequest (PR), each PR table has two forms of pay, a WorkProgress, and a AdvanceByWarranty, the relation is like this:
I Need to create a report to get all the payment made in that (PR), and some other fields between them
The sql that I was using to join PaymentRequest with WorkProgress is this, and it works, it returns the WorkProgress of that payment
To get the Advances by warranty I use this, it also works, returns 2 Advances, as it should be
But, when I mix both, it doesnt return 3 rows, as it should be, it returns two. The result is this
I was expecting something like this (With shorter names)
How can i get the expected query?
Edit:
The sql to get the expected query is this
select
pr.ProjectId, pr.NumberPaymentState,
wp.ToCollectAmmount as WPAmmount, wp.ToCollectPercent as WPPercent,
null as AWAmmount, null as AWPercent
from PaymentRequests pr
left join WorkProgresses wp on (wp.ProjectId = pr.ProjectId and wp.NumberPaymentState = pr.NumberPaymentState)
union all
select
pr.ProjectId, pr.NumberPaymentState,
null as WPAmmount, null as WPPercent,
aw.ToCollectAmmount as AWAmmount, aw.ToCollectPercent as AWPercent
from PaymentRequests pr
left join AdvanceByWarranties aw on (aw.ProjectId = pr.ProjectId and aw.NumberPaymentState = pr.NumberPaymentState)
You might have wanted what you show, but it doesn't work like this.
Just use UNION ALL between your first two queries, and rename the columns accordingly. Here is some pseudocode hybrid to guide you:
select keycols, workercols, null as advancecols
from pr join worker
union all
select keycols, null as workercols, advancecols
from pr join advancecols

SQL - join three tables based on (different) latest dates in two of them

Using Oracle SQL Developer, I have three tables with some common data that I need to join.
Appreciate any help on this!
Please refer to https://i.stack.imgur.com/f37Jh.png for the input and desired output (table formatting doesn't work on all tables).
These tables are made up in order to anonymize them, and in reality contain other data with millions of entries, but you could think of them as representing:
Product = Main product categories in a grocery store.
Subproduct = Subcategory products to the above. Each time the table is updated, the main product category may loses or get some new suproducts assigned to it. E.g. you can see that from May to June the Pulled pork entered while the Fishsoup was thrown out.
Issues = Status of the products, for example an apple is bad if it has brown spots on it..
What I need to find is: for each P_NAME, find the latest updated set of subproducts (SP_ID and SP_NAME), and append that information with the latest updated issue status (STATUS_FLAG).
Please note that each main product category gets its set of subproducts updated at individual occasions i.e. 1234 and 5678 might be "latest updated" on different dates.
I have tried multiple queries but failed each time. I am using combos of SELECT, LEFT OUTER JOIN, JOIN, MAX and GROUP BY.
Latest attempt, which gives me the combo of the first two tables, but missing the third:
SELECT
PRODUCT.P_NAME,
SUBPRODUCT.SP_PRODUCT_ID, SUBPRODUCT.SP_NAME, SUBPRODUCT.SP_ID, SUPPRODUCT.SP_VALUE_DATE
FROM SUBPRODUCT
LEFT OUTER JOIN PRODUCT ON PRODUCT.P_ID = SUBPRODUCT.SP_PRODUCT_ID
JOIN(SELECT SP_PRODUCT_ID, MAX(SP_VALUE_DATE) AS latestdate FROM SUBPRODUCT GROUP BY SP_PRODUCT_ID) sub ON
sub.SP_PRODUCT_ID = SUBPRODUCT.SP_PRODUCT_ID AND sub.latestDate = SUBPRODUCT.SP_VALUE_DATE;
Trying to find a row with a max value is a common SQL pattern - you can do it with a join, like your example, but it's usually more clear to use a subquery or a window function.
Correlated subquery example
select
PRODUCT.P_NAME,
SUBPRODUCT.SP_PRODUCT_ID, SUBPRODUCT.SP_NAME, SUBPRODUCT.SP_ID, SUPPRODUCT.SP_VALUE_DATE,
ISSUES.STATUS_FLAG, ISSUES.STATUS_LAST_UPDATED
from PRODUCT
join SUBPRODUCT
on PRODUCT.P_ID = SUBPRODUCT.SP_PRODUCT_ID
and SUBPRODUCT.SP_VALUE_DATE = (select max(S2.SP_VALUE_DATE) as latestDate
from SUBPRODUCT S2
where S2.SP_PRODUCT_ID = SUBPRODUCT.SP_PRODUCT_ID)
join ISSUES
on ISSUES.ISSUE_ID = SUBPRODUCT.SP_ID
and ISSUES.STATUS_LAST_UPDATED = (select max(I2.STATUS_LAST_UPDATED) as latestDate
from ISSUES I2
where I2.ISSUE_ID = ISSUES.ISSUE_ID)
Window function / inline view example
select
PRODUCT.P_NAME,
S.SP_PRODUCT_ID, S.SP_NAME, S.SP_ID, S.SP_VALUE_DATE,
I.STATUS_FLAG, I.STATUS_LAST_UPDATED
from PRODUCT
join (select SUBPRODUCT.*,
max(SP_VALUE_DATE) over (partition by SP_PRODUCT_ID) as latestDate
from SUBPRODUCT) S
on PRODUCT.P_ID = S.SP_PRODUCT_ID
and S.SP_VALUE_DATE = S.latestDate
join (select ISSUES.*,
max(STATUS_LAST_UPDATED) over (partition by ISSUE_ID) as latestDate
from ISSUES) I
on I.ISSUE_ID = S.SP_ID
and I.STATUS_LAST_UPDATED = I.latestDate
This often performs a bit better, but window functions can be tricky to understand.

Conditional join that changes number of join conditions

I am trying to join data based on the following scenario.
Let's say there are two businesses. Business 1 has one field for customer data, business 2 has two fields. I need to join to multiple other tables using these customer fields.
I would like to create a join that joins on just field 1 for business 1, but field 1 AND field 2 for business 2. In other words, there is a more granular identifier available for business 2, but it is still valid to join on just field 1 for business 1 as well. It also needs to function like an inner join, in that we are only preserving the relevant data that match these conditions.
The code would look something like this for business 1:
FROM customer_data a
INNER JOIN marketing_data b
ON a.member_number = b.member_number
WHERE business_number = 1
And something like this for business 2:
FROM customer_data a
INNER JOIN marketing_data b
ON a.member_number = b.member_number
AND a.sub_member_number = b.sub_member_number
WHERE business_number = 2
I am hoping to extract both sets of data in one join statement. Also, just in case it helps, I am using the Snowflake platform to write my queries.
Following should work for both the cases.
FROM customer_data a
INNER JOIN marketing_data b ON a.member_number = b.member_number
WHERE (
a.sub_member_number = b.sub_member_number
AND business_number = 2
)
OR business_number = 1
You can put the conditions in the ON clause like this:
FROM customer_data cd INNER JOIN
marketing_data md
ON cd.member_number = md.member_number AND
( cd.business_number <> 2 OR
cd.sub_member_number = md.sub_member_number
)
Note: this generalizes beyond just businesses 1 and 2, with the special condition only applying to 2. The first condition can be = 1 if you want to be more specific.
Also note that this introduces meaningful table aliases rather than arbitrary letters. This makes queries much easier to understand.

Duplication happening when second call to warehouse item

I am getting some strange duplication in my query the problem is I need to be able to query both stock qtys from warehouse item table and as you see i am calling it twice hence there is duplication of warehouse items. Will find that its my joins that will be the issue.
SELECT ki.[KitItemID]
,ki.[KitHeaderID]
,kh.StockCode as KitHeaderStockCode
,ki.[StockCode]
,ki.[StockDescription]
,ki.[StockItemID]
,ki.[Qty]
,ki.[IsBoard]
,ki.[IsSubAssembly],
ISNULL(wip.ConfirmedQtyInStock,0) as InStockCs,
ISNULL(SUM(wip2.ConfirmedQtyInStock), 0) as InStockWip,
#ppBatch as BatchID
FROM KitItem ki
LEFT JOIN KitHeader kh ON ki.KitHeaderID = kh.KitHeaderID
LEFT JOIN WarehouseItem wip2 ON ki.StockItemID = wip2.ItemID AND wip2.WarehouseID = (SELECT TOP 1 WIP_LocationID FROM Settings)
INNER JOIN
dbo.WarehouseItem wip ON ki.StockItemID =wip.ItemID INNER JOIN
dbo.Warehouse war ON wip.WarehouseID = war.WarehouseID
WHERE ki.IsBox = 0
GROUP BY
ki.[KitItemID]
,ki.[KitHeaderID]
,kh.StockCode
,ki.[StockCode]
,ki.[StockDescription]
,ki.[StockItemID]
,ki.[Qty]
,ki.[IsBoard]
,ki.[IsSubAssembly]
,wip.ConfirmedQtyInStock
,wip2.ConfirmedQtyInStock
After ON ki.StockItemID =wip.ItemID, add
and wip.ItemID=wip2.ItemID
so that each row does only have data about 1 item, not 2
If you get full duplicates you can use distinct in select, otherwise add a column in group by which is different

MS Access SQL left join giving all 0

I am trying to make a summary table of all the items I have. I have a raw data table with 10 users who respectively have different items. There are maximum 3 different items and I want to do a count to see how many items each individual has. The following is my code.
Select b.Country,b.UserID,Num_including_fruits, Apple,Orange
from
(((SELECT o.Country,o.UserID, IIF(ISNULL(Count(o.UserID)),0,Count(o.UserID))
AS Num_including_fruits
FROM [SEA2_View] as o
GROUP BY o.UserID, o.Country
ORDER BY Country)as b
LEFT JOIN
(SELECT o.Country,o.UserID,IIF(ISNULL(Count(o.UserID)),0,Count(o.UserID)
AS Apple
FROM [APAC2_View] as o
WHERE o.fruit_status <>"fresh" AND o.HWType = "Apple"
GROUP BY o.Country,o.UserID)as d
ON (b.UserID = d.UserID))
LEFT JOIN
(SELECT o.Country,o.UserID,IIF(ISNULL(Count(o.UserID)),0,Count(o.UserID))
AS Orange
FROM [SEA2_View] as o
WHERE o.fruit_status <>"fresh" AND o.HWType = "Orange"
GROUP BY o.Country,o.UserID)as e
ON (d.UserID = e.UserID))
;
The first join returns the correct result but the second join somehow returns all 0, which is incorrect. Therefore please help! and I would appreciate any advice for best practice when it comes to joins in SQL. Thanks lot!
Are you sure you don't have a table naming error?
You're first joining [SEA2_View] with [APAC2_View]. The second join is joining with [SEA2_View] with itself.