Adding LEFT JOIN causes "multi-part identifier not bound" - sql

Why does the below query fail when I add the second LEFT JOIN statement? The error states "Multi-part identifier T3.ConfigIDx could not be bound". Prior to adding the statement the column T3.ConfigIDx showed in the results. I tried with and with out T3.
I removed some code within the INNER JOINS for brevity.
-- Add CfgDescription to ComponentID include QuantityWH for all components 'Used' or blank found in the order.
-- Attach Line information like Quantity and DiscountRate from the Order using Configuration ID.
SELECT
BDCComponentAttributes.componentID AS ComponentID,
BDCComponentAttributes.Value AS CfgDescription,
CAST (BDC10.Value AS INT) AS QuantityWH,
CfgIDx,
T3.ConfigIDx
FROM BDCComponentAttributes
Left join BDCComponentAttributes BDC10 on BDC10.ComponentID = BDCComponentAttributes.componentID and BDC10.ComponentAttributeName = 'QuantityWH'
Left join OrderDetails on OrderDetails.ConfigurationID = T3.ConfigIDx
INNER JOIN
(
-- Select ComponentID's and their respective CfgDescription for components found in order. This creates derived table T3.
INNER JOIN
(
-- Select Components in the order NOT 'NotUsed'. This creates derived table T2.
INNER JOIN
(
-- Select ConfigurationID's for components of the order. This creates derived table T1.
) AS T1
ON BDCComponents.CfgID = T1.CfgIDx
) AS T2
ON BDCComponentAttributes.ComponentID = T2.ComponentID
WHERE BDCComponentAttributes.ComponentAttributeName = 'PartInSystem' AND ( 'Used' = IsNull(BDCComponentAttributes.Value,'Used') OR BDCComponentAttributes.Value='Used')
) AS T3
ON BDCComponentAttributes.componentID = T3.ComponentID
WHERE BDCComponentAttributes.ComponentAttributeName = 'CfgDescription'
ORDER BY ComponentID

The from clause in your query starts:
FROM BDCComponentAttributes Left join
BDCComponentAttributes BDC10
on BDC10.ComponentID = BDCComponentAttributes.componentID and
BDC10.ComponentAttributeName = 'QuantityWH' Left join
OrderDetails
on OrderDetails.ConfigurationID = T3.ConfigIDx
When a query is compiled, the from clause is interpreted in lexical ordering -- that is, in the same "left-to-right" "top-to-bottom" way that we read. When the symbol T3 is encountered, it is not defined. That is causing your error. SQL does not have "look-ahead" to see that it is defined later in the from clause.
You can fix this by moving the join condition after the definition of T3.

Related

How to do operations between a column and a subquery

