MS Access SQL Query Not Exist - sql

I have been stuck on trying to figure how to return data that is in one table but not the other. I thought an outter join would work, but it seems that Access does not allow that.
My SQL is returning results if a record exists in the MonthlyTargets_0_SPARTN_qry but if there is not record then no data is being returned. I would like to display a 0 if there are not records.
My sql is:
SELECT REF_TestCategory_tbl.CategoryID
,MonthlyTargets_0_SPARTN_qry.[Supervisor Id] AS TestOfficerID
,Count(MonthlyTargets_0_SPARTN_qry.[Sheet ID]) AS Actuals
,MonthlyTargets_0_SPARTN_qry.ComplianceMonth
FROM MonthlyTargets_0_SPARTN_qry
INNER JOIN (
REF_TestCategory_tbl INNER JOIN REF_TestCatalog_tbl ON REF_TestCategory_tbl.CategoryID = REF_TestCatalog_tbl.TestCategory
) ON MonthlyTargets_0_SPARTN_qry.[Test Number] = REF_TestCatalog_tbl.TestID
GROUP BY REF_TestCategory_tbl.CategoryID
,MonthlyTargets_0_SPARTN_qry.[Supervisor Id]
,MonthlyTargets_0_SPARTN_qry.ComplianceMonth
ORDER BY REF_TestCategory_tbl.CategoryID;
Which returns:
CategoryID TestOfficerID Actuals ComplianceMonth
1 3062 26 1/1/2020
1 3062 6 2/1/2020
2 3062 2 1/1/2020
3 3062 2 1/1/2020
3 3062 1 2/1/2020
if there are no records for feb, I need it to reurn 0 in Actuals
Thank you

If your 'ComplianceMonth' Values consistently exists regardless of your adjacent data(Meaning if the adjacent data returned for your ComplianceMonth is NULL) then you could do something like this.
SELECT REF_TestCategory_tbl.CategoryID,
MonthlyTargets_0_SPARTN_qry.[Supervisor Id] AS TestOfficerID,
coalesce(Count(MonthlyTargets_0_SPARTN_qry.[Sheet ID]),0) AS Actuals,
MonthlyTargets_0_SPARTN_qry.ComplianceMonth
FROM dbo.MonthlyTargets_0_SPARTN_qry RIGHT OUTER JOIN
dbo.REF_TestCategory_tbl RIGHT OUTER JOIN
dbo.REF_TestCatalog_tbl ON REF_TestCategory_tbl.CategoryID = REF_TestCatalog_tbl.TestCategory ON MonthlyTargets_0_SPARTN_qry.[Test Number] = REF_TestCatalog_tbl.TestID
GROUP BY REF_TestCategory_tbl.CategoryID, MonthlyTargets_0_SPARTN_qry.[Supervisor Id], MonthlyTargets_0_SPARTN_qry.ComplianceMonth
ORDER BY REF_TestCategory_tbl.CategoryID
Hope this Helps.

MS-Access DOES allow outer joins in its SQL. You can do both a LEFT JOIN or a RIGHT JOIN.
MS-Access does not include a statement for a full-outer-join. However, if you want to do a full-outer-join you can do it with a UNION ALL of a specific LEFT JOIN and a specific RIGHT JOIN. The instructions to do a full-outer-join are the following:
You do a “LEFT JOIN” (enclosed in a Select operation) between the two input record-lists. If one of the two input record-lists has one (or more) fields that for sure cannot be Null, that will be the left input record-list. The “ON” Boolean expression is the one that you want for the Full-Outer-Join.
If the left record-list has one (or more) fields that for sure cannot be Null, you skip this step. Otherwise, you do a Cross-Join between the left record-list and a record-list having only one record with one non-Null field (it can be exactly the same Select over “T_Numbers” in the example above, highlighted in green). The Cross-Join is enclosed in a Select that exposes all the fields from the Cross-Join operation, including the field “Num” from “T_Numbers” (with another field name, if you want).
You do a “RIGHT JOIN” having the same right input record-list from point 1. Its left record-list is either the Select from point 2, or the left input record-list from point 1, as corresponds (see point 2). The “ON” expression must be exactly the same as the one of the “LEFT JOIN” from point 1.
The “RIGHT JOIN” from point 3 is enclosed in a Select that exposes all the fields from the left and right input record-lists from point 1. This Select has the “WHERE” expression “IsNull(field)”, where “field” is either the “Num” field from point 2, or the field from left input record-list that for sure cannot be Null, as corresponds (see point 2).
You do a “UNION ALL” with the Select enclosing the “RIGHT JOIN” from point one and the Select enclosing the “RIGHT JOIN” from point 4.
More information at LightningGuide.net.

Related

