Dynamically decide join table based on column value - sql

I want to dynamically inner join tables, here is my SQL query
Update temp
Set temp.Order_Id = parent.ID
from #TempTransactions AS temp
Inner Join (case when temp.OrderType = 1 then preorders else orders end) AS parent
ON parent.Cloud_Id = temp.Order_Id
Is it possible I can decide in above way or any other alternative?
If yes, how?

Two Left joins would do.
Update temp Set temp.Order_Id = COALESCE(p.ID, o.ID)
from #TempTransactions AS temp
LEFT Join preorders p ON p.Cloud_Id = temp.Order_Id AND temp.OrderType=1
LEFT JOIN orders o ON o.Cloud_Id = temp.Order_Id AND (temp.OrderType <> 1 OR temp.OrderType IS NULL)
WHERE COALESCE(p.ID, o.ID) IS NOT NULL

Related

How to replace only some Guids from a table to another, under conditions

I've created a View, but I wanted to change some of the result's Guids to Guids from another table, I want it directly in my view Result and I Don't know how?
select p.[Guid], c.[Guid] detailsGuid
INTO #temp1
from
ret_PayrollCalculationCommands s INNER JOIN
ret_PayrollCalculations p ON p.CalculationCommandGuid = s.Guid INNER JOIN
ret_vwPayrollCalculationDetails c ON c.CalculationGuid = p.Guid
you should INNER JOIN your table with same table that has target Guid column with another condition:
SELECT
p.[Guid],
c.[Guid] detailsGuid,
pMainCalculation.[Guid] AS [TargetGuid]
INTO #temp1
FROM
ret_PayrollCalculationCommands s INNER JOIN
ret_PayrollCalculations p ON p.CalculationCommandGuid = s.Guid INNER JOIN
ret_PayrollCalculations pMainCalculation ON pMainCalculation.CalculationCommandGuid = p.CalculationCommandGuid AND pMainCalculation.MainCalculation = 1 INNER JOIN
ret_vwPayrollCalculationDetails c ON c.CalculationGuid = p.Guid

why selecting particular columns from same table slows down query performance significantly?

I have SELECT statement that querying columns from tblQuotes. Why if I am selecting columns a.ProducerCompositeCommission and a.CompanyCompositeCommission, then query spinning forever.
Execution plans with and without those columns are IDENTICAL!
If I commented them out - then it brings result for 1 second.
SELECT
a.stateid risk_state1,
--those columns slows down performance
a.ProducerCompositeCommission,
a.CompanyCompositeCommission,
GETDATE() runDate
FROM
tblQuotes a
INNER JOIN
lstlines l ON a.LineGUID = l.LineGUID
INNER JOIN
tblSubmissionGroup tsg ON tsg.SubmissionGroupGUID = a.SubmissionGroupGuid
INNER JOIN
tblUsers u ON u.UserGuid = tsg.UnderwriterUserGuid
INNER JOIN
tblUsers u2 ON u2.UserGuid = a.UnderwriterUserGuid
LEFT OUTER JOIN
tblFin_Invoices tfi ON tfi.QuoteID = a.QuoteID AND tfi.failed <> 1
INNER JOIN
lstPolicyTypes lpt ON lpt.policytypeid = a.policytypeid
INNER JOIN
tblproducercontacts prodC ON prodC.producercontactguid = a.producercontactguid
INNER JOIN
tblProducerLocations pl ON pl.producerlocationguid = prodc.producerlocationguid
INNER JOIN
tblproducers prod ON prod.ProducerGUID = pl.ProducerGUID
LEFT OUTER JOIN
Catalytic_tbl_Model_Analysis aia ON aia.ImsControl = a.controlno
AND aia.analysisid = (SELECT TOP 1 tma2.analysisid
FROM Catalytic_tbl_Model_Analysis tma2
WHERE tma2.imscontrol = a.controlno)
LEFT OUTER JOIN
Catalytic_tbl_RDR_Analysis rdr ON rdr.ImsControl = a.controlno
AND rdr.analysisid = (SELECT TOP 1 tma2.analysisid
FROM Catalytic_tbl_RDR_Analysis tma2
WHERE tma2.imscontrol = a.controlno)
LEFT OUTER JOIN
tblProducerContacts mnged ON mnged.producercontactguid = ProdC.ManagedBy
LEFT OUTER JOIN
lstQuoteStatusReasons r1 ON r1.id = a.QuoteStatusReasonID
WHERE
l.LineName = 'EARTHQUAKE'
AND CAST(a.EffectiveDate AS DATE) >= CAST('2017-01-01' AS DATE)
AND CAST(a.EffectiveDate AS DATE) <= CAST('2017-12-31' AS DATE)
ORDER BY
a.effectiveDate
The execution plan can be found here:
https://www.brentozar.com/pastetheplan/?id=rJawDkTx-
I ran sp_help and this is what I see:
What exactly wrong with those columns?
I dont use them in a JOIN or anything. Why such bahaviour?
Table Size:
Indexes on table tblQuotes