I would like to know how I can do operations between a column and a subquery, what I want to do is add to the field Subtotal what was obtained in the subquery Impuestos, the following is the query that I am using for this case.
Select
RC.PURCHID;
LRC.VALUEMST as 'Subtotal',
isnull((
select sum((CONVERT(float, TD1.taxvalue)/100)*LRC1.VALUEMST ) as a
FROM TAXONITEM TOI1
inner join TAXDATA TD1 ON (TD1.TAXCODE = TOI1.TAXCODE and RC.DATAAREAID = TD1.DATAAREAID)
inner join TRANS LRC1 on (LRC1.VEND = RC.RECID)
WHERE TOI1.TAXITEMGROUP = PL.TAXITEMGROUP and RC.DATAAREAID = TOI1.DATAAREAID
), 0) Impuestos
from VEND RC
inner join VENDTABLE VTB on VTB.ACCOUNTNUM = RC.INVOICEACCOUNT
inner join TRANS LRC on (LRC.VEND = RC.RECID)
inner join PURCHLINE PL on (PL.LINENUMBER =LRC.LINENUM and PL.PURCHID =RC.PURCHID)
where year (RC.DELIVERYDATE) =2021 and RC.PURCHASETYPE =3 order by RC.PURCHID;
Hope someone can give me some guidance when doing operations with subqueries.
A few disjointed facts that may help:
When a SELECT statement returns only one row with one column, you can enclose that statement in parenthesis and use it as a plain value. In your case, let's say that select sum(......= TOI1.DATAAREAID returns 500. Then, your outer select's second column is equivalent to isnull(500,0)
You mention in your question "subquery Impuestos". Keep in mind that, although you indeed used a subquery as we mentioned earlier, by the time it was enclosed in parentheses it is not treated as a subquery (more accurately: derived table), but as a value. Thus, the "Impuestos" is only a column alias at this point
I dislike and avoid subqueries before the from, makes things much harder to read. Here is a solution with apply which will keep your code mostly intact:
Select
RC.PURCHID,
LRC.VALUEMST as 'Subtotal',
isnull(subquery1.a, 0) as Impuestos
from VEND RC
inner join VENDTABLE VTB on VTB.ACCOUNTNUM = RC.INVOICEACCOUNT
inner join TRANS LRC on (LRC.VEND = RC.RECID)
inner join PURCHLINE PL on (PL.LINENUMBER =LRC.LINENUM and PL.PURCHID =RC.PURCHID)
outer apply
(
select sum((CONVERT(float, TD1.taxvalue)/100)*LRC1.VALUEMST ) as a
FROM TAXONITEM TOI1
inner join TAXDATA TD1 ON (TD1.TAXCODE = TOI1.TAXCODE and RC.DATAAREAID = TD1.DATAAREAID)
inner join TRANS LRC1 on (LRC1.VEND = RC.RECID)
WHERE TOI1.TAXITEMGROUP = PL.TAXITEMGROUP and RC.DATAAREAID = TOI1.DATAAREAID
) as subquery1
where year (RC.DELIVERYDATE) =2021 and RC.PURCHASETYPE =3 order by RC.PURCHID;

query with left outer join in sql

I have an issue with the below query:
select main.courseid
,main.coursename
,main.catid
,main.catname
,main.need_dte
from (
select t1.courseid
,t1.coursename
,t2.catid
,t2
,catname
,t2.need_dte
from t1
,t2
where t1.courseid = t2.courseid
and t1.coursename = t2.coursename
) main
left outer join (
select courseid
,coursename
,need_dte training_info
) ui on main.courseid = ui.courseid
and main.coursename = ui.coursename
and main.need_dte = ui.need_dte
I have the above scenario in which i am trying to do left outer join between the tables "main" and "training_info".
main table: a inner join between t1 and t2 to get the training and the category details.
training_info(ui): has training details without category details.
here i have few course details in "main" and "ui" tables in common. and i have few unique course records in "main" table not in "ui" table. so i am trying to extract both the unique and common records.
I am able to get the results for this join, but the issue is with the need_dte. the need_dte field is present in both tables.In the result if the records are from "main" table am able to get the need_dte field updated from the inner table t2. if the records are from "ui" table in the result, the need_dte is not being populated.
Is there any way using this join set up I need to get the need_dte for the result records from training_info table also if those records have a need_dte.
Thanks!
Is this what you want?
select t1.courseid, t1.coursename, t2.catid, t2.catname,
coalesce(ti.need_dte, t2.need_dte ) as need_dte
from t1 join
t2
on t1.courseid = t2.courseid and
t1.coursename = t2.coursename left outer join
training_info ti
on t1.courseid = ti.courseid and
t1.coursename = ti.coursename and
t2.need_dte = ti.need_dte;
I find your query with the nested subqueries, multiple levels of naming, and archaic join syntax to be difficult to read. I think the above is what you are looking for. It returns need_dte from training_info, if present, and then from t2.

Access left join not working as I am picturing it

