performance significantly reduced when inner join table and views - sql-server

I have three views in my sql server:
CREATE VIEW [dbo].[v_CompanyLabelCreate]
AS
SELECT
c.Id AS Id,
c.[Name] AS CompanyName,
CASE WHEN r.ApprovedPatentCreativeApplication > 2 OR r.ApprovedCopyRightBookApplication + r.ApprovedCopyRightSoftwareApplication > 4 OR NumberInProduction + NumberNotInProduction > 10 THEN N'创造型'
ELSE NULL END AS Label
FROM Company c INNER JOIN ResearchInfo r ON c.Id = r.CompanyID
WHERE c.Submitted = 1
CREATE VIEW [dbo].[v_CompanyLabelHighPotential]
AS
SELECT
c.Id AS Id,
c.[Name] AS CompanyName,
CASE WHEN si1.Income >= 1000000 AND si2.Income <> 0 AND ((si1.Income -si2.Income)/si2.Income) >= 1 THEN N'潜力型'
WHEN n1.TotalProfit >= 500000 AND n2.TotalProfit <> 0 AND ((n1.TotalProfit - n2.TotalProfit)/n2.TotalProfit) >= 1 THEN N'潜力型'
WHEN nfa1.AssetsTotal >= 5000000 AND nfa2.AssetsTotal <> 0 AND ((nfa1.AssetsTotal - nfa2.AssetsTotal)/nfa2.AssetsTotal) >= 1 THEN N'潜力型'
ELSE NULL END AS Label
FROM Company c INNER JOIN SaleIncome si1 ON c.Id = si1.CompanyID AND si1.YearQuarterID = 2
INNER JOIN SaleIncome si2 ON c.Id = si2.CompanyID AND si2.YearQuarterID = 1
INNER JOIN NetProfit n1 ON c.Id = n1.CompanyID AND n1.YearQuarterID = 2
INNER JOIN NetProfit n2 ON c.Id = n2.CompanyID AND n2.YearQuarterID = 1
INNER JOIN NonFloatingAsset nfa1 ON c.Id = nfa1.CompanyID AND nfa1.YearQuarterID = 2
INNER JOIN NonFloatingAsset nfa2 ON c.Id = nfa2.CompanyID AND nfa2.YearQuarterID = 1
WHERE c.Submitted = 1
CREATE VIEW [dbo].[v_CompanyLabelHighTotalPolicies]
AS
SELECT
c.Id AS Id,
c.[Name] AS CompanyName,
CASE WHEN p.NumberOfPolicies >= 4 AND cp.PolicyID IS NOT NULL THEN N'政策大户'
ELSE NULL END AS Label
FROM Company c LEFT JOIN (SELECT CompanyID, COUNT(*) AS NumberOfPolicies FROM CompanyPolicy GROUP BY CompanyID) p ON c.Id = p.CompanyID
LEFT JOIN (SELECT CompanyID, PolicyID FROM CompanyPolicy WHERE PolicyID = 7) cp ON c.Id = cp.CompanyID
WHERE c.Submitted = 1
When I run a select query which inner joins these three views:
select *
from v_CompanyLabelCreate clc
INNER JOIN v_CompanyLabelHighPotential clhp ON clc.Id = clhp.Id
INNER JOIN v_CompanyLabelHighTotalPolicies chtp ON clc.Id = chtp.Id
It is fast and smooth. However, when I try to run a select query which inner join these three views with some other tables:
select *
FROM Company c
INNER JOIN BasicInfo b ON c.Id = b.CompanyID
INNER JOIN CompanyDimension cd ON c.Id = cd.CompanyID
INNER JOIN TotalProfit t ON c.Id = t.CompanyID AND t.YearQuarterID = 2
INNER JOIN SaleCost sc ON c.Id = sc.CompanyID AND sc.YearQuarterID = 2
INNER JOIN CompanyFinancialIndex cfi ON c.Id = cfi.CompanyID AND cfi.YearQuarterID = 6
INNER JOIN SaleIncome si1 ON c.Id = si1.CompanyID AND si1.YearQuarterID = 2
INNER JOIN SaleIncome si2 ON c.Id = si2.CompanyID AND si2.YearQuarterID = 1
INNER JOIN NetProfit n1 ON c.Id = n1.CompanyID AND n1.YearQuarterID = 2
INNER JOIN NetProfit n2 ON c.Id = n2.CompanyID AND n2.YearQuarterID = 1
INNER JOIN v_CompanyLabelCreate clc ON c.Id = clc.Id
INNER JOIN v_CompanyLabelHighPotential clhp ON clc.Id = clhp.Id
INNER JOIN v_CompanyLabelHighTotalPolicies chtp ON clc.Id = chtp.Id
WHERE c.Submitted = 1
It looks like it will take forever to get the result (Download the execution plan here: the execution plan). Now, if I just run the query without inner joining the three views like this:
select *
FROM Company c
INNER JOIN BasicInfo b ON c.Id = b.CompanyID
INNER JOIN CompanyDimension cd ON c.Id = cd.CompanyID
INNER JOIN TotalProfit t ON c.Id = t.CompanyID AND t.YearQuarterID = 2
INNER JOIN SaleCost sc ON c.Id = sc.CompanyID AND sc.YearQuarterID = 2
INNER JOIN CompanyFinancialIndex cfi ON c.Id = cfi.CompanyID AND cfi.YearQuarterID = 6
INNER JOIN SaleIncome si1 ON c.Id = si1.CompanyID AND si1.YearQuarterID = 2
INNER JOIN SaleIncome si2 ON c.Id = si2.CompanyID AND si2.YearQuarterID = 1
INNER JOIN NetProfit n1 ON c.Id = n1.CompanyID AND n1.YearQuarterID = 2
INNER JOIN NetProfit n2 ON c.Id = n2.CompanyID AND n2.YearQuarterID = 1
WHERE c.Submitted = 1
It is fast and smooth again.
About the tables used:
Company: A table which stores company Ids and company names. Of course c.Id is the PK and it will be referred to as Company ID later.
ResearchInfo, BasicInfo, CompanyDimension, CompanyFinancialIndex: CompanyID is foreign key, every company only has at most one row in this table.
SaleIncome, SaleCost, NetProfit, NonFloatingAsset, TotalProfit: the combination of CompanyID and YearQuarterID work as Primary Key, although every table has an identity field which is defined as the PK.