Should I use an SQL full outer join for this?

Consider the following tables:
Table A:
DOC_NUM
DOC_TYPE
RELATED_DOC_NUM
NEXT_STATUS
...
Table B:
DOC_NUM
DOC_TYPE
RELATED_DOC_NUM
NEXT_STATUS
...
The DOC_TYPE and NEXT_STATUS columns have different meanings between the two tables, although a NEXT_STATUS = 999 means "closed" in both. Also, under certain conditions, there will be a record in each table, with a reference to a corresponding entry in the other table (i.e. the RELATED_DOC_NUM columns).
I am trying to create a query that will get data from both tables that meet the following conditions:
A.RELATED_DOC_NUM = B.DOC_NUM
A.DOC_TYPE = "ST"
B.DOC_TYPE = "OT"
A.NEXT_STATUS < 999 OR B.NEXT_STATUS < 999
A.DOC_TYPE = "ST" represents a transfer order to transfer inventory from one plant to another. B.DOC_TYPE = "OT" represents a corresponding receipt of the transferred inventory at the receiving plant.
We want to get records from either table where there is an ST/OT pair where either or both entries are not closed (i.e. NEXT_STATUS < 999).
I am assuming that I need to use a FULL OUTER join to accomplish this. If this is the wrong assumption, please let me know what I should be doing instead.
UPDATE (11/30/2021):
I believe that #Caius Jard is correct in that this does not need to be an outer join. There should always be an ST/OT pair.
With that I have written my query as follows:
SELECT <columns>
FROM A LEFT JOIN B
ON
A.RELATED_DOC_NUM = B.DOC_NUM
WHERE
A.DOC_TYPE IN ('ST') AND
B.DOC_TYPE IN ('OT') AND
(A.NEXT_STATUS < 999 OR B.NEXT_STATUS < 999)
Does this make sense?
UPDATE 2 (11/30/2021):
The reality is that these are DB2 database tables being used by the JD Edwards ERP application. The only way I know of to see the table definitions is by using the web site http://www.jdetables.com/, entering the table ID and hitting return to run the search. It comes back with a ton of information about the table and its columns.
Table A is really F4211 and table B is really F4311.
Right now, I've simplified the query to keep it simple and keep variables to a minimum. This is what I have currently:
SELECT CAST(F4211.SDDOCO AS VARCHAR(8)) AS SO_NUM,
F4211.SDRORN AS RELATED_PO,
F4211.SDDCTO AS SO_DOC_TYPE,
F4211.SDNXTR AS SO_NEXT_STATUS,
CAST(F4311.PDDOCO AS VARCHAR(8)) AS PO_NUM,
F4311.PDRORN AS RELATED_SO,
F4311.PDDCTO AS PO_DOC_TYPE,
F4311.PDNXTR AS PO_NEXT_STATUS
FROM PROD2DTA.F4211 AS F4211
INNER JOIN PROD2DTA.F4311 AS F4311
ON F4211.SDRORN = CAST(F4311.PDDOCO AS VARCHAR(8))
WHERE F4211.SDDCTO IN ( 'ST' )
AND F4311.PDDCTO IN ( 'OT' )
The other part of the story is that I'm using a reporting package that allows you to define "virtual" views of the data. Virtual views allow the report developer to specify the SQL to use. This is the application where I am using the SQL. When I set up the SQL, there is a validation step that must be performed. It will return a limited set of results if the SQL is validated.
When I enter the query above and validate it, it says that there are no results, which makes no sense. I'm guessing the data casting is causing the issue, but not sure.
UPDATE 3 (11/30/2021):
One more twist to the story. The related doc number is not only defined as a string value, but it contains leading zeros. This is true in both tables. The main doc number (in both tables) is defined as a numeric value and therefore has no leading zeros. I have no idea why those who developed JDE would have done this, but that is what is there.
So, there are matching records between the two tables that meet the criteria, but I think I'm getting no results because when I convert the numeric to a string, it does not match, because one value is, say "12345", while the other is "00012345".
Can I pad the numeric -> string value with zeros before doing the equals check?
UPDATE 4 (12/2/2021):
Was able to finally get the query to work by converting the numeric doc num to a left zero padded string.
SELECT <columns>
FROM PROD2DTA.F4211 AS F4211
INNER JOIN PROD2DTA.F4311 AS F4311
ON F4211.SDRORN = RIGHT(CONCAT('00000000', CAST(F4311.PDDOCO AS VARCHAR(8))), 8)
WHERE F4211.SDDCTO IN ( 'ST' )
AND F4311.PDDCTO IN ( 'OT' )
AND ( F4211.SDNXTR < 999
OR F4311.PDNXTR < 999 )
You should write your query as follows:
SELECT <columns>
FROM A INNER JOIN B
ON
A.RELATED_DOC_NUM = B.DOC_NUM
WHERE
A.DOC_TYPE IN ('ST') AND
B.DOC_TYPE IN ('OT') AND
(A.NEXT_STATUS < 999 OR B.NEXT_STATUS < 999)
LEFT join is a type of OUTER join; LEFT JOIN is typically a contraction of LEFT OUTER JOIN). OUTER means "one side might have nulls in every column because there was no match". Most critically, the code as posted in the question (with a LEFT JOIN, but then has WHERE some_column_from_the_right_table = some_value) runs as an INNER join, because any NULLs inserted by the LEFT OUTER process, are then quashed by the WHERE clause
See Update 4 for details of how I resolved the "data conversion or mapping" error.