I am trying to write a query that involves 3 tables and left joining two of them onto a main one.
SELECT UNIT_MAIN.UNIT_NO, DEPT_MAIN.LEV_2, Card.CardNumberLong AS [Some
Number], Card.Enabled, F_CARD.CARD_NO, F_CARD.END_DT
FROM (((UNIT_MAIN
INNER JOIN DEPT_MAIN ON UNIT_MAIN.USING_DEPT = DEPT_MAIN.DEPT_ID)
LEFT JOIN Card ON (UNIT_MAIN.UNIT_NO = Card.UnitCode AND Card.Enabled = True) )
LEFT JOIN F_CARD ON (UNIT_MAIN.UNIT_ID = F_CARD.ASSIGNED_ID AND (F_CARD.END_DT) Is Null ))
WHERE (((UNIT_MAIN.STATUS)="A") AND ((DEPT_MAIN.LEV_2)="AM") AND ((Card.Enabled)=True) )
OR (((UNIT_MAIN.STATUS)="D") AND ((DEPT_MAIN.LEV_2)="AM") AND ((Card.Enabled)=True) )
The issue I am having is when F_CARD table has rows where the F_CARD.END_DT is not null, causing the main table (unit table) not to show up even though it is a left join and the F_CARD table rows did not satisfy the join condition (or I am to believe).
I don't have any where clauses on the F_CARD table and they are only on the join condition.
edit
When I perform
LEFT JOIN MFIVE_F_CARD ON (MFIVE_UNIT_DEPT_COMP_MAIN.UNIT_ID = MFIVE_F_CARD.ASSIGNED_ID AND ((MFIVE_F_CARD.END_DT) Is Null)
The unit does not appear if the F_CARD table contained rows that had an END_DT, I was to believe that since the left join condition failed, the inner table (unit table) should appear regardless.
If I remove any F_CARD related values from the query, the missing units I am looking for appear. It is an inner join, left join, left join. When the second left join happens, I lose rows even when they should appear.
I narrowed down my joins and just did the inner with the left with F_CARD. Trying to see why it doesnt return rows where the join fails.
Tried to do the following, however im getting an unsupported join error...
SELECT
UNIT_MAIN.UNIT_NO
,DEPT_MAIN.LEV_2
,Card.CardNumberLong AS [SomeNumber]
,Card.Enabled
,F_CARD.CARD_NO
,F_CARD.END_DT FROM
(
(
(
UNIT_MAIN
INNER JOIN DEPT_MAIN
ON UNIT_MAIN.USING_DEPT = DEPT_MAIN.DEPT_ID
)
LEFT JOIN Card
ON (UNIT_MAIN.UNIT_NO = Card.UnitCode AND Card.Enabled = True)
)
LEFT JOIN F_CARD
ON (UNIT_MAIN.UNIT_ID = F_CARD.ASSIGNED_ID AND F_CARD.END_DT Is Null)
) WHERE
(UNIT_MAIN.STATUS = "A" OR UNIT_MAIN.STATUS = "D")
AND DEPT_MAIN.LEV_2 = "AM"
Thanks.
I have a feeling it's because you have clauses in your joins that are doing boolean checks rather than matching records between the tables, i.e.
Card.Enabled = True and (F_CARD.END_DT) IS NULL
Try changing the query to:
SELECT
UNIT_MAIN.UNIT_NO
,DEPT_MAIN.LEV_2
,Card.CardNumberLong AS [SomeNumber]
,Card.Enabled
,F_CARD.CARD_NO
,F_CARD.END_DT
FROM
(
(
(
UNIT_MAIN
INNER JOIN DEPT_MAIN
ON UNIT_MAIN.USING_DEPT = DEPT_MAIN.DEPT_ID
)
LEFT JOIN Card
ON UNIT_MAIN.UNIT_NO = Card.UnitCode
)
LEFT JOIN F_CARD
ON UNIT_MAIN.UNIT_ID = F_CARD.ASSIGNED_ID
)
WHERE
(UNIT_MAIN.STATUS = "A" OR UNIT_MAIN.STATUS = "D")
AND DEPT_MAIN.LEV_2 = "AM"
AND Card.Enabled = True

Ambiguous outer join in MS Access

Trying to create an outer join on two other joined tables when recieving this error - I just dont see how to create two separate queries to make it work. Subqueries don't seem to work either, any help appreciated. I get errors for the below query, thanks.
SELECT
CardHeader.CardID, CardHeader.CardDescription, CardHeader.GloveSize,
CardHeader.GloveDescription, CardDetail.Bin, CardDetail.ItemID, Items.ItemDescription,
Items.VCatalogID, CardDetail.ChargeCode, CardDetail.Quantity, Items.Cost, CardColors.ColorID
FROM
((Items
INNER JOIN
(CardHeader INNER JOIN CardDetail ON CardHeader.CardID = CardDetail.CardID) ON Items.ItemID = CardDetail.ItemID)
LEFT JOIN
CardColors ON CardDetail.ItemID = CardColors.ItemID)
INNER JOIN
Colors ON CardColors.ColorID = Colors.ID
ORDER BY
CardHeader.CardID;
I tried the following which runs but asks for the following parameters (which it shouldnt)
CardHeader.ID, MainQry.CardID
SELECT
MainQry.ID, MainQry.CardDescription, MainQry.GloveSize,
MainQry.GloveDescription, MainQry.Bin, MainQry.ItemID,
MainQry.ItemDescription, MainQry.VCatalogID, MainQry.ChargeCode,
MainQry.Quantity, MainQry.Cost, SubQry.ColorID
FROM
(SELECT
CardHeader.ID, CardHeader.CardDescription, CardHeader.GloveSize,
CardHeader.GloveDescription, CardDetail.Bin,
CardDetail.ItemID, Items.ItemDescription, Items.VCatalogID,
CardDetail.ChargeCode, CardDetail.Quantity, Items.Cost
FROM
Items
INNER JOIN
(CardHeader
INNER JOIN
CardDetail ON CardHeader.CardID = CardDetail.CardID) ON Items.ItemID = CardDetail.ItemID
) AS MainQry
LEFT JOIN
(SELECT
CardColors.ItemID, CardColors.ColorID
FROM
CardColors
INNER JOIN
Colors ON CardColors.ColorID = Colors.ID) AS SubQry ON MainQry.ItemID = SubQry.ItemID
ORDER BY
MainQry.CardID;
The second SQL statement can be corrected by reference to the first statement and the error. The error is that both CardHeader.ID and MainQry.CardID are prompting for a parameter, which indicates that the inner statement should include CardHeader.CardID, rather than CardHeader.ID

Adding a join to a count() query

I have the following code taken from my previous question here and changed a little.
SELECT *
FROM ES_TOOL
INNER JOIN ES_HARDWARE ON ES_HARDWARE.eshw_ID = ES_TOOL.ESTOOL_HARDWARE
INNER JOIN ES_PAYMENT on ES_payment.espay_id = es_TOOL.estool_payment
LEFT JOIN (
SELECT
tchap.estch_tool, tfacet.estfa_tool,
count(marks.esmrk_value) AmtMarks
FROM ES_MARK marks
left Join ES_TOOL_FACET tfacet ON marks.esmark_tool_facet = tfacet.estfa_id --line added
left Join ES_TOOL_CHAPTER tchap ON marks.esmark_tool_chapter = tchap.estch_id
GROUP BY tchap.estch_tool
) h ON ES_TOOL.estool_id = h.estch_tool
I'm trying to add an additional join in an attempt to get a mark count from "marks" that meet either of the left join "ON" criteria. Without the extra line the query executes, but doesn't count marks that match "facet" criteria. With it I get the following error:
Msg 8120, Level 16, State 1, Line 1
Column 'ES_TOOL_FACET.estfa_tool' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Any help would be appreciated.
The error message means that ES_TOOL_FACET.estfa_tool needs to be included in the Group By.
When you use Group By, all non-aggregated columns must be included in the group by section.
This should be obvious, in your inner query:
SELECT tchap.estch_tool, tfacet.estfa_tool, count(marks.esmrk_value) AmtMarks
FROM ES_MARK marks
left Join ES_TOOL_FACET tfacet ON marks.esmark_tool_facet = tfacet.estfa_id --line added
left Join ES_TOOL_CHAPTER tchap ON marks.esmark_tool_chapter = tchap.estch_id
GROUP BY tchap.estch_tool
you have three selected columns, estch_tool which is in the GROUP BY clause, esmrk_value which is in an aggregate function, and estfa_tool which is neither in the GROUP BY clause nor in an aggregate function.
Your solution should be either:
GROUP BY tchap.estch_tool, tfacet.estfa_tool
AVG(tfacet.estfa_tool) or any aggregate function
There is a syntax error in this query -
SELECT
tchap.estch_tool,
tfacet.estfa_tool,
count(marks.esmrk_value) AmtMarks
FROM ES_MARK marks
left Join ES_TOOL_FACET tfacet ON
marks.esmark_tool_facet = tfacet.estfa_id --line added
left Join ES_TOOL_CHAPTER tchap ON
marks.esmark_tool_chapter = tchap.estch_id
GROUP BY tchap.estch_tool
GROUP BY mandates that any column appearing in SELECT list should either be aggregated or appear in GROUP BY clause.
So put an aggregate function - MIN, MAX, SUM, AVG etc on tfacet.estfa_tool because it does not appear in group by clause or include it there.
My solution comes in two variants. Which one better suits you may depend on which one will yield the better execution plan when tried on your data.
Description of variant #1: (In both cases I am describing only the logic behind the main SELECT's LEFT JOIN subselect, the part that is actually becomes substituted. But the scripts come as complete queries, equivalent to yours):
Pull and UNION ALL the items from both tools tables.
Join the list against the marks table accordingly.
Group the result set by tool items and get the counts.
The query:
SELECT *
FROM ES_TOOL
INNER JOIN ES_HARDWARE ON ES_HARDWARE.eshw_ID = ES_TOOL.ESTOOL_HARDWARE
INNER JOIN ES_PAYMENT on ES_payment.espay_id = es_TOOL.estool_payment
LEFT JOIN (
SELECT
tools.tool,
COUNT(*) AS AmtMarks
FROM (
SELECT 'tchap' AS tbl, estch_id AS id, estch_tool AS tool
FROM ES_TOOL_CHAPTER
UNION ALL
SELECT 'tfacet' AS tbl, estfa_id AS id, estfa_tool AS tool
FROM ES_TOOL_FACET
) tools
INNER JOIN ES_MARK marks
ON tools.tbl = 'tchap' AND tools.id = marks.esmark_tool_chapter
OR tools.tbl = 'tfacet' AND tools.id = marks.esmark_tool_facet
GROUP BY tools.tool
) h ON ES_TOOL.estool_id = h.tool
Variant #2:
Join ES_TOOL_CHAPTER against marks and get all the estch_tool values, including duplicates.
Similarly, join ES_TOOL_FACET against marks and get all the estfa_tool values, with duplicates too.
UNION ALL both sets.
Group the resulting set by tool items and get the counts.
And the query:
SELECT *
FROM ES_TOOL
INNER JOIN ES_HARDWARE ON ES_HARDWARE.eshw_ID = ES_TOOL.ESTOOL_HARDWARE
INNER JOIN ES_PAYMENT on ES_payment.espay_id = es_TOOL.estool_payment
LEFT JOIN (
SELECT
tools.tool,
COUNT(*) AS AmtMarks
FROM (
SELECT estch_tool AS tool
FROM ES_TOOL_CHAPTER tools
INNER JOIN ES_MARK marks ON tools.estch_id = marks.esmark_tool_chapter
UNION ALL
SELECT estfa_tool AS tool
FROM ES_TOOL_FACET tools
INNER JOIN ES_MARK marks ON tools.estfa_id = marks.esmark_tool_facet
) tools
GROUP BY tools.tool
) h ON ES_TOOL.estool_id = h.tool