SQL Server Query returning duplicate rows

I have a query of SQL that is a join of multiple tables, it is returning duplicate rows and after hours of going through it can't find out where its going wrong
SELECT
StkItem.iUOMStockingUnitID,
_etblUnits1.cUnitCode as 'parkSize',
_etblUnits2.cUnitCode as 'quantitySize',
InvNum.fInvTotExclForeign,
[_btblInvoiceLines].*,
[_rtblCountry].cCountryName,
[CurrencyHist].fBuyRate,
Vendor.Name,
InvNum.OrderDate,
InvNum.InvNumber
FROM
[dbo].[_btblInvoiceLines]
LEFT JOIN
StkItem ON StkItem.StockLink = [_btblInvoiceLines].iStockCodeID
LEFT JOIN
_etblUnits as _etblUnits1 ON _etblUnits1.idunits = StkItem.iUOMDefSellUnitID
LEFT JOIN
_etblUnits as _etblUnits2 ON _etblUnits2.idunits = StkItem.iUOMStockingUnitID
LEFT JOIN
InvNum ON iInvoiceID = AutoIndex
LEFT JOIN
Vendor ON Vendor.DCLink = InvNum.AccountID
LEFT JOIN
[_rtblCountry] ON [_rtblCountry].idCountry = Vendor.iCountryID
LEFT JOIN
[CurrencyHist] ON InvNum.ForeignCurrencyID = [CurrencyHist].iCurrencyID
WHERE
OrderNum = ''
AND [CurrencyHist].iCurrencyID = (SELECT TOP 1 iCurrencyID
FROM [CurrencyHist]
WHERE iCurrencyID = InvNum.ForeignCurrencyID
ORDER BY idCurrencyHist DESC)
Here is the query, any help will be highly appreciated, thanks in advance
From your previous comments, The problem is coming when you join [CurrencyHist]. From the name, it seems it's a history table and so must be having multiple rows as a history for each currency. To eliminate duplicate rows, you should join with the latest updated record for the particular currency. So, your query could be like below,
SELECT StkItem.iUOMStockingUnitID,
_etblUnits1.cUnitCode as 'parkSize',
_etblUnits2.cUnitCode as 'quantitySize',
InvNum.fInvTotExclForeign,
[_btblInvoiceLines].*,
[_rtblCountry].cCountryName,
[CurrencyHist].fBuyRate,
Vendor.Name,
InvNum.OrderDate,
InvNum.InvNumber
FROM [dbo].[_btblInvoiceLines]
LEFT JOIN StkItem ON StkItem.StockLink = [_btblInvoiceLines].iStockCodeID
LEFT JOIN _etblUnits as _etblUnits1 ON _etblUnits1.idunits = StkItem.iUOMDefSellUnitID
LEFT JOIN _etblUnits as _etblUnits2 ON _etblUnits2.idunits = StkItem.iUOMStockingUnitID
LEFT JOIN InvNum ON iInvoiceID = AutoIndex
LEFT JOIN Vendor ON Vendor.DCLink = InvNum.AccountID
LEFT JOIN [_rtblCountry] ON [_rtblCountry].idCountry = Vendor.iCountryID
LEFT JOIN (SELECT DENSE_RANK() over (partition by [CurrencyHist].iCurrencyID order by [CurrencyHist].LastUpdated desc) as rn,[CurrencyHist].iCurrencyID as 'iCurrencyID'
FROM [CurrencyHist] AS [CurrencyHist]
)[CurrencyHist] ON InvNum.ForeignCurrencyID = [CurrencyHist].iCurrencyID
and [CurrencyHist].rn=1
WHERE OrderNum = '' AND
[CurrencyHist].iCurrencyID = (SELECT TOP 1 iCurrencyID
FROM [CurrencyHist]
WHERE iCurrencyID = InvNum.ForeignCurrencyID
ORDER BY idCurrencyHist DESC)
Note : I have assumed that CurrencyHist table has a LastUpdated with DateTime datatype Column

How to use group by only for some columns in sql Query?