Bcause of Null Value data is not refleting

I have two tables view_shipment_order_release and order_release_remark. When there is no record in order_release_remark for a given order_release_gid, there is no data shown. I want to show data in view_shipment_order_release even if there is no data in order_release_remark. How can I do this? My query is shown below.
select distinct
vsor.shipment_gid,
vsor.order_release_gid,
orem1.remark_text as Related_Party,
orem2.remark_text as ULTIMATE_CONSIGNEE_TYPE,
orem3.remark_text as CONSIGNEE_TYPE
from
order_release_remark orem1,
order_release_remark orem2,
order_release_remark orem3,
view_shipment_order_release vsor
--order_release_gid in('GECORP.18460727','GECORP.18435030','GECORP.18439869')
where
orem1.REMARK_QUAL_GID ='GECORP.CONSIGNEE TYPE'
and orem1.order_release_gid=vsor.order_release_gid
and orem2.REMARK_QUAL_GID ='GECORP.RELATED PARTY'
and orem2.order_release_gid=vsor.order_release_gid
and orem3.REMARK_QUAL_GID ='GECORP.ULTIMATE CONSIGNEE TYPE'
and orem3.order_release_gid=vsor.order_release_gid
and vsor.shipment_gid='GECORP.101027274'
;
Use left join instead. left join will not be strict and will still display even if there is no data on related party.
select distinct
vsor.shipment_gid,
vsor.order_release_gid,
orem1.remark_text as Related_Party,
orem2.remark_text as ULTIMATE_CONSIGNEE_TYPE,
orem3.remark_text as CONSIGNEE_TYPE
from view_shipment_order_release vsor
LEFT JOIN order_release_remark orem1
ON orem1.REMARK_QUAL_GID ='GECORP.CONSIGNEE TYPE'
and orem1.order_release_gid=vsor.order_release_gid
LEFT JOIN order_release_remark orem2
ON orem2.REMARK_QUAL_GID ='GECORP.RELATED PARTY'
and orem2.order_release_gid=vsor.order_release_gid
LEFT JOIN order_release_remark orem3
ON orem3.REMARK_QUAL_GID ='GECORP.ULTIMATE CONSIGNEE TYPE'
and orem3.order_release_gid=vsor.order_release_gid
where vsor.shipment_gid='GECORP.101027274';
I can only assume that you actually mean order_release_remark.remark_text - which is called Related_Party in your output.
If this is indeed the case - there is nothing in this query that explains such behavior.
However, your query is bases on a view - view_shipment_order_release (at least I hope it's a view). Views are just names for select statements - which means that oracle is combining the query recorded in the view with the select statement you posted. My guess is, that there is something in that view that says that that order_release_remark.remark_text must not be empty. Or may be the records where it's empty do not have a value in order_release_gid?
Bear in mind, oracle believes that null is not equal null - so if order_release_gid is not present (is null) in two records, joining on this field will not return any rows.

Subquery in Case statement using value from outer select statement

I have got two tables, something like what is shown below
I need to write a select query, which when comes across a Mat_Name from category P11 or P12, and has last four characters anything other than 'B111' (for ex. AA-1234-B333), then it should give out Mat_Num of some other Mat_Name which has the same first eight characters, but has 'B111' as its last 4 characters ie. in case of AA-1234-B333 it should return Mat_Num as 123456, which is Mat_Num for AA-1234-B111, and not 114466.
I was thinking of using the below query, but then I couldn't quite figure out passing value of Mat_Name from outer select to the one inside the CASE statement (to get correct Mat_Num).
select tbl1.Mat_Name,
CASE
When (tbl2.Category IN ('P11','P12')) AND (RIGHT(tbl.Mat_Name,4) <> 'B111') THEN (Select tbl1.Mat_Num from tbl1 where ... ),
tbl2.Category
from tbl1
INNER JOIN tbl2 ON tb1.Mat_Num = tbl2.Mat_Num

SQL using inner join

So this is the situation I have. I have 3 tables (tblEmployeesinfo , sqlSumrepMTC, sqlSumrepMTC15th) I display this info using inner join:
SELECT
SQLSummRepMTC."RepCompany", SQLSummRepMTC."WHTax",
SQLSummRepMTC."Company", SQLSummRepMTC."MonthName",
SQLSummRepMTC."YearVal", SQLSummRepMTC."Basis",
tblEmployeesInfo."LastName", tblEmployeesInfo."FirstName",
tblEmployeesInfo."Company", tblEmployeesInfo."MInitial",
tblEmployeesInfo."Division", sqlSumrepMTC15th."WHTax",
sqlSumrepMTC15th."Basis"
FROM
{
oj ("BIOMETRICS"."dbo"."SQLSummRepMTC" SQLSummRepMTC INNER JOIN
"BIOMETRICS"."dbo"."tblEmployeesInfo" tblEmployeesInfo
ON SQLSummRepMTC."EmployeeNo" = tblEmployeesInfo."EmployeeNo")
INNER JOIN "BIOMETRICS"."dbo"."sqlSumrepMTC15th" sqlSumrepMTC15th
ON tblEmployeesInfo."EmployeeNo" = sqlSumrepMTC15th."EmployeeNo"
}
ORDER BY
SQLSummRepMTC."Basis" ASC,
tblEmployeesInfo."Company" ASC,
tblEmployeesInfo."LastName" ASC
Let's say one employee has his record on sqlSumrepMTC with its field Taxvalue of 50 but he does not exist on sqlSumrepMTC15th my problem is that this record will not be displayed in the inner join since it does not have value on both tables. What i want to achieve is just display a 0 value when it does not exist in the other table. This is my report looks like.
Employeeno employeename 15th 30th
01 james 10 20
02 Chris NULL 50
first record will appear in the report since it has both record existing in the two tables, the second will not since its null in the first table. I just need it to appear in the report if one value is null or is missing from the other. Thanks in advance
You have two joins! Thus, if there is no record in sqlSumrepMTC15th you need to replace the second join with LEFT JOIN. If it is possible, that there is no join record in sqlSumrepMTC15th AND tblEmployeesInfo, you need to replace both joins with LEFT JOIN.
Furthermore, you can replace NULL by
SELECT CASE
WHEN attribute IS NULL
THEN 0
ELSE attribute
END AS resultColumName,
nextAttribute
FROM ...

Coalescing a subset to its parent set

I have two tables, A and B. B is a random subset of A but with some values that override the default values in A. How do I join the two tables to coalesce their values?
A
1, 0
2, 0
3, 0
4, 0
B
2, 10
3, 11
Output
1, 0
2, 10
3, 11
4, 0
Here is my actual query - I thought I could do this with LEFT OUTER JOIN, but this restricts the Output set to the intersection of A and B rows. I need all A rows to return, coalesced with the relevant B rows.
SELECT A.factor, A.categorical_value, coalesce(A.positive, B.positive), coalesce(A.negative, B.negative)
FROM features A
LEFT OUTER JOIN profiles B ON (A.factor=B.factor AND A.categorical_value=B.categorical_value)
WHERE B.uuid='9e5083da74305628336631da9d2903e3'
As Craig Ringer points out below, I am inadvertently restricting A with my B clause. But then how do I do this? Table A is a many-to-many table of profile attributes, where uuid indicates the user id. Table B is a master list of all possible profile attributes. I want the query to return the master list with the an individual profile superimposed on to it.
After question update:
As #Craig already informed you, a WHERE condition on B would only select matching rows in B and act like a [INNER] JOIN instead of a LEFT [OUTER] JOIN.
You need to pull that WHERE condition up into the condition of the LEFT JOIN.
While being at it, I opportunistically simplified with USING, since all joining column names are identical. Details in the manual.
Information is still incomplete and contradicting. Here is another educated guess:
SELECT a.factor, a.categorical_value
, COALESCE(a.positive, b.positive) AS positive
, COALESCE(a.negative, b.negative) AS negative
FROM features a
LEFT JOIN profiles b USING (factor, categorical_value, uuid)
WHERE a.uuid='9e5083da74305628336631da9d2903e3'
Not sure if you need to join on udid, too.
Your example would indicate COALESCE(b.positive, a.positive). Something does not add up ...
More updates in comment
Adapt your JOIN condition then:
SELECT a.factor, a.categorical_value
, COALESCE(a.positive, b.positive) AS positive
, COALESCE(a.negative, b.negative) AS negative
FROM features a
LEFT JOIN profiles b ON a.factor = b.factor
AND a.categorical_value = b.categorical_value
AND b.uuid='9e5083da74305628336631da9d2903e3';