Join max date from a related table - sql

I have the following queries:
select AccountId
into #liveCustomers
from AccountExtensionBase where New_duos_group not in ('T053','T054')
and New_AccountStage = 7
select AccountId
into #customerWhoLeft
from New_marketmessagein as a
inner join AccountExtensionBase as b on a.new_accountmminid = b.AccountId
where New_MessageTypeCode = '105L'
and a.New_EffectiveFromDate > '30 jun 2016'
and b.New_duos_group not in ('T053','T054')
select
accountid
, New_MPRNNumber
, New_duos_group
, New_CommercialAgreementDayRate
, New_CommercialAgreementNightRate
, New_CommercialAgreementHeatRate
, New_Tariffpriceagreedatsignup
, New_Tariffname
into
#monthCustomers
from
AccountExtensionBase
where
AccountId in (select * from #customerWhoLeft)
or
AccountId in (select * from #liveCustomers)
I now wish to join a table called usagefactorExtensionBase and join only the row containing the most recent read date but when I try to join this to my table of 4985 monthly customers I get like 106,813 rows using this code so I think my join or methodology has gone awry, can someone please help me correct the error so I display the list of monthCustomers plus the read details of their most recent read.
Attempting:
select
accountid
, New_MPRNNumber
, New_duos_group
, New_CommercialAgreementDayRate
, New_CommercialAgreementNightRate
, New_CommercialAgreementHeatRate
, New_Tariffpriceagreedatsignup
, New_Tariffname
, max(b.New_EffectiveFromDate)
, b.New_ActualUsageFactor
, b.New_EstimatedUseage
from
#monthCustomers as a
left join
New_marketmessageinusagefactorExtensionBase as b
on a.AccountId = b.new_accountmmusagefactorid
group by
accountid
, New_MPRNNumber
, New_duos_group
, New_CommercialAgreementDayRate
, New_CommercialAgreementNightRate
, New_CommercialAgreementHeatRate
, New_Tariffpriceagreedatsignup
, New_Tariffname
, b.New_ActualUsageFactor
, b.New_EstimatedUseage

try this,
SELECT
accountid,
New_MPRNNumber,
New_duos_group,
New_CommercialAgreementDayRate,
New_CommercialAgreementNightRate,
New_CommercialAgreementHeatRate,
New_Tariffpriceagreedatsignup,
New_Tariffname,
b.New_EffectiveFromDate,
b.New_ActualUsageFactor,
b.New_EstimatedUseage
FROM #monthCustomers AS a
-- Get only max date rows for each AccountID
LEFT JOIN( SELECT t1.*
FROM New_marketmessageinusagefactorExtensionBase AS t1
INNER JOIN ( SELECT new_accountmmusagefactorid, MAX(New_EffectiveFromDate) AS New_EffectiveFromDate_Max
FROM New_marketmessageinusagefactorExtensionBase
GROUP BY new_accountmmusagefactorid
) AS t2 ON t2.new_accountmmusagefactorid = t1.new_accountmmusagefactorid
AND t2.New_EffectiveFromDate_Max = t1.New_EffectiveFromDate
)AS b
ON a.AccountId = b.new_accountmmusagefactorid
there might be rows with same date, try below if is works,
SELECT
accountid,
New_MPRNNumber,
New_duos_group,
New_CommercialAgreementDayRate,
New_CommercialAgreementNightRate,
New_CommercialAgreementHeatRate,
New_Tariffpriceagreedatsignup,
New_Tariffname,
b.New_EffectiveFromDate,
b.New_ActualUsageFactor,
b.New_EstimatedUseage
FROM #monthCustomers AS a
-- Get only max date rows for each AccountID
LEFT JOIN( SELECT New_MPRNNumber,
New_duos_group,
New_CommercialAgreementDayRate,
New_CommercialAgreementNightRate,
New_CommercialAgreementHeatRate,
New_Tariffpriceagreedatsignup,
New_Tariffname,
MAX(New_EffectiveFromDate) AS New_EffectiveFromDate,
New_ActualUsageFactor,
New_EstimatedUseage
FROM New_marketmessageinusagefactorExtensionBase AS t1
GROUP BY
New_MPRNNumber,
New_duos_group,
New_CommercialAgreementDayRate,
New_CommercialAgreementNightRate,
New_CommercialAgreementHeatRate,
New_Tariffpriceagreedatsignup,
New_Tariffname,
New_ActualUsageFactor,
New_EstimatedUseage
)AS b
ON a.AccountId = b.new_accountmmusagefactorid

Related

Use CTE in SQL to flag DUPLICATES and reference in sub-query

So I have the following CTE:
with dupeinv AS (
select * from (
select
tci.t_idoc,
tci.t_idat,
ROW_NUMBER() OVER (partition by tci.t_idoc ORDER BY tci.t_idoc, tci.t_idat DESC) as rn
from [ln106].[dbo].tcisli305100 tci
) as t
where t.rn = 1
)
There are duplicates in the above table ([ln106].[dbo].tcisli305100) , hence the CTE to get single values. I want to format just these values in the below query (prefixed with ---)
select 'JCI' as BU,
RTRIM(LTRIM(cl.t_orno)) AS SALES_ORDER_NUMBER
, cl.t_pono AS SALES_ORDER_LINE_NUMBER
, CONCAT(cl.t_shpm, cl.t_pono, cl.t_idoc) AS SHIPPING_RECORD_ID
,CASE WHEN cl.t_dqua = 0 or cl.t_dqua is null THEN cl.t_amti ELSE
cl.t_amti / cl.t_dqua END AS AR_INVOICE_LINE_ITEM_PRICE_LOCAL
, cl.t_line AS AR_INVOICE_LINE_NUMBER
, cl.t_dqua AS AR_INVOICE_LINE_ITEM_QUANTITY
--- , concat(dupeinv.t_idoc,'|',format(dupeinv.t_idat,'MMddyyyy') ---
,ci.t_ccur AS AR_INVOICE_CURRENCY
, ci.t_idat AS AR_INVOICE_DATE
FROM [ln106].[dbo].tcisli310100 cl
LEFT JOIN [ln106].[dbo].tcisli305100 ci ON cl.t_idoc = ci.t_idoc
LEFT JOIN t di on cl.t_doc = di_t_doc
LEFT JOIN (SELECT t_orno,t_pono FROM [ln106].[dbo].ttdsls401100 WHERE t_oltp <> 1 group by t_orno,t_pono) as l --Jed 10162020 Changed the join to prevent duplicate records
ON l.t_orno=cl.t_orno COLLATE SQL_Latin1_General_CP1_CI_AS AND l.t_pono=cl.t_pono
LEFT JOIN dupeinv tci on cl.r_idoc = ci.t_doc
WHERE ci.t_idat > '2017'
Query doesn't like me referencing it in the main query. Can anyone help, or suggest a better idea?
Your final query should look something like this:
WITH dupeinv AS
(SELECT *
FROM
(SELECT tci.t_idoc,
tci.t_idat,
ROW_NUMBER() OVER (PARTITION BY tci.t_idoc
ORDER BY tci.t_idoc,
tci.t_idat DESC) AS rn
FROM [ln106].[dbo].tcisli305100 tci) AS t
WHERE t.rn = 1 )
SELECT 'JCI' AS BU,
RTRIM(LTRIM(cl.t_orno)) AS SALES_ORDER_NUMBER ,
cl.t_pono AS SALES_ORDER_LINE_NUMBER ,
CONCAT(cl.t_shpm, cl.t_pono, cl.t_idoc) AS SHIPPING_RECORD_ID ,
CASE
WHEN cl.t_dqua = 0
OR cl.t_dqua IS NULL THEN cl.t_amti
ELSE cl.t_amti / cl.t_dqua
END AS AR_INVOICE_LINE_ITEM_PRICE_LOCAL ,
cl.t_line AS AR_INVOICE_LINE_NUMBER ,
cl.t_dqua AS AR_INVOICE_LINE_ITEM_QUANTITY ,
concat(dupeinv.t_idoc,
'|',
format(dupeinv.t_idat, 'MMddyyyy')) ,
ci.t_ccur AS AR_INVOICE_CURRENCY ,
ci.t_idat AS AR_INVOICE_DATE
FROM [ln106].[dbo].tcisli310100 cl
LEFT JOIN [ln106].[dbo].tcisli305100 ci ON cl.t_idoc = ci.t_idoc
LEFT JOIN t di ON cl.t_doc = di_t_doc
LEFT JOIN
(SELECT t_orno,
t_pono
FROM [ln106].[dbo].ttdsls401100
WHERE t_oltp <> 1
GROUP BY t_orno,
t_pono) AS l --Jed 10162020 Changed the join to prevent duplicate records
ON l.t_orno=cl.t_orno COLLATE SQL_Latin1_General_CP1_CI_AS
AND l.t_pono=cl.t_pono
LEFT JOIN dupeinv tci ON cl.r_idoc = ci.t_doc
WHERE ci.t_idat > '2017'

Applying cluster indexing to a view in SQL Server 2012

I have a view which queries around 1+ million rows and takes around 10-15 minutes to finish its execution,I want to provide cluster indexing to it so that it exists in physical schema and takes less time to load, but there are a number of constraints in order to provide cluster indexing i.e. only INNER JOIN are allowed and No subqueries should be present in views defination how do I replace the LEFT JOIN present in this view with INNER JOIN and how do I eliminate subqueries from this views defination so that cluster indexing can be applied to it.
CREATE view [dbo].[FTM_ProfileDetailsView] with SCHEMABINDING as
select FTM.Id
, FTM.EmployeeId
, FTM.CustomerId
, FTM.AbsenceFirstDate
, FTM.BackgroundHistory
, FTM.BackgroundHistoryComments
, FTM.IsEmployeeAbsent,FTM.ServiceId
, Case When isnull(FTM.IsSelfManagement,'')='' THEN cast(0 as bit) ELSE FTM.IsSelfManagement END as IsSelfManagement
, PR.ServiceLineId,FTM.ProfileId,PR.StatusId,Status.Status as StatusName
, PR.ReasonID
, PR.ModifiedDate
, PR.WithdrawnReason
, PR.CreatedBy
, PR.CreatedDate
, PR.IsActive
, mgrs.usernames as LineManagers
, cust.CustomerName
, ltrim(rtrim( emp.EmployeeTitle+' '+ emp.FirstName+' '+ emp.Surname)) as EmployeeFullName
, FTM.ProfileManagerId
, FTM.IsProfileManagement
, AM.MonitoringChecks
, AM.Frequency
, AM.ProfileManagerNotes
, AM.TaskDateAndTime
, FTM.ProfileManagementCriteriaId
,cast(case when PR.StatusId = 13 then 1 else 0 end as bit) as IsActiveMonitoring
, CustServ.CustomerServiceName
, BU.Name as BusinessUnit
, emp.DASID
, emp.DateOfBirth as EmployeeDOB
, addr.PostCode
, coninfo.Email
, (select top 1
StatusId from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc) as LatestInterventionStatusId
, (select name from dbo.FTM_Intervention Intr
where Intr.Id=(select top 1 InterventionId from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc))
as LatestInterventionName from FTM_Profile FTM
LEFT JOIN dbo.ProfileManagersView mgrs ON mgrs.ProfileID = FTM.ProfileID
INNER JOIN dbo.Customer cust on cust.Id= FTM.CustomerId
INNER JOIN dbo.Employee emp on emp.Id = FTM.EmployeeId
INNER JOIN dbo.PR_Profile PR on PR.Profileid=FTM.ProfileId
LEFT JOIN dbo.BusinessUnit BU on BU.Id=PR.BUId
LEFT JOIN dbo.PR_dv_Status [Status] on [Status].Id = PR.StatusId
LEFT JOIN dbo.CM_ActiveMonitoringDetails AM on AM.ProfileId = PR.Profileid
LEFT JOIN dbo.FTM_CustomerServiceMapping CustServ on CustServ.ServiceId = FTM.ServiceId and CustServ.CustomerId = FTM.CustomerId
LEFT JOIN dbo.contact con on con.Id = emp.ContactID
LEFT JOIN dbo.address addr on addr.Id = con.HomeAddressId
LEFT JOIN dbo.contactinfo coninfo on coninfo.Id = con.ContactInfoId
I have a suggestion. Can you try and change your query so the sub -queries in the SELECT are placed in CROSS APPLYs?
So something along the lines of this in your WHERE clause:
CROSS APPLY (
select top 1 StatusId AS LatestInterventionStatusId
from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc
) LatestInterventionStatusId
CROSS APPLY (
select name AS LatestInterventionName
from dbo.FTM_Intervention Intr
where Intr.Id=(select top 1 InterventionId
from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc)
)LatestInterventionName
And then of course change the column names in the SELECT to something like this:
, LatestInterventionStatusId.LatestInterventionStatusId
, LatestInterventionName.LatestInterventionName
Give this a go and let me know if it makes a different.
Ok, you didn't give me an answer on my question, but the subqueries should be changed. Try to use this instead the two subqueries:
/*
...
, emp.DateOfBirth as EmployeeDOB
, addr.PostCode
, coninfo.Email
*/
, p.StatusId as LatestInterventionStatusId
, p.name as LatestInterventionName
from FTM_Profile FTM
OUTER APPLY (
select TOP 1 Intr.name, ProfileInt.StatusId
from dbo.PR_Profileintervention ProfileInt
LEFT JOIN dbo.FTM_Intervention Intr ON Intr.Id = ProfileInt.InterventionId
where ProfileInt.ProfileId = FTM.Profileid
order by ProfileInt.Id desc
) p
/*
LEFT JOIN dbo.ProfileManagersView mgrs ON mgrs.ProfileID = FTM.ProfileID
INNER JOIN dbo.Customer cust on cust.Id= FTM.CustomerId
INNER JOIN dbo.Employee emp on emp.Id = FTM.EmployeeId
...
*/

sql: join two tables and display records even if they are in first table and not in the second table

I don't know if the title justifies the question but
i have 2 tables table A a and table B b. I am inner joining these two tables with
on (a.msisdn = b.frmsisdn or a.msisdn = b.tomsisdn)
in table A i have all the details of the users like names, msisdn, regdate, status, address etc
in table B i have user's transaction reports like timestamp, frmsisdn, tomsisdn, reference, amounts etc
Both tables have MSISDN as common but in Table A it is named as MSISDN and in Table B this can either be in FRMSISDN or TOMSISDN or will not be in any of the fields(usually users with no transactions).
But when i try to do like this, the report i am getting is not displaying the users who are in Table A with no entries in Table B, basically registered in the database but did not do any transactions as all.
Can someone tell me how do i include the MSISDN from Table A in the report even if they dont have an entry in Table B
Here is the query i am trying
select mai.msisdn, mai.firstname, mai.lastname, type as account_type,
alias as nickname, mai.regdate, mai.status,
amount as balance, count(trai.referenceid) as number_of_transactions,
sum(trai.amount) as sum_of_transactions from tableA mai
inner join tableC stk
on mai.msisdn = stk.msisdn
inner join tableB trai
on (mai.msisdn = trai.tomsisdn or mai.msisdn = trai.frmsisdn)
where trai.status = 0
and stk.walletid = 0
group by mai.msisdn, mai.firstname, mai.lastname, mai.type,
mai.alias, mai.regdate, mai.status,
stk.amount;
If you need all the entry of table A also when there si no enty in table B the use LEFT join for table B
select
mai.msisdn
, mai.firstname
, mai.lastname
, type as account_type
, alias as nickname
, mai.regdate
, mai.status
, amount as balance
, count(trai.referenceid) as number_of_transactions
, sum(trai.amount) as sum_of_transactions
from tableA mai
left join tableB trai on (mai.msisdn = trai.tomsisdn or mai.msisdn = trai.frmsisdn)
inner join tableC stk on mai.msisdn = stk.msisdn
where trai.status = 0
and stk.walletid = 0
group by
mai.msisdn
, mai.firstname
, mai.lastname
, mai.type
, mai.alias
, mai.regdate
, mai.status
, stk.amount;
or if you problem is limited but the inner join for table C
try using inner join for this table too
select
mai.msisdn
, mai.firstname
, mai.lastname
, type as account_type
, alias as nickname
, mai.regdate
, mai.status
, amount as balance
, count(trai.referenceid) as number_of_transactions
, sum(trai.amount) as sum_of_transactions
from tableA mai
left join tableB trai on (mai.msisdn = trai.tomsisdn or mai.msisdn = trai.frmsisdn)
left join tableC stk on mai.msisdn = stk.msisdn
where trai.status = 0
and stk.walletid = 0
group by
mai.msisdn
, mai.firstname
, mai.lastname
, mai.type
, mai.alias
, mai.regdate
, mai.status
, stk.amount;
Try
select mai.msisdn, mai.firstname, mai.lastname, type as account_type,
alias as nickname, mai.regdate, mai.status,
amount as balance, count(trai.referenceid) as number_of_transactions,
sum(trai.amount) as sum_of_transactions
from tableA mai
inner join tableC stk
on mai.msisdn = stk.msisdn
and stk.walletid = 0
left join tableB trai
on (mai.msisdn = trai.tomsisdn or mai.msisdn = trai.frmsisdn)
and trai.status = 0
group by mai.msisdn, mai.firstname, mai.lastname, mai.type,
mai.alias, mai.regdate, mai.status,
stk.amount;
See the difference how (at what stage) predicate is applied in LEFT JOIN .. ON and in WHERE.

Get Distinct results of all columns based on MAX DATE of one

Using SQL Server 2012
I have seen a few threads about this topic but I can't find one that involves multiple joins in the query. I can't create a VIEW on this database so the joins are needed.
The Query
SELECT
p.Price
,s.Type
,s.Symbol
, MAX(d.Date) Maxed
FROM AdventDW.dbo.FactPrices p
INNER JOIN dbo.DimSecurityMaster s
ON s.SecurityID = p.SecurityID
INNER JOIN dbo.DimDateTime d
ON
p.DateTimeKey = d.DateTimeKey
GROUP BY p.Price ,
s.Type ,
s.Symbol
ORDER BY s.Symbol
The query works but does not produce distinct results. I am using Order by to validate the results, but it is not required once I get it working. I The result set looks like this.
Price Type Symbol Maxed
10.57 bfus *bbkd 3/31/1989
10.77 bfus *bbkd 2/28/1990
100.74049 cbus 001397AA6 8/2/2005
100.8161 cbus 001397AA6 7/21/2005
The result set I want is
Price Type Symbol Maxed
10.77 bfus *bbkd 2/28/1990
100.74049 cbus 001397AA6 8/2/2005
Here were a few other StackOverflow threads I tried but couldn't get t work with my specific query
How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?
SQL Selecting distinct rows from multiple columns based on max value in one column
If you want data for the maximum date, use row_number() rather than group by:
SELECT ts.*
FROM (SELECT p.Price, s.Type, s.Symbol, d.Date,
ROW_NUMBER() OVER (PARTITION BY s.Type, s.Symbol
ORDER BY d.Date DESC
) as seqnum
FROM AdventDW.dbo.FactPrices p INNER JOIN
dbo.DimSecurityMaster s
ON s.SecurityID = p.SecurityID INNER JOIN
dbo.DimDateTime d
ON p.DateTimeKey = d.DateTimeKey
) ts
WHERE seqnum = 1
ORDER BY s.Symbol;
You should use a derived table since you really only want to group the DateTimeKey table to get the MAX date.
SELECT p.Price ,
s.Type ,
s.Symbol ,
tmp.MaxDate
FROM AdventDW.dbo.FactPrices p
INNER JOIN dbo.DimSecurityMaster s ON s.SecurityID = p.SecurityID
INNER JOIN
( SELECT MAX(d.Date) AS MaxDate ,
d.DateTimeKey
FROM dbo.DimDateTime d
GROUP BY d.DateTimeKey ) tmp ON p.DateTimeKey = tmp.DateTimeKey
ORDER BY s.Symbol;
/*
this is your initial select which is fine because this is base from your original criteria,
I cannot ignore this so i'll keep this in-tact. Instead from here i'll create a temp
*/
SELECT
p.Price
, s.Type
, s.Symbol
, MAX(d.Date) Maxed
INTO #tmpT
FROM AdventDW.dbo.FactPrices p
INNER JOIN dbo.DimSecurityMaster s
ON s.SecurityID = p.SecurityID
INNER JOIN dbo.DimDateTime d
ON p.DateTimeKey = d.DateTimeKey
GROUP BY p.Price ,
s.Type ,
s.Symbol
ORDER BY s.Symbol
SELECT innerTable.Price, innerTable.Symbol, innerTable.Type, innerTable.Maxed
FROM (
SELECT
ROW_NUMBER () OVER (PARTITION BY t1.Symbol, t1.Type, t1.Maxed ORDER BY t1.Maxed DESC) as row
, *
FROM #tmpT AS t1
) AS innerTable
WHERE row = 1
DROP TABLE #tmpT

not able to select a column outside left join

I am working with the below query
SELECT * FROM
(SELECT DISTINCT
a.Number
,a.Description
,ISNULL(temp.Quantity,0) Quantity
,LastReceived
,LastIssued
FROM Article a
LEFT JOIN (
select ss.ArticleId
, ss.Quantity
, max(lastreceiveddate) as LastReceived
, max(lastissueddate) as LastIssued
from StockSummary ss
where ss.UnitId = 8
group by ss.ArticleId, ss.StockQuantity
having (MAX(ss.LastReceivedDate) < '2014-09-01' or MAX(ss.LastReceivedDate) is NULL)
AND (MAX(ss.LastIssuedDate) < '2014-09-01' or MAX(ss.LastIssuedDate) is NULL)
) temp on a.Id = temp.ArticleId
WHERE a.UnitId = 8
) main
ORDER BY main.Number
What i want to achieve is to select the articles only with the MAX(ss.LastReceivedDate) and MAX(ss.LastIssuedDate) condition in the Left join query and then do the Quantity Select in the main query.
Note: the quantity column can be 0 or NULL.
Kindly help