The following query returns 550 records, which I am then grouping by some columns in the controller via linq. However, how can I achieve the "group by" logic in the SQL query itself? Additionally, post-grouping, I need to show only 150 results to the user.
Current SQL query:
SELECT DISTINCT
l.Id AS LoadId
, l.LoadTrackingNumber AS LoadDisplayId
, planningType.Text AS PlanningType
, loadStatus.Id AS StatusId
, loadWorkRequest.Id AS LoadRequestId
, loadStatus.Text AS Status
, routeIds.RouteIdentifier AS RouteName
, planRequest.Id AS PlanId
, originPartyRole.Id AS OriginId
, originParty.Id AS OriginPartyId
, originParty.LegalName AS Origin
, destinationPartyRole.Id AS DestinationId
, destinationParty.Id AS DestinationPartyId
, destinationParty.LegalName AS Destination
, COALESCE(firstSegmentLocation.Window_Start, originLocation.Window_Start) AS StartDate
, COALESCE(firstSegmentLocation.Window_Start, originLocation.Window_Start) AS BeginDate
, destLocation.Window_Finish AS EndDate
AS Number
FROM Domain.Loads (NOLOCK) AS l
INNER JOIN dbo.Lists (NOLOCK) AS loadStatus ON l.LoadStatusId = loadStatus.Id
INNER JOIN Domain.Routes (NOLOCK) AS routeIds ON routeIds.Id = l.RouteId
INNER JOIN Domain.BaseRequests (NOLOCK) AS loadWorkRequest ON loadWorkRequest.LoadId = l.Id
INNER JOIN Domain.BaseRequests (NOLOCK) AS planRequest ON planRequest.Id = loadWorkRequest.ParentWorkRequestId
INNER JOIN Domain.Schedules AS planSchedule ON planSchedule.Id = planRequest.ScheduleId
INNER JOIN Domain.Segments (NOLOCK) os on os.RouteId = routeIds.Id AND os.[Order] = 0
INNER JOIN Domain.LocationDetails (NOLOCK) AS originLocation ON originLocation.Id = os.DestinationId
INNER JOIN dbo.EntityRoles (NOLOCK) AS originPartyRole ON originPartyRole.Id = originLocation.DockRoleId
INNER JOIN dbo.Entities (NOLOCK) AS originParty ON originParty.Id = originPartyRole.PartyId
INNER JOIN Domain.LocationDetails (NOLOCK) AS destLocation ON destLocation.Id = routeIds.DestinationFacilityLocationId
INNER JOIN dbo.EntityRoles (NOLOCK) AS destinationPartyRole ON destinationPartyRole.Id = destLocation.DockRoleId
INNER JOIN dbo.Entities (NOLOCK) AS destinationParty ON destinationParty.Id = destinationPartyRole.PartyId
INNER JOIN dbo.TransportationModes (NOLOCK) lictm on lictm.Id = l.LoadInstanceCarrierModeId
INNER JOIN dbo.EntityRoles (NOLOCK) AS carrierPartyRole ON lictm.CarrierId = carrierPartyRole.Id
INNER JOIN dbo.Entities (NOLOCK) AS carrier ON carrierPartyRole.PartyId = carrier.Id
INNER JOIN dbo.EntityRoles (NOLOCK) AS respPartyRole ON l.ResponsiblePartyId = respPartyRole.Id
INNER JOIN dbo.Entities (NOLOCK) AS respParty ON respPartyRole.PartyId = respParty.Id
INNER JOIN Domain.LoadOrders (NOLOCK) lo ON lo.LoadInstanceId = l.Id
INNER JOIN Domain.Orders (NOLOCK) AS o ON lo.OrderInstanceId = o.Id
INNER JOIN Domain.BaseRequests (NOLOCK) AS loadRequest ON loadRequest.LoadId = l.Id
--Load Start Date
LEFT JOIN Domain.Segments (NOLOCK) AS segment ON segment.RouteId = l.RouteId AND segment.[Order] = 0
LEFT JOIN Domain.LocationDetails (NOLOCK) AS firstSegmentLocation ON firstSegmentLocation.Id = segment.DestinationId
LEFT JOIN dbo.Lists (NOLOCK) AS planningType ON l.PlanningTypeId = planningType.Id
LEFT JOIN dbo.EntityRoles (NOLOCK) AS billToRole ON o.BillToId = billToRole.Id
LEFT JOIN dbo.Entities (NOLOCK) AS billTo ON billToRole.PartyId = billTo.Id
WHERE o.CustomerId in (34236) AND originLocation.Window_Start >= '07/19/2015 00:00:00' AND originLocation.Window_Start < '07/25/2015 23:59:59' AND l.IsHistoricalLoad = 0
AND loadStatus.Id in (285, 286,289,611,290)
AND loadWorkRequest.ParentWorkRequestId IS NOT NULL
AND routeIds.RouteIdentifier IS NOT NULL
AND (planSchedule.EndDate IS NULL OR (planSchedule.EndDate is not null and CAST(CONVERT(varchar(10), planSchedule.EndDate,101) as datetime) > CAST(CONVERT(varchar(10),GETDATE(),101) as datetime))) ORDER BY l.Id DESC
linq:
//Get custom grouped data
var loadRequest = (from lq in returnList
let loadDisplayId = lq.LoadDisplayId
let origin = lq.OriginId //get this origin for route
let destination = lq.DestinationId // get this destination for route
group lq by new
{
RouteId = lq.RouteName,
PlanId = lq.PlanId,
Origin = lq.OriginId,
Destination = lq.DestinationId
}
into grp
select new
{
RouteId = grp.Key.RouteId,
PlanId = grp.Key.PlanId,
Origin = grp.Key.Origin,
Destination = grp.Key.Destination,
Loads = (from l in grp select l)
}).OrderBy(x => x.Origin).ToList();
I'm guessing you want to Group By column 1 but include columns 2 and 3 in your Select. Using a Group By you cannot do this. However, you can do this using a T-SQL Windowing function using the OVER() operator. Since you don't say how you want to aggregate, I cannot provide an example. But look at T-SQL Windowing functions. This article might help you get started.
One important thing you need to understand about GROUP BY is that you must assume that there are multiple values in every column outside of the GROUP BY list. In your case, you must assume that for each value of Column1 there would be multiple values of Column2 and Column3, all considered as a single group.
If you want your query to process any of these columns, you must specify what to do about these multiple values.
Here are some choices you have:
Pick the smallest or the largest value for a column in a group - use MIN(...) or MAX(...) aggregator for that
Count non-NULL items in a group - use COUNT(...)
Produce an average of non-NULL values in a group - use AVG(...)
For example, if you would like to find the smallest Column2 and an average of Column3 for each value of Column1, your query would look like this:
select
Column1, MIN(Column2), AVG(Column3)
from
TableName
group by
Column1

