I have the query below. When I use LEFT OUTER JOIN my query is very slow. It took more than 1 minute for the query to complete. Is there a way I can improve query speed while still using LEFT OUTER JOIN?
SELECT RISK.RA_HAZ_ID,
RISK.RA_CTRL_ID,
RISK.RA_HAZ_HAZARD_NAME,
RISK.RA_CTRL_CONTROL_NAME,
RISK.RA_CTRL_CONTROL_ID,
RISK.RA_IS_ESCALATED,
RISK.RA_IS_CONSEQUENCE,
RISK.RA_CTRL_OUTCOME,
RISK.RA_HAZ_IS_ALARP,
RISK.RA_HAZ_CONSEQUENCE,
RISK.RA_STEP_ORDER,
RISK.RA_STEP_NAME,
RISK.RA_HAZ_TYPE_NAME,
RISK.RA_CTRL_IS_REQUIRED,
RISK.RA_CTRL_IS_PRE_SELECTED,
RISK.RA_CTRL_IS_SELECTED,
RISK.RA_HAZ_SORT_ORDER,
RISK.RA_HAZ_COMMENT,
RISK.RA_CONTROL_COMMENT,
RISK.INIT_RISK,
RISK.RES_RISK,
RISK.RA_MATRIX_ID,
RISK.RES_RISK_LEVEL,
RISK.INIT_RISK_LEVEL,
MAX(RISK.RA_CTRL_ASSIGNED_FULL_NAME) AS RA_CTRL_ASSIGNED_FULL_NAME
FROM PRINT_RISK_ASSESSMENT_DETAILS RISK
LEFT OUTER JOIN PRINT_JSA_REFERENCE JSA ON JSA.OWNING_ACTIVITY_ID = RISK.OWNING_ACTIVITY_ID
WHERE JSA.ACTIVITY_ID = 10977 OR RISK.OWNING_ACTIVITY_ID = 10977
GROUP BY RISK.RA_HAZ_ID,
RISK.RA_CTRL_ID,
RISK.RA_HAZ_HAZARD_NAME,
RISK.RA_CTRL_CONTROL_NAME,
RISK.RA_CTRL_CONTROL_ID,
RISK.RA_IS_ESCALATED,
RISK.RA_IS_CONSEQUENCE,
RISK.RA_CTRL_OUTCOME,
RISK.RA_HAZ_IS_ALARP,
RISK.RA_HAZ_CONSEQUENCE,
RISK.RA_STEP_ORDER,
RISK.RA_STEP_NAME,
RISK.RA_HAZ_TYPE_NAME,
RISK.RA_CTRL_IS_REQUIRED,
RISK.RA_CTRL_IS_PRE_SELECTED,
RISK.RA_CTRL_IS_SELECTED,
RISK.RA_HAZ_SORT_ORDER,
RISK.RA_HAZ_COMMENT,
RISK.RA_CONTROL_COMMENT,
RISK.INIT_RISK,
RISK.RES_RISK,
RISK.RA_MATRIX_ID,
RISK.RES_RISK_LEVEL,
RISK.INIT_RISK_LEVEL
ORDER BY RISK.RA_STEP_ORDER,
RISK.RA_HAZ_SORT_ORDER,
RISK.RA_HAZ_HAZARD_NAME,
RISK.RA_HAZ_TYPE_NAME DESC,
RISK.RA_CTRL_IS_REQUIRED DESC,
RISK.RA_CTRL_IS_PRE_SELECTED DESC,
RISK.RA_CTRL_CONTROL_NAME
I want to improve query speed while still using LEFT OUTER JOIN
You can first see if you have indexes over important fields JSA.ACTIVITY_ID, JSA.OWNING_ACTIVITY_ID and RISK.OWNING_ACTIVITY_ID. If not, consider creating it.
Since you are grouping over the entiry table, if RISK has an important amount of row, it will be slow.
Related
Appropriate if somebody could help us to optimize below query
As per execution plane it seems the else part sub query is always executing, irrespective of conditions.
Won't CASE be short circuited? Why is it executing, even though it is not necessary?
IF OBJECT_ID('#Calculation') IS NOT NULL
DROP TABLE #Calculation;
SELECT
Result.IdDeckungsbeitrag,
Result.wert AS Wert,
REPLACE(#Formula, '<#PackagingCosts> ', Result.wert) AS Kalkulation
INTO
#Calculation
FROM
(SELECT
deck.IdDeckungsbeitrag,
CASE
WHEN lp.ID_VERPACKUNG_2 IS NULL
AND lp.ID_VERPACKUNG_3 IS NULL
THEN vg.VERPACKUNGSKOSTEN_PRO_EINHEIT * deck.Menge
ELSE
(
SELECT SUM(temp.me) * vg.VERPACKUNGSKOSTEN_PRO_EINHEIT
FROM
(
SELECT SUM(gv.MENGE) AS me
FROM dbo.KUNDENRECHNUNG_POSITION krp
LEFT JOIN dbo.LIEFERSCHEIN_POSITION lp
ON lp.ID_LIEFERSCHEIN_POSITION = krp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.GEBINDE_VERLADEN gv
ON gv.ID_LIEFERSCHEIN_POSITION = lp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.MATERIAL_BESTAND mb
ON mb.ID_MATERIAL_BESTAND = gv.ID_MATERIAL_BESTAND
LEFT JOIN dbo.MATERIAL_GEBINDE mg
ON mg.ID_MATERIAL_BESTAND = mg.ID_MATERIAL_BESTAND
WHERE mg.CHARGE_NUMMER = deck.Charge
GROUP BY mg.ID_VERPACKUNG
) temp
)
END AS wert
FROM #DeckungsbeitragCalculationPositions_TVP deck
LEFT JOIN dbo.KUNDENRECHNUNG_POSITION krp
ON krp.ID_KUNDENRECHNUNG_POSITION = deck.IdDeckungsbeitrag
LEFT JOIN dbo.LIEFERSCHEIN_POSITION lp
ON lp.ID_LIEFERSCHEIN_POSITION = krp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.VERPACKUNG vg
ON vg.ID_VERPACKUNG = lp.ID_VERPACKUNG_1
WHERE deck.IdMandant = #Id_Mandant
) Result;
Don't think of it as short-circuit or not. That's a procedural code mindset rather than a set-based mindset.
In SQL, the actual "execution" happens in the realm of table or index scans and seeks, hash matches, sorts, and the like. Pull data from different tables into a working set that will eventually produce the desired relational result.
Not seeing any real or projected execution plan, in this case (no pun intended), I suspect the query optimizer decided it was most efficient to first produce this result set in memory:
SELECT mg.ID_VERPACKUNG, mg.CHARGE_NUMMER, SUM(gv.MENGE) AS me
FROM dbo.KUNDENRECHNUNG_POSITION krp
LEFT JOIN dbo.LIEFERSCHEIN_POSITION lp
ON lp.ID_LIEFERSCHEIN_POSITION = krp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.GEBINDE_VERLADEN gv
ON gv.ID_LIEFERSCHEIN_POSITION = lp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.MATERIAL_BESTAND mb
ON mb.ID_MATERIAL_BESTAND = gv.ID_MATERIAL_BESTAND
LEFT JOIN dbo.MATERIAL_GEBINDE mg
ON mg.ID_MATERIAL_BESTAND = mg.ID_MATERIAL_BESTAND
GROUP BY mg.ID_VERPACKUNG, mg.CHARGE_NUMMER
This is the subquery from the ELSE clause, minus the WHERE clause conditions and with additional info added to the SELECT to make the match more effective. If the query optimizer can't be confident of meeting the WHEN clause a high percentage of the time, it might believe producing this larger ELSE set once to match against as needed is more efficient. Put another way, if it thinks it will have to run that subquery a lot anyway, it may try to pre-load it for all possible data.
We don't know enough about your database to suggest real solutions, but indexing around the ID_VERPACKUNG_2, ID_VERPACKUNG_3, and CHARGE_NUMMER fields might help. You might also be able to use a CTE, temp table, or table variable to help Sql Server to a better job of caching this data just once.
If the conditions of where are not met then the else will become active. If this is always the case then you would expect the following to return no rows:
select *
FROM #DeckungsbeitragCalculationPositions_TVP deck
LEFT JOIN dbo.KUNDENRECHNUNG_POSITION krp ON krp.ID_KUNDENRECHNUNG_POSITION = deck.IdDeckungsbeitrag
LEFT JOIN dbo.LIEFERSCHEIN_POSITION lp ON lp.ID_LIEFERSCHEIN_POSITION = krp.ID_LIEFERSCHEIN_POSITION
WHERE lp.ID_VERPACKUNG_2 IS NULL
AND lp.ID_VERPACKUNG_3 IS NULL
Need help for faster execution and optimisation for the below.
Find the execution plan in the 2 images attached..
Data in all tables are as follows:
company - 25 rows
warranty_period - 878 rows
company_claimtype - 216 rows
claim_type - 25 rows
customer - 15980 rows
auto_handle - 25 rows
auto_handle_condition - 31 rows
PART_REQUIRED_RETURN - 4521 rows
The following query took almost 12 mins to execute and it contains only left outer join of all the above mentioned tables:
select
company0_.ID as ID1_9_0_,
warrantype1_.ID as ID1_36_1_,
partsrequi2_.ID as ID1_20_2_,
claimtype4_.ID as ID1_8_3_,
autohandle5_.ID as ID1_4_4_,
autohandle6_.ID as ID1_5_5_,
customer7_.ID as ID1_14_6_,
company0_.CREATED as CREATED2_9_0_,
company0_.UPDATED as UPDATED3_9_0_,
company0_.AUTO_REJECT_USER as AUTO_REJ4_9_0_,
company0_.CLAIM_CREDIT_ORDER_HISTORY as CLAIM_CR5_9_0_,
company0_.CLAIM_ORDER_HISTORY as CLAIM_OR6_9_0_,
company0_.COMPANY_CODE as COMPANY_7_9_0_,
company0_.COMPANY_NAME as COMPANY_8_9_0_,
company0_.CONNECTED_TO_ERP as CONNECTE9_9_0_,
company0_.DEFAULT_CUSTOMER_ID as DEFAULT16_9_0_,
company0_.DATE_FORMAT as DATE_FO10_9_0_,
company0_.DISPLAY_WORK_LOCATION as DISPLAY11_9_0_,
company0_.DISTANCE_UNIT as DISTANC12_9_0_,
company0_.ENABLE_SHIPPING_LABEL as ENABLE_13_9_0_,
company0_.HANDLE_CREDIT_INVOICES as HANDLE_14_9_0_,
company0_.RETURNS_PARTS_DAYS as RETURNS15_9_0_,
warrantype1_.CREATED as CREATED2_36_1_,
warrantype1_.UPDATED as UPDATED3_36_1_,
warrantype1_.COMPANY_ID as COMPANY_8_36_1_,
warrantype1_.PERIOD_CONSUMER as PERIOD_C4_36_1_,
warrantype1_.PERIOD_PROFESSIONAL as PERIOD_P5_36_1_,
warrantype1_.PRODUCT_GROUP as PRODUCT_6_36_1_,
warrantype1_.PRODUCT_NO as PRODUCT_7_36_1_,
warrantype1_.COMPANY_ID as COMPANY_8_36_0__,
warrantype1_.ID as ID1_36_0__,
partsrequi2_.CREATED as CREATED2_20_2_,
partsrequi2_.UPDATED as UPDATED3_20_2_,
partsrequi2_.COMPANY_ID as COMPANY_5_20_2_,
partsrequi2_.PRODUCT_NO as PRODUCT_4_20_2_,
partsrequi2_.COMPANY_ID as COMPANY_5_20_1__,
partsrequi2_.ID as ID1_20_1__,
claimtype4_.CREATED as CREATED2_8_3_,
claimtype4_.UPDATED as UPDATED3_8_3_,
claimtype4_.CATEGORY as CATEGORY4_8_3_,
claimtype4_.CLAIM_TYPE as CLAIM_TY5_8_3_,
claimtype4_.SORT_ORDER as SORT_ORD6_8_3_,
claimtype4_.TEXT_KEY as TEXT_KEY7_8_3_,
claimtypes3_.COMPANY_ID as COMPANY_2_10_2__,
claimtypes3_.CLAIMTYPE_ID as CLAIMTYP1_10_2__,
autohandle5_.CREATED as CREATED2_4_4_,
autohandle5_.UPDATED as UPDATED3_4_4_,
autohandle5_.[ACTION] as ACTION4_4_4_,
autohandle5_.[ACTIVE] as ACTIVE5_4_4_,
autohandle5_.[ASSIGN] as ASSIGN6_4_4_,
autohandle5_.[COMPANY_ID] as COMPANY_8_4_4_,
autohandle5_.[NAME] as NAME7_4_4_,
autohandle5_.[COMPANY_ID] as COMPANY_8_4_3__,
autohandle5_.ID as ID1_4_3__,
autohandle6_.CREATED as CREATED2_5_5_,
autohandle6_.UPDATED as UPDATED3_5_5_,
autohandle6_.AUTO_HANDLE_ID as AUTO_HAN7_5_5_,
autohandle6_.[OPERATOR] as OPERATOR4_5_5_,
autohandle6_.[TYPE] as TYPE5_5_5_,
autohandle6_.[VALUE] as VALUE6_5_5_,
autohandle6_.AUTO_HANDLE_ID as AUTO_HAN7_5_4__,
autohandle6_.ID as ID1_5_4__,
customer7_.CREATED as CREATED2_14_6_,
customer7_.UPDATED as UPDATED3_14_6_,
customer7_.COMPANY_ADDRESS as COMPANY_4_14_6_,
customer7_.STREET as STREET5_14_6_,
customer7_.ZIPCODE as ZIPCODE6_14_6_,
customer7_.COMPANY_ID as COMPANY_9_14_6_,
customer7_.CUSTOMER_NO as CUSTOMER7_14_6_,
customer7_.NAME as NAME8_14_6_
from
COMPANY company0_
left outer join
WARRANTY_PERIOD warrantype1_
on company0_.ID=warrantype1_.COMPANY_ID
left outer join
PART_REQUIRED_RETURN partsrequi2_
on company0_.ID=partsrequi2_.COMPANY_ID
left outer join
COMPANY_CLAIMTYPE claimtypes3_
on company0_.ID=claimtypes3_.COMPANY_ID
left outer join
CLAIM_TYPE claimtype4_
on claimtypes3_.CLAIMTYPE_ID=claimtype4_.ID
left outer join
AUTO_HANDLE autohandle5_
on company0_.ID=autohandle5_.[COMPANY_ID]
left outer join
AUTO_HANDLE_CONDITION autohandle6_
on autohandle5_.ID=autohandle6_.AUTO_HANDLE_ID
left outer join
CUSTOMER customer7_
on company0_.DEFAULT_CUSTOMER_ID=customer7_.ID
What I find particularly strange is that you get about 585k records from PART_REQUIRED_RETURN and then tag those along but when the server adds the AUTO_HANDLE data things suddenly multiply to 2.1M records. Are you sure your join takes into account the entire PK? As your query looks right now I would assume that ID is the PK of AUTO_HANDLE, however the numbers seem to contradict this. Something similar happens when adding the AUTO_HANDLE_CONDITION data.
In the end you are reading 3.3M rows, or about 4.5Gb of data. I don't think you can expect to bring this down to seconds.
I have the below tables in my DB.
Orders:
OrderNo.........ItemNo........OrderQty
1000________10_________10
2000________20_________10
VendorPO:
OrderNo.........ItemNo........VendorPO........POQty
1000________10_________100__________5
2000________20_________100__________7
2000________20_________200__________3
And I used this Query:
SELECT Order.OrderNo, Order.ItemNo, Order.OrderQty, VendorPO.VendorPO, VendorPO.POQty
FROM [Order]
INNER JOIN VendorPO ON (Order.ItemNo = VendorPO.ItemNo)
AND (Order.OrderNo = VendorPO.OrderNo);
With these results:
Query Result
OrderNo.........ItemNo........OrderQty........VendorPO........POQty
1000________10__________10_________100__________5
2000________20__________10_________100__________7
2000________20__________10_________200__________3
I want to avoid repetition of the quantity in the query result, where Item quantity 10 is repeated twice against two PO reference with POQty 3 and 7.
I appreciate your support on finding a way to avoid order quantity repetition.
I have tried to find answers to this question on the net but am not really getting anywhere.
I tried to do screen shots but don't have enough rep. Anyway.
Here is my current query structure.
Tables:
tblInventoryItems(intSerial, intItem, intStyle) -This is the list of current items that are on inventory(built or unbuilt)
tblLocations(intLocationID, chrLocationName, intLotType)
tblItemStyles(intItemStyleID, intBasic Style)
tblItemList(intItemID, intType, intSubtype, intStyle)
tblCommissions(intBuildEvent, intItemType, intItemSubtype)
tblBuildEvents(intSerial, intBuildEventType, dtEventDate)
First Set of Queries
qryCompletedBarns:
SELECT dbo.tblInventoryItems.intSerial,dbo.tblBuildEvents.dtEventDate
FROM dbo.tblItemList
INNER JOIN dbo.tblItemStyles ON
dbo.tblItemList.intStyle = dbo.tblItemStyles.intBasicStyle
INNER JOIN dbo.tblInventoryItems ON
dbo.tblItemList.intItemID = dbo.tblInventoryItems.intItem AND
dbo.tblItemStyles.intItemStyleID = dbo.tblInventoryItems.intStyle
INNER JOIN dbo.tblCommissions ON
dbo.tblItemList.intSubType = dbo.tblCommissions.intItemSubtype
AND dbo.tblItemList.intType = dbo.tblCommissions.intItemType
INNER JOIN dbo.tblBuildEvents ON
dbo.tblBuildEvents.intBuildEventType = dbo.tblCommissions.intBuildEvent AND
dbo.tblInventoryItems.intSerial = dbo.tblBuildEvents.intSerial
WHERE (dbo.tblCommissions.ynCompletesBarn = 1)
So First we select all items that have a build event that qualifies them as completed. An item can have multiple build events but there is only one that qualifies it as completed
qryCompletedBarnDateFilter:
SELECT qryCompletedBarns.intSerial, qryCompletedBarns.dtEventDate
FROM qryCompletedBarns
WHERE (((qryCompletedBarns.dtEventDate)<=InventoryDate()));
Then we jump to Access and filter those results by a UDF that pulls the criteria for the build date of the item(Saved report definitions are stored in a table).
Now, we have a list of all Inventory items that meet the first criteria, which is that they must be built on or before the Inventory Date that the user selects.
Second set of queries:
qryInventoryLogDateFilter:
SELECT tblHaulLogs.*, tblHaulLogs.dtmHaulDate
FROM tblHaulLogs
WHERE (((tblHaulLogs.dtmHaulDate)<=InventoryDate()));
Get all the Haullogs (or you could call them inventory transactions) that are equal to or older than the InventoryDate criteria.
qryLastLogForBarn:
SELECT t1.intSerial, t1.intHaulType, t1.intDestinationSource, t1.intDestination
FROM qryInventoryLogDateFilter AS t1
LEFT JOIN qryInventoryLogDateFilter AS t2
ON (t1.intLogID < t2.intLogID) AND (t1.intSerial = t2.intSerial)
WHERE t2.intLogID IS NULL;
Get the last inventory transaction for each Inventory Item. This query is actually very fast when executed on the server natively.
qryInventoryCurrentCustomer:
SELECT tblSales.intSerial, tblCustomers.chrFirstName + ' ' + tblCustomers.chrLastName
AS chrCustomerName, tblSales.dtSaleDate
FROM tblSales INNER JOIN tblCustomers ON
tblSales.intCustomer = tblCustomers.intCustID
LEFT OUTER JOIN tblHaulLogs ON
tblSales.intSaleID = tblHaulLogs.intOrigon
WHERE (tblHaulLogs.intHaulType IS NULL) AND (tblSales.bolSaleCancelled = 0)
OR (tblHaulLogs.intHaulType <> 3) AND
(tblSales.intOrderType <4) AND (tblSales.bolSaleCancelled = 0)
GROUP BY tblSales.intSerial, tblCustomers.chrFirstName + ' ' + tblCustomers.chrLastName,
tblSales.dtSaleDate, tblSales.intOrderType;
This query does not actually return an "Inventory Item" but rather checks the sales table and returns a customer name if the inventory item was sold.
Now we finally join the two "sections" and the "Current Customer Query":
SELECT qryCompletedBarnDateFilter.intSerial, qryLastLogForBarn.intHaulType,
IIf(IsNull([intDestination]),7,[intDestination]) AS Location,
qryInventoryCurrentCustomer.chrCustomerName,
qryInventoryCurrentCustomer.dtSaleDate, qryCompletedBarnDateFilter.dtEventDate
FROM (qryCompletedBarnDateFilter
LEFT JOIN qryLastLogForBarn
ON qryCompletedBarnDateFilter.intSerial = qryLastLogForBarn.intSerial)
LEFT JOIN qryInventoryCurrentCustomer
ON qryCompletedBarnDateFilter.intSerial = qryInventoryCurrentCustomer.intSerial
WHERE (((qryLastLogForBarn.intDestinationSource)=1
Or (qryLastLogForBarn.intDestinationSource) Is Null));
Then we join to the "Locations" table to get the name of the inventory item's location, and also filter out a certain type of location.
qryRetailBarnsOnInventory:
SELECT qryBarnsOnInventory.intSerial, qryBarnsOnInventory.Location,
tblLocations.chrLocationName, qryBarnsOnInventory.chrCustomerName,
qryBarnsOnInventory.dtEventDate, qryBarnsOnInventory.intHaulType
FROM tblLocations
INNER JOIN qryBarnsOnInventory
ON tblLocations.intLocationID = qryBarnsOnInventory.Location
WHERE (((tblLocations.intLotType)=1));
The Final Query:
SELECT tblItemStyles.chrItemStyle, tblInventoryItems.intSerial,
tblItemSizeList.intItemSize, tblItemPrices.ccyPrice,
tblInventoryItems.txtOptions, qryRetailBarnsOnInventory.chrCustomerName,
qryRetailBarnsOnInventory.dtEventDate, qryRetailBarnsOnInventory.intHaulType,
qryRetailBarnsOnInventory.chrLocationName, tblItemList.intType,
tblItemList.intSubType, tblItemList.intStyle, tblItemSizes.intItemSizeID,
tblItemStyles.intItemStyleID, tblItemPrices.intPriceSheet,
tblInventoryItems.bolinTransit
FROM tblItemSizeList INNER JOIN (tblItemSizes INNER JOIN
(qryRetailBarnsOnInventory INNER JOIN (((tblItemList INNER JOIN
tblItemPrices ON tblItemList.intItemID = tblItemPrices.intItemID)
INNER JOIN tblItemStyles ON tblItemList.intStyle = tblItemStyles.intBasicStyle)
INNER JOIN tblInventoryItems
ON (tblItemList.intItemID = tblInventoryItems.intItem)
AND (tblItemStyles.intItemStyleID = tblInventoryItems.intStyle))
ON qryRetailBarnsOnInventory.intSerial = tblInventoryItems.intSerial)
ON tblItemSizes.intItemSizeID = tblItemList.intSize)
ON tblItemSizeList.intItemSizeID = tblItemSizes.intSize
WHERE (((tblItemList.intType) Like ItemType())
AND ((tblItemList.intSubType) Like ItemSubType())
AND ((tblItemList.intStyle) Like BasicStyle())
AND ((tblItemSizes.intItemSizeID) Like ItemSize())
AND ((tblItemStyles.intItemStyleID) Like SubStyle())
AND ((tblItemPrices.intPriceSheet)=1)
AND ((tblInventoryItems.bolinTransit)=False)
AND ((IIf(IsNull([intHaulType]),2,3)) Like NewUsed())
AND ((IIf(IsNull([chrCustomerName]),2,3)) Like IsSold())
AND ((qryRetailBarnsOnInventory.Location) Like LotID()));
Summary:
In plain English, here is what I want to happen:
Get all Inventory Items from the inventory items table that were completed on or before the date criteria, then get the last inventory transaction on or before the date criteria for each of those items. And then filter by additional criteria that the user provides
I have the correct results but it is SLOW! Like 10-15 seconds. And we do a tremendous amount of queries every day.
What my idea was is to put this all on SQL Server in sprocs or views. If I do this all with views on SQL server and type manual criteria in, it's blazing fast. The problem I have is that every query requires a parameter. Not just the last one. I can pass parameters for the last query all right with a passthrough query but how do I pass the date criteria parameters for the first query?
EDIT:
Would it be possible to get the date criteria from another table? The criteria is stored in another table in the DB. If I could perform some kind of lookup to get that value and use it as the criteria that would make life really simple.
This query has been keeping me busy for the last couple of days. I tried to rewrite it with different ideas but I keep having the same problem. To simplify the problem I put part of my query in a view, this view returns 23 records. Using a left join I would like to add fields coming from the table tblDatPositionsCalc to these 23 records. As you can see I have an additional condition on the tblDatPositionsCalc in order to only consider the most recent records. With this condition it would return 21 records. The join should be on two fields together colAccount and colId.
I simply want the query to return the 23 records from the view and where possible have the information from tblDatPositionsCalc. There is actually only 2 records in the view without corresponding id and account in tblDatPositionsCalc, that means out of the 23 records only 2 will have missing values in the fields coming from the table tblDatPositionsCalc.
The problem with my query is that it only returns the 21 records from tblDatPositionsCalc. I don't understand why. I tried to move the condition on date in just after the JOIN condition but that did not help.
SELECT TOP (100) PERCENT
dbo.vwCurrPos.Account,
dbo.vwCurrPos.Id,
dbo.vwCurrPos.TickerBB,
dbo.vwCurrPos.colEquityCode,
dbo.vwCurrPos.colType,
dbo.vwCurrPos.colCcy,
dbo.vwCurrPos.colRegion,
dbo.vwCurrPos.colExchange,
dbo.vwCurrPos.[Instr Type],
dbo.vwCurrPos.colMinLastDay,
dbo.vwCurrPos.colTimeShift,
dbo.vwCurrPos.Strike,
dbo.vwCurrPos.colMultiplier,
dbo.vwCurrPos.colBetaVol,
dbo.vwCurrPos.colBetaEq,
dbo.vwCurrPos.colBetaFloor,
dbo.vwCurrPos.colBetaCurv,
dbo.vwCurrPos.colUndlVol,
dbo.vwCurrPos.colUndlEq,
dbo.vwCurrPos.colUndlFut,
tblDatPositionsCalc_1.colLots,
dbo.vwCurrPos.[Open Positions],
dbo.vwCurrPos.colListMatShift,
dbo.vwCurrPos.colStartTime,
tblDatPositionsCalc_1.colPrice,
tblDatPositionsCalc_1.colMktPrice,
dbo.vwCurrPos.colProduct,
dbo.vwCurrPos.colCalendar,
CAST(dbo.vwCurrPos.colExpiry AS DATETIME) AS colExpiry,
dbo.vwCurrPos.colEndTime,
CAST(tblDatPositionsCalc_1.colDate AS datetime) AS colDate,
dbo.vwCurrPos.colFund,
dbo.vwCurrPos.colExchangeTT,
dbo.vwCurrPos.colUserTag
FROM dbo.vwCurrPos
LEFT OUTER JOIN dbo.tblDatPositionsCalc AS tblDatPositionsCalc_1
ON tblDatPositionsCalc_1.colId = dbo.vwCurrPos.Id
AND tblDatPositionsCalc_1.colAccount = dbo.vwCurrPos.Account
WHERE (tblDatPositionsCalc_1.colDate =
(SELECT MAX(colDate) AS Expr1 FROM dbo.tblDatPositionsCalc))
ORDER BY
dbo.vwCurrPos.Account,
dbo.vwCurrPos.Id,
dbo.vwCurrPos.colEquityCode,
dbo.vwCurrPos.colRegion
Any idea what might cause the problem?
(Option 1) DrCopyPaste is right so your from clause would look like:
...
FROM dbo.vwCurrPos
LEFT OUTER JOIN dbo.tblDatPositionsCalc AS tblDatPositionsCalc_1
ON tblDatPositionsCalc_1.colId = dbo.vwCurrPos.Id
AND tblDatPositionsCalc_1.colAccount = dbo.vwCurrPos.Account
and (tblDatPositionsCalc_1.colDate =
(SELECT MAX(colDate) AS Expr1 FROM dbo.tblDatPositionsCalc))
...
reason: the where clause restriction of left joined to column = some expression with fail to return for "null = something" so the row will be removed.
(Option 2) As oppose to pushing code in to additional views where it is harder to maintain you can nest sql select statements;
select
X.x1,X.x2,
Y.*
from X
left join
(select Z.z1 as y1, Z.z2 as y2, Z.z3 as y3
from Z
where Z.z1 = (select max(Z.z1) from Z)
) as Y
on x.x1 = Y.y1 and X.x2 = Y.y2
The advantage here is you check each nested sub query a move out quickly. Although if you still building up more logic check out common table expressions (CTE's) http://msdn.microsoft.com/en-us/library/ms175972.aspx