You also can have a missed index issue, but your query is a bit complex. You can try to reduce the complexity using cte table like (You need the field names be unique in CTEs):
WITH cte_tb1
AS (SELECT * -- UNIQUE NAMES FIELDS IS REQUIRED
FROM company c
INNER JOIN basicinfo b
ON c.id = b.companyid
INNER JOIN companydimension cd
ON c.id = cd.companyid
INNER JOIN totalprofit t
ON c.id = t.companyid
AND t.yearquarterid = 2
INNER JOIN salecost sc
ON c.id = sc.companyid
AND sc.yearquarterid = 2
INNER JOIN companyfinancialindex cfi
ON c.id = cfi.companyid
AND cfi.yearquarterid = 6
INNER JOIN saleincome si1
ON c.id = si1.companyid
AND si1.yearquarterid = 2
INNER JOIN saleincome si2
ON c.id = si2.companyid
AND si2.yearquarterid = 1
INNER JOIN netprofit n1
ON c.id = n1.companyid
AND n1.yearquarterid = 2
INNER JOIN netprofit n2
ON c.id = n2.companyid
AND n2.yearquarterid = 1
WHERE c.submitted = 1),
cte_tb2
AS (SELECT * -- UNIQUE NAMES FIELDS IS REQUIRED
FROM v_companylabelcreate clc
INNER JOIN v_companylabelhighpotential clhp
ON clc.id = clhp.id
INNER JOIN v_companylabelhightotalpolicies chtp
ON clc.id = chtp.id)
SELECT *
FROM cte_tb1 a
INNER JOIN cte_tb2 b
ON a.id = b.id

Related

T-SQL query not grouping results in output