Conditional Inner Join

I want to be able to inner join two tables based on the result of an expression.
What I've been trying so far:
INNER JOIN CASE WHEN RegT.Type = 1 THEN TimeRegistration ELSE DrivingRegistration AS RReg
ON
RReg.RegistreringsId = R.Id
RegT is a join I made just before this join:
INNER JOIN RegistrationTypes AS RegT ON R.RegistrationTypeId = RegT.Id
This SQL-script does not work.
So all in all, if the Type is 1, then it should join on the table TimeRegistration else it should join on DrivingRegistration.
Solution:
In my select statement I performed the following joins:
INNER JOIN RegistrationTypes AS RegT ON R.RegistrationTypeId = RegT.Id
LEFT OUTER JOIN TimeRegistration AS TReg ON TReg.RegistreringsId = R.Id AND RegT.Type = 1
LEFT OUTER JOIN DrivingRegistration AS DReg ON DReg.RegistreringsId = R.Id AND RegT.Type <>1
Then I edited my where-clause to output the correct, depending on the RegType, like this:
WHERE (CASE RegT.Type WHEN 1 THEN TReg.RegistreringsId ELSE DReg.RegistreringsId END = R.Id)
Try putting both tables in the query using LEFT JOIN's
LEFT JOIN TimeRegistration TR ON r.rid = TR.Id AND RegT.type =1
LEFT JOIN DrivingRegistration DR ON r.rid = DR.Id AND RegT.type <>1
Now, in you select clause, use
CASE RegType.Type WHEN 1 THEN TR.SomeField ELSE DR.someField END as SomeField
The other option is to use dynamic SQL
You probably need to perform two left joins, one onto TimeRegistration and one onto DrivingRegistration, and return the fields you want from the appropriate join table something like this:
LEFT JOIN TimeRegistration ON TimeRegistration.RegistreringsId = R.Id
LEFT JOIN DrivingRegistration ON DrivingRegistration.RegistreringsId = R.Id
and you select statement would be something like this:
SELECT CASE WHEN RegT.Type = 1 THEN TimeRegistration.Foo ELSE DrivingRegistration.Bar END
I like what you're trying to do, but I don't think SQL is that clever.
SELECT
R.foo, tr.bar
FROM
SomeTable AS R
INNER JOIN RegistrationTypes AS RegT ON R.RegistrationTypeId = RegT.Id
AND RegT1.Type = 1
INNER JOIN TimeRegistration AS tr ON /* whatever */
UNION
SELECT
R.foo, dr.bar
FROM
SomeTable AS R
INNER JOIN RegistrationTypes AS RegT ON R.RegistrationTypeId = RegT.Id
AND RegT1.Type = 2
INNER JOIN DrivingRegistration AS dr ON /* whatever */
So I had a scenario where there were three email columns in one table (don't ask why) and any of them could be null (or empty). In this example code I will just deal with a case where it is null.
I had to join it to another table by any of the emails to retrieve the users firstname.
Here is what worked
select
m.email1,
m.email2,
m.email3,
m2.firstName
from MyTable m
left join MyOtherTable m2 on m2.Email =
case when m.email1 is null then
case when m.email2 is null then
case when m.email3 null then
'nonexistent#mydomain.com' -- i stopped here
else m.email3 end
else wm.email2 end
else m.email1 end
Obviously you would include further conditions like
case when m.email1 is null or m.email1 = '' then ...
To cover for empty values.