Conditional Left Join MS Access - ms-access

I have here a query that updates some fields based on a lookup table via left join.
UPDATE finalTbl
LEFT JOIN LookupTbl ON (finalTbl.Product = LookupTbl.Product) AND (finalTbl.Detail1 = LookupTbl.[Product Detail])
SET finalTbl.Description = LookupTbl.Description, finalTbl.Category = LookupTbl.Category;
Now, There's another field in finalTbl that i would like to include in the process (Detail2).
The idea will be..
if finalTbl.Detail2 IS NULL then LEFT JOIN LookupTbl ON (finalTbl.Product = LookupTbl.Product) AND (finalTbl.Detail1 = LookupTbl.[Product Detail])
else
LEFT JOIN LookupTbl ON (finalTbl.Detail2 = LookupTbl.[Product Detail])
Detail2doesn't need to rely on Product field, compared to Detail1
I tried to create it via Design View but failed. Seems I am lost and need some light about it. Thanks for your inputs!

I haven't tested this, but I often use NZ in joins where a date may be missing.
For example: Table0.ShiftDate<=NZ(Table1.EndDate,#01/01/9999#)
Try:
UPDATE finalTbl LEFT JOIN LookupTbl ON (finalTbl.Product = LookupTbl.Product) AND
(NZ(finalTbl.Detail1,finalTbl.Detail2) = LookupTbl.[Product Detail])
SET finalTbl.Description = LookupTbl.Description
, finalTbl.Category = LookupTbl.Category;
Edit:
After a quick test it appears to work using the SQL below.
SELECT *
FROM finalTbl LEFT JOIN LookupTbl ON (finalTbl.Product = LookupTbl.Product) AND
(NZ(finalTbl.Detail1,finalTbl.Detail2) = LookupTbl.[Product Detail])
Edit again:
But I haven't taken this into account.
Detail2doesn't need to rely on Product field, compared to Detail1

Related

How to Join to a table where the result can sometimes lead with a - sign?

Hopefully i can explain this well enough. I have a bit of a unique issue where the customer system we use can change a ID in the database in the background based on the products status.
What this means is when i want to report old products we don't use anymore along side active products there ID differs between the two key tables depending on there status. This means Active products in the product table match that of the stock item table with both showing as 647107376 but when the product is no long active the StockItem table will present as 647107376 but the table that holds the product information the id presents as -647107376
This is proving problematic for me when i comes to joining the tables together to get the information needed. Originally i had my query set up like this:
SELECT
Company_0.CoaCompanyName
,SopProduct_0.SopStiStockItemCode AS hbpref
,SopProduct_0.SopStiCustomerStockCode AS itemref
,SopProduct_0.SopDescription AS ldesc
,StockMovement_0.StmOriginatingEntityID AS Goodsin
FROM
SBS.PUB.StockItem StockItem_0
LEFT JOIN SBS.PUB.SopProduct SopProduct_0 ON StockItem_0.StockItemID = SopProduct_0.StockItemID
LEFT JOIN SBS.PUB.Company Company_0 ON SopProduct_0.CompanyID = Company_0.CompanyID
LEFT JOIN SBS.PUB.StockMovement StockMovement_0 ON StockItem_0.StockItemID = StockMovement_0.StockItemID
WHERE
Company_0.CoaCompanyName = ?
AND StockMovement_0.MovementTypeID = '173355'
AND StockMovement_0.StmMovementDate >= ? AND StockMovement_0.StmMovementDate <= ?
AND StockMovement_0.StmQty <> 0
AND StockMovement_0.StockTypeID ='12049886'
Unfortunately though what this means is any of the old product will not show because there is no matching id due to the SopProduct table presenting the StockItemID with a leading -
So from this i thought best to use a case when statement with a nested concat and left in it to bring through the results but this doesn't appear to work either sample of the join below:
LEFT JOIN SBS.PUB.SopProduct SopProduct_0 ON (CASE WHEN LEFT(SopProduct_0.StockItemID,1) = "-" THEN CONCAT("-",StockItem_0.StockItemID) ELSE StockItem_0.StockItemID END) = SopProduct_0.StockItemID
Can anyone else think of a way around this issue? I am working with a Progress OpenEdge ODBC.
Numbers look like numbers. If they are, you can use abs():
ON StockItem_0.StockItemID = ABS(SopProduct_0.StockItemID)
Otherwise a relatively simple method is:
ON StockItem_0.StockItemID IN (SopProduct_0.StockItemID, CONCAT('-', SopProduct_0.StockItemID))
Note that non-equality conditions often slow down JOIN operations.
Using an or in the join should work:
LEFT JOIN SBS.PUB.SopProduct SopProduct_0
ON SopProduct_0.StockItemID = StockItem_0.StockItemID
OR
SopProduct_0.StockItemID = CONCAT("-", StockItem_0.StockItemID)
You might need to cast the result of the concat to a number (if the ids are stored as numbers).
Or you could use the abs function too (assuming the ids are numbers):
LEFT JOIN SBS.PUB.SopProduct SopProduct_0
ON SopProduct_0.StockItemID = abs(StockItem_0.StockItemID)

How do I add a criteria to a query on one table but keep all the records from another?

I have the following query:
SELECT games_atp.ID1_G, odds_atp.K1
FROM games_atp LEFT JOIN odds_atp ON (games_atp.ID1_G = odds_atp.ID1_O) AND (games_atp.ID2_G = odds_atp.ID2_O) AND (games_atp.ID_T_G = odds_atp.ID_T_O) AND (games_atp.ID_R_G = odds_atp.ID_R_O)
I know the joining is convoluted but the original db is built without a primary key. The above works fine and importantly pulls all the records from games_atp. I now want to add a criteria into this to pull only certain K1 records from odds_atp. I added a WHERE clause as follows:
SELECT games_atp.ID1_G, odds_atp.K1
FROM games_atp LEFT JOIN odds_atp ON (games_atp.ID1_G = odds_atp.ID1_O) AND (games_atp.ID2_G = odds_atp.ID2_O) AND (games_atp.ID_T_G = odds_atp.ID_T_O) AND (games_atp.ID_R_G = odds_atp.ID_R_O)
WHERE (((odds_atp.ID_B_O)=2));
However, this overides the left join and only pulls records from games_atp where there is a corresponding record in odds_atp with ID_B_O = 2. How do I keep the criteria and all the records in games_atp? Thanks in advance.
Your current where condition will filter your final result, hence you are only seeing id_B_O = 2.
However, you could also add the wehre condition directly into your left join.
something like this.
SELECT
games_atp.ID1_G, odds_atp.K1
FROM
games_atp
LEFT JOIN odds_atp ON
(
(odds_atp.ID_B_O =2)
AND
(
(games_atp.ID1_G = odds_atp.ID1_O)
AND (games_atp.ID2_G = odds_atp.ID2_O)
AND (games_atp.ID_T_G = odds_atp.ID_T_O)
AND (games_atp.ID_R_G = odds_atp.ID_R_O)
)
);
or you could also take advantage of sub-queries

Microsoft Access Update Statement with Inner Joins and Subqueries

I am having a tough time figuring out how to do this update query. Basically I need to update a table named tblOpenJobs. It needs to be updated with the dbo_WorkOrders table with the Max Install date. But there is not direct relationship between those two tables you need to have the dbo_premise table between. Here is my query, what am I doing wrong?
UPDATE tblOpenJobs
INNER JOIN (dbo_Premise INNER JOIN dbo_WorkOrders w (WHERE w.InstallDate IN
(SELECT MAX(InstallDate) FROM dbo_WorkOrders WHERE dbo_WorkOrders.PremiseKey = w.PremiseKey))
ON (dbo_Premise.PremiseKey = w.PremiseKey)
ON tblOpenJobs.ServiceOrderNum = dbo_Premise.AccountNumber
SET tblOpenJobs.InstallerID = w.InstallerID,
tblOpenJobs.InstallDate= w.InstallDate,
tblOpenJobs.New_Serial_num= w.NewSerial,
tblOpenJobs.Old_Reading= w.OldRead;
I checked this in Access 2007 query window:
Your query seems neither Transact-SQL, neither Access, as the two have different syntax.
In Access, table aliasing must use the keyword AS, while Transact-SQL does not require:
UPDATE ((tblOpenJobs
INNER JOIN dbo_Premise
ON tblOpenJobs.ServiceOrderNum = dbo_Premise.AccountNumber)
INNER JOIN dbo_WorkOrders AS w
ON dbo_Premise.PremiseKey = w.PremiseKey)
SET tblOpenJobs.InstallerID = w.InstallerID,
tblOpenJobs.InstallDate = w.InstallDate,
tblOpenJobs.New_Serial_num = w.NewSerial,
tblOpenJobs.Old_Reading = w.OldRead
WHERE (w.InstallDate IN
(SELECT MAX(InstallDate)
FROM dbo_WorkOrders
WHERE dbo_WorkOrders.PremiseKey = w.PremiseKey))
This is correct in syntax, but I'm not sure it can update your data, as multi-table linked update is not easy in Access.

Taking one column from MySQL joined tables

I have a query in MySQL and I am making a crystal report by using this.
Now inside the query i have a column called scan_mode and it is coming from gfi_transaction table. This scan_mode I am using in report to suppress some sections. But some times this value is coming null for some transaction ids.
So now I want to take this scan_mode as separate query so that it will work.
Can any one please help how I can modify the below query to take only scan_mode column.
SELECT
cc.cost_center_code AS cccde,
cc.name AS ccnme,gf.scan_mode,
cc.cost_center_id AS ccid,
site.name AS siteme,
crncy.currency_locale AS currency_locale,
cntry.language AS LANGUAGE,
cntry.country_name AS cntrynm,
crncy.decimal_digits AS rnd,
gf.transaction_no AS Serial_No,
brnd.name AS brand_name,
rsn.description AS reason,
gf.comment AS COMMENT,
ts.status_description AS STATUS,
DATE_FORMAT(gf.created_date,'%d/%m/%Y') AS created_date,
gf.created_by AS created_by,
IFNULL(gf.approval_no,'Not authorized') AS Trans_no,
gf.approved_date AS approval_dt,
gf.approved_by AS approved_by,gf.status AS status1,
IFNULL(loc.cost_center_code,cc.cost_center_code) AS cur_location,
gf.document_ref_no,gf.document_ref_type,
,DATE_FORMAT(document_ref_date1,'%d/%m/%Y')) AS invoice_no
FROM
gfi_transaction gf
INNER JOIN gfi_instruction gfn ON (gf.transaction_id=gfn.transaction_id)
INNER JOIN gfi_document_instruction doc ON (gf.ref_transaction_no = doc.document_instruction_id)
INNER JOIN reason rsn ON (gf.reason_id = rsn.reason_id)
INNER JOIN gfi_status ts ON (gf.status = ts.gfi_status_id)
INNER JOIN transaction_type tt ON (gf.transaction_type_id = tt.transaction_type_id)
INNER JOIN brand brnd ON(gf.brand_id=brnd.brand_id)
-- cc details
INNER JOIN cost_center cc ON (brnd.parent_brand = cc.brand_id OR gf.brand_id = cc.brand_id)
INNER JOIN site site ON(cc.site_id = site.site_id)
INNER JOIN country cntry ON (site.country_id = cntry.country_id)
INNER JOIN currency crncy ON (cntry.currency_id=crncy.currency_id)
LEFT OUTER JOIN alshaya_location_details loc ON
(gf.brand_id = loc.brand_id AND loc.cost_center_id = gf.cost_centre_id)
LEFT OUTER JOIN alshaya_location_details locto ON
(locto.cost_center_id = gf.from_cost_center_id)
WHERE
gf.transaction_id='{?TransID}'
AND rsn.transaction_type_id IN (10,11,14)
wow, that's a big query. I ran across a similar problem in a query i was building and found the if syntax to be a solution to my problem. This was also answered in this question: MYSQL SELECT WITHIN IF Statement
$psdb->query = "SELECT count, s.classid,
if (k.sic != k.siccode, k.siccode, s.siccode) as siccode,
if (k.sic != k.siccode, k.sicdesc, s.sicdesc) as sicdesc,
if (k.sic != k.siccode, k.sicslug, s.sicslug) as sicslug
FROM ...
It looks like scan_mode column comes from "gfi_transaction" table which seems to be primary table in your query. If you get null for this column then it means your table itself have NULL value for this column. Taking that separately in a query wont solve your problem. Try replacing null with a default value and handle it in code. You can add default value instead of NULL by using ifnull(scan_mode, 'default')

MYSQL get other table data in a join

I am currently running this SQL
SELECT jm_recipe.name, jm_recipe.slug
FROM jm_recipe
LEFT JOIN jm_category_recipe ON jm_category_recipe.recipe_id = jm_recipe.id
WHERE jm_category_recipe.category_id = $cat"
This returns the desired results except that I also need to return the name of the category that the recipe I am looking for is in, to do this I tried to add the field in to my SELECT statement and also add the table into the FROM clause,
SELECT jm_recipe.name, jm_recipe.slug, jm_category_name
FROM jm_recipe, jm_category
LEFT JOIN jm_category_recipe ON jm_category_recipe.recipe_id = jm_recipe.id
WHERE jm_category_recipe.category_id = $cat"
However this just returns no results, what am i doing wrong?
You need to join both tables:
SELECT jm_recipe.name, jm_recipe.slug, jm.category_name
FROM jm_recipe
INNER JOIN jm_category_recipe ON jm_category_recipe.recipe_id = jm_recipe.id
INNER JOIN jm_category ON jm_recipe.recipe_id = jm_category.recipe_id
WHERE jm_category_recipe.category_id = $cat
I've changed the joins to inner joins as well. You might want to make them both LEFT joins if you have NULLs and want them in the result.
Also, you're vulnerable to SQL Injection by simply copying over $cat.
Here's some PHP specific info for you (I'm assuming you're using PHP.)