I have the follwoing query embedded in a stored procedure
select u.UserName, s.Name, count(i.id) as NumberAccounts, sum(i.total) as CCTotal
from invoice i
inner join visit v on v.id = i.id
inner join branch b on b.id = v.branchid
inner join practice p on p.id = b.practiceid
inner join visitscheme vs on vs.id = v.id
inner join [plan] pl on pl.id = vs.planid
inner join scheme s on s.id = pl.schemeid
inner join creditcontrol cc on cc.SchemeId = s.id
inner join [user] u on u.id = cc.userid
where p.APIKey = #pracId
and (u.id = #CCid OR #CCId = '999999')
and (s.id = #SchemeId or #SchemeId = 999999)
group by u.UserName, s.Name
order by u.username
When I run it instead of result being grouped by username and scheme I get the following
UserName Name NumberAccounts CCTotal
chanel BANKMED 9954 11882514.19
ciske BANKMED 9954 11882514.19
Estee BANKMED 9954 11882514.19
Feroza BANKMED 9954 11882514.19
No grouping applied, the same values in each. Anyone know where I am going wrong?
Thanks
just write like this....
select u.UserName, s.Name, count(i.id) as NumberAccounts, sum(i.total) as CCTotal
from invoice i
inner join visit v on v.id = i.id
inner join branch b on b.id = v.branchid
inner join practice p on p.id = b.practiceid and p.APIKey = #pracId
inner join visitscheme vs on vs.id = v.id
inner join [plan] pl on pl.id = vs.planid
inner join scheme s on s.id = pl.schemeid and (s.id = #SchemeId or #SchemeId = 999999)
inner join creditcontrol cc on cc.SchemeId = s.id
inner join [user] u on u.id = cc.userid and (u.id = #CCid OR #CCId = '999999')
group by u.UserName, s.Name
order by u.username
assuming that your joins are correct

Count item corresponding listed Item

SELECT a.UPC,COUNT(*)
FROM StoreTransactions a WITH (NOLOCK)
JOIN StoreTransactions_Expanded_UOM c
ON a.StoreTransactionID = c.StoreTransactionID
LEFT JOIN ProductCatalog cat
ON a.ProductID = cat.ProductID
LEFT JOIN ProductCatalogBase base
ON cat.ProductCatalogID = base.ProductCatalogID
JOIN ProductIdentifiers d
ON cat.ProductID = d.ProductID AND d.ProductIdentifierTypeID = 2
GROUP BY a.UPC
, d.IdentifierValue, cat.PackDesc, a.ReportedCost,
base.ManualHigh, base.ManualLow,cat.DateTimeCreated,cat.DateTimeLastUpdate
ORDER BY count(*) desc
I want count of UPC corresponding UPC but not getting correct result like below.
UPC Count
071990316006 1463
026565245455 4530
You only need to group by a.UPC:
SELECT a.UPC,COUNT(*)
FROM StoreTransactions a WITH (NOLOCK)
JOIN StoreTransactions_Expanded_UOM c
ON a.StoreTransactionID = c.StoreTransactionID
LEFT JOIN ProductCatalog cat
ON a.ProductID = cat.ProductID
LEFT JOIN ProductCatalogBase base
ON cat.ProductCatalogID = base.ProductCatalogID
JOIN ProductIdentifiers d
ON cat.ProductID = d.ProductID AND d.ProductIdentifierTypeID = 2
GROUP BY a.UPC
ORDER BY count(*) desc

How to group row value using SQL Server?

I want to group same yAxisTitle in SQL Server, below image shows my data.
Expected result:
Query I used:
select
q.questionId, q.questionName,
p.perspectiveTitle, x.xAxisTitle, y.yAxisTitle, c.value
from
coaching_questionPerspectiveMap as c
inner join
Coaching_question as q on c.questionId = q.questionId
inner join
Coaching_perspective as p on c.perspectiveId = p.perspectiveId
inner join
coaching_xAxisData x on c.xAxisDataId = x.xAxisDataId
inner join
coaching_yAxisData y on c.yAxisDataId = y.yAxisDataId
where
q.questionId = 14
and p.perspectiveId = 1
order by
c.sort
Please provide any solution?
Thanks,
If you just want the data ordered so that it shows in groups of yAxisTitle, use this:
select
q.questionId, q.questionName,
p.perspectiveTitle, x.xAxisTitle, y.yAxisTitle, c.value
from
coaching_questionPerspectiveMap as c
inner join
Coaching_question as q on c.questionId = q.questionId
inner join
Coaching_perspective as p on c.perspectiveId = p.perspectiveId
inner join
coaching_xAxisData x on c.xAxisDataId = x.xAxisDataId
inner join
coaching_yAxisData y on c.yAxisDataId = y.yAxisDataId
where
q.questionId = 14
and p.perspectiveId = 1
order by
y.yAxisTitle, c.sort

How to change this query to use joins (inner or left) but not subquery to get same result

How to change this query to use joins (inner or left) but not subquery
SELECT * FROM External_Blk_Itm_Contracts ELC
WHERE
NOT EXISTS(SELECT
NULL
FROM
[BUDCONTRACTS] c
INNER JOIN
BUDTERMINALS t on t.TerminalID = c.TerminalID AND t.MBFTERMINALNAME = ELC.TerminalName AND c.CONTRACTNAME = ELC.ContractName
INNER JOIN
BudCustomers ct on ct.CustomerId = c.CustomerId AND ELC.CustomerName = ct.LegalName
)
AND ELC.ContractName = '00-000'
Untested (obviously):
SELECT distinct
ELC.*
FROM
External_Blk_Itm_Contracts ELC
LEFT JOIN
BUDCONTRACTS c on c.CONTRACTNAME = ELC.ContractName
LEFT JOIN
BUDTERMINALS t on t.TerminalID = c.TerminalID and t.MBFTERMINALNAME = ELC.TerminalName
LEFT JOIN
BudCustomers ct on ct.CustomerId = c.CustomerId and ELC.CustomerName = ct.LegalName
WHERE
c.CONTRACTNAME is NULL
and t.TerminalID is NULL
and ct.CustomerID is NULL
AND ELC.ContractName = '00-000'
My biggest question about this is why we're joining using name fields to ELC? Isn't there e.g. TerminalID, CustomerID and CotractID available on ELC?
I fixed this by
SELECT ELC.* FROM External_Blk_Itm_Contracts ELC
INNER JOIN BUDTERMINALS BT ON BT.MBFTERMINALNAME = ELC.TerminalName AND ELC.ContractName = '00-000'
INNER JOIN BudCustomers BCUST ON BCUST.LegalName = ELC.CustomerName
LEFT JOIN BUDCONTRACTS BCON ON BCON.CONTRACTNAME = ELC.ContractName AND BCON.TERMINALID = BT.TERMINALID AND BCON.CUSTOMERID = BCUST.CustomerID
WHERE BCON.CONTRACTID IS NULL

SSRS 2012: How do I return the most recent rows only?

Okay, here is my current query:
SELECT pk.RxFill.PATIENT_PRICE
,PersonQuotas.QuotaYear
,PersonQuotas.QuotaMonth
(and a bunch of other stuff to link them)
FROM
pk.RxMain
INNER JOIN pk.Doctor
ON pk.RxMain.PHARMACY_ID = pk.Doctor.PHARMACY_ID AND pk.RxMain.DOCTOR_ID = pk.Doctor.DOCTOR_ID
INNER JOIN pk.Formula
ON pk.RxMain.PHARMACY_ID = pk.Formula.PHARMACY_ID AND pk.RxMain.FORMULA_ID = pk.Formula.FORMULA_ID
INNER JOIN pk.Patient
ON pk.RxMain.PHARMACY_ID = pk.Patient.PHARMACY_ID AND pk.RxMain.PATIENT_ID = pk.Patient.PATIENT_ID
INNER JOIN pk.RxFill
ON pk.RxMain.PHARMACY_ID = pk.RxFill.PHARMACY_ID AND pk.RxMain.RXMAIN_ID = pk.RxFill.RXMAIN_ID
INNER JOIN pk.Insurance
ON pk.RxFill.PHARMACY_ID = pk.Insurance.PHARMACY_ID AND pk.RxFill.INSURANCE_ID = pk.Insurance.INSURANCE_ID
INNER JOIN PersonsRepId
ON pk.Doctor.PHARMACY_ID = PersonsRepId.PharmacyId AND pk.Doctor.SALES_PERSON_ID = PersonsRepId.SalesRepId
INNER JOIN Persons
ON PersonsRepId.PersonId = Persons.PersonId
INNER JOIN PersonQuotas
ON Persons.PersonId = PersonQuotas.PersonId
WHERE
Year(pk.RxFill.FILL_DATE) >= Year(GetDate())
I'm only really interested in the most recent QuotaYear/QuotaMonth combination, and our records database keeps returning RXFILL rows for every QuotaYear/QuotaMonth combination since we've started keeping track of them in SQL (so, I get a row for 2014/4, 2014/5, 2014/6, etc.).
To further complicate matters, the current year/month combination may not exist in my table (right now, for instance, no one has entered quotas for this current month), so I need to essentially be able to both identify the most recent year/month (both are entered as Integers) and pull only those rows (so that I can do other calculations).
How would I do this -- EDIT: in such a way that I wouldn't have to know what the most recent month is at run-time?
I'm taking a stab at this, there may be something more optimal. But basically, use a CTE to filter the year/date, and join on it.
with cte1 as (
select top 1 max(QuotaYear) as QuotaYear, QuotaMonth
from PersonQuotas
group by QuotaMonth
order by QuotaYear desc, QuotaMonth desc
)
SELECT pk.RxFill.PATIENT_PRICE
,PersonQuotas.QuotaYear
,PersonQuotas.QuotaMonth
--(and a bunch of other stuff to link them)
FROM
pk.RxMain
INNER JOIN pk.Doctor
ON pk.RxMain.PHARMACY_ID = pk.Doctor.PHARMACY_ID AND pk.RxMain.DOCTOR_ID = pk.Doctor.DOCTOR_ID
INNER JOIN pk.Formula
ON pk.RxMain.PHARMACY_ID = pk.Formula.PHARMACY_ID AND pk.RxMain.FORMULA_ID = pk.Formula.FORMULA_ID
INNER JOIN pk.Patient
ON pk.RxMain.PHARMACY_ID = pk.Patient.PHARMACY_ID AND pk.RxMain.PATIENT_ID = pk.Patient.PATIENT_ID
INNER JOIN pk.RxFill
ON pk.RxMain.PHARMACY_ID = pk.RxFill.PHARMACY_ID AND pk.RxMain.RXMAIN_ID = pk.RxFill.RXMAIN_ID
INNER JOIN pk.Insurance
ON pk.RxFill.PHARMACY_ID = pk.Insurance.PHARMACY_ID AND pk.RxFill.INSURANCE_ID = pk.Insurance.INSURANCE_ID
INNER JOIN PersonsRepId
ON pk.Doctor.PHARMACY_ID = PersonsRepId.PharmacyId AND pk.Doctor.SALES_PERSON_ID = PersonsRepId.SalesRepId
INNER JOIN Persons
ON PersonsRepId.PersonId = Persons.PersonId
INNER JOIN PersonQuotas
ON Persons.PersonId = PersonQuotas.PersonId
WHERE
--Year(pk.RxFill.FILL_DATE) >= Year(GetDate())
PersonQuotas.QuotaYear = cte1.QuotaYear
and PersonQuotas.QuotaMonth = cte1.quotaMonth
WITH Ordinal (PersonID, QuotaYear, QuotaMonth, TRxAmount, QRxAmount, Ord) AS
(
SELECT PersonQuotas.PersonID, PersonQuotas.QuotaYear, PersonQuotas.QuotaMonth, PersonQuotas.TRxAmount, PersonQuotas.QRxAmount,
ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY QuotaYear DESC, QuotaMonth DESC)
FROM PersonQuotas
)
SELECT
pk.RxMain.PHARMACY_ID AS [RxMain PHARMACY_ID]
[STUFF FROM OTHER DATA TABLES]
,Ordinal.PersonID AS [Ordinal PersonID]
,Ordinal.QuotaYear
,Ordinal.QuotaMonth
,Ordinal.TRxAmount
,Ordinal.QRxAmount
FROM
pk.RxMain
INNER JOIN pk.Doctor
ON pk.RxMain.PHARMACY_ID = pk.Doctor.PHARMACY_ID AND pk.RxMain.DOCTOR_ID = pk.Doctor.DOCTOR_ID
INNER JOIN pk.Formula
ON pk.RxMain.PHARMACY_ID = pk.Formula.PHARMACY_ID AND pk.RxMain.FORMULA_ID = pk.Formula.FORMULA_ID
INNER JOIN pk.Patient
ON pk.RxMain.PHARMACY_ID = pk.Patient.PHARMACY_ID AND pk.RxMain.PATIENT_ID = pk.Patient.PATIENT_ID
INNER JOIN pk.RxFill
ON pk.RxMain.PHARMACY_ID = pk.RxFill.PHARMACY_ID AND pk.RxMain.RXMAIN_ID = pk.RxFill.RXMAIN_ID
INNER JOIN pk.Insurance
ON pk.RxFill.PHARMACY_ID = pk.Insurance.PHARMACY_ID AND pk.RxFill.INSURANCE_ID = pk.Insurance.INSURANCE_ID
INNER JOIN PersonsRepId
ON pk.Doctor.PHARMACY_ID = PersonsRepId.PharmacyId AND pk.Doctor.SALES_PERSON_ID = PersonsRepId.SalesRepId
INNER JOIN Persons
ON PersonsRepId.PersonId = Persons.PersonId
INNER JOIN Ordinal
ON Persons.PersonId = Ordinal.PersonId
WHERE
( pk.RxFill.FILL_DATE >= dateadd(year, datediff(year, 0, getdate()), 0) AND
Ordinal.Ord = 1 )

Resources