Adding a Helper SQL Index - sql

I have the following View which seems to work quickly enough but when I look at the Execution Plan, it shows the Top N Sort in the second query taking ~90% due to it being repeated for every row in the first query.
Should I be adding an Index to the Loan table to help the ORDER BY clause?
CREATE VIEW [dbo].[ResourceItemStatus] AS
SELECT
i.ID AS ItemID,
i.ResourceID,
i.DateAdded,
i.LocationID,
i.OwnerID,
i.Barcode,
i.MissingReasonID,
i.DateRemoved,
ll.PatronID,
ll.ID AS LoanID,
ll.IssueDateTime,
ll.DueDate,
ll.ReturnDateTime,
ll.LoanTypeID,
ll.RenewalCount,
ll.DeleteSummary,
ll.ReturnStatusID,
ll.FineID,
(SELECT COUNT(*) FROM Loan WHERE Loan.ItemID = i.ID) AS LoanCount,
(SELECT COUNT(*) FROM Item WHERE Item.DateRemoved IS NULL AND Item.ResourceID = i.ResourceID) AS AvailableItemCount
FROM Item i
OUTER APPLY
(
SELECT TOP 1
l.ID,
l.ItemID,
l.PatronID,
l.IssueDateTime,
l.DueDate,
l.ReturnDateTime,
l.LoanTypeID,
l.RenewalCount,
l.DeleteSummary,
l.ReturnStatusID,
l.FineID
FROM Loan l
WHERE l.ItemID = i.ID
ORDER BY l.IssueDateTime DESC, l.ID DESC
) AS ll

Try Windowed Aggregates instead of Scalar Subqueries/Outer Apply:
SELECT
i.ID AS ItemID,
i.ResourceID,
i.DateAdded,
i.LocationID,
i.OwnerID,
i.Barcode,
i.MissingReasonID,
i.DateRemoved,
ll.PatronID,
ll.ID AS LoanID,
ll.IssueDateTime,
ll.DueDate,
ll.ReturnDateTime,
ll.LoanTypeID,
ll.RenewalCount,
ll.DeleteSummary,
ll.ReturnStatusID,
ll.FineID,
coalesce(ll.LoanCount, 0)
COUNT(case when Item.DateRemoved IS NULL then 1 end)
over (partition by ResourceID) AS AvailableItemCount
FROM Item i
LEFT JOIN
(
SELECT
l.ID,
l.ItemID,
l.PatronID,
l.IssueDateTime,
l.DueDate,
l.ReturnDateTime,
l.LoanTypeID,
l.RenewalCount,
l.DeleteSummary,
l.ReturnStatusID,
l.FineID,
COUNT(*) over (partition by ItemId) AS LoanCount,
row_number()
over (partition by ItemId
order by l.IssueDateTime DESC, l.ID DESC) as rn
FROM Loan l
) as ll
on ll.ItemID = i.ID
and ll.rn = 1

Related

I need to only select the minimum value of my query

I have a view created in SQL Server Management Studio that brings in certain data, I need to only select the rows with the minimum sequence. For example, in the screenshot see the job number "50773-4", I would only need to see the row with SEQ number 2. I've tried to Group by Min, but to no avail. Any help would be appreciated.
SELECT
TOP (100) PERCENT dbo.Job_Operation.Job,
MIN(dbo.Job_Operation.Sequence) AS SEQ,
dbo.Job_Operation.Work_Center,
dbo.Work_Center.Department
FROM
dbo.Job_Operation
INNER JOIN dbo.Job ON dbo.Job_Operation.Job = dbo.Job.Job
INNER JOIN dbo.User_Values ON dbo.Job.User_Values = dbo.User_Values.User_Values
INNER JOIN dbo.Work_Center ON dbo.Job_Operation.Work_Center = dbo.Work_Center.Work_Center
GROUP BY
dbo.Job_Operation.Job,
dbo.User_Values.Numeric2,
dbo.Work_Center.UVText4,
dbo.Job.Status,
dbo.Job_Operation.Status,
dbo.User_Values.Decimal1,
dbo.Job_Operation.Work_Center,
dbo.Work_Center.Department
HAVING
(dbo.Work_Center.UVText4 = 'Machining')
ORDER BY
dbo.User_Values.Decimal1 DESC,
SEQ
[enter image description here]
I would try the RANK() window function. Perhaps:
SELECT column1,
column2,
rank() OVER (PARTITION BY job ORDER BY seq) AS seq_by_job
Then use this as a nested statement, and filter on only the min rank (i.e. WHERE nested_statement.seq_by_job = 1)
here is one way :
SELECT
TOP (100) PERCENT Job,
Sequence AS SEQ,
Work_Center,
Department
FROM
( select dbo.Job_Operation.Job,
dbo.Job_Operation.Sequence,
dbo.Job_Operation.Work_Center,
dbo.Work_Center.Department,
dbo.User_Values.Decimal1 ,
ROW_NUMBER() over (partition by dbo.Job_Operation.Job,
dbo.User_Values.Numeric2,
dbo.Work_Center.UVText4,
dbo.Job.Status,
dbo.Job_Operation.Status,
dbo.User_Values.Decimal1,
dbo.Job_Operation.Work_Center,
dbo.Work_Center.Department
Order by dbo.Job_Operation.Sequence asc) rn
FROM
dbo.Job_Operation
INNER JOIN dbo.Job ON dbo.Job_Operation.Job = dbo.Job.Job
INNER JOIN dbo.User_Values ON dbo.Job.User_Values = dbo.User_Values.User_Values
INNER JOIN dbo.Work_Center ON dbo.Job_Operation.Work_Center = dbo.Work_Center.Work_Center
) tt
WHERE rn = 1
and UVText4 = 'Machining'
You can do:
with
q as (
SELECT
dbo.Job_Operation.Job,
MIN(dbo.Job_Operation.Sequence) AS SEQ,
dbo.Job_Operation.Work_Center,
dbo.Work_Center.Department,
dbo.User_Values.Decimal1
FROM
dbo.Job_Operation
INNER JOIN dbo.Job ON dbo.Job_Operation.Job = dbo.Job.Job
INNER JOIN dbo.User_Values
ON dbo.Job.User_Values = dbo.User_Values.User_Values
INNER JOIN dbo.Work_Center
ON dbo.Job_Operation.Work_Center = dbo.Work_Center.Work_Center
GROUP BY
dbo.Job_Operation.Job,
dbo.User_Values.Numeric2,
dbo.Work_Center.UVText4,
dbo.Job.Status,
dbo.Job_Operation.Status,
dbo.User_Values.Decimal1,
dbo.Job_Operation.Work_Center,
dbo.Work_Center.Department
HAVING
(dbo.Work_Center.UVText4 = 'Machining')
),
r as (
select *,
row_number() over(partition by job order by seq) as rn
from q
)
select job, seq, work_center, department
from r
where rn = 1
order by Decimal1 DESC

What will be the query for this?

JOIN public.match m ON (s.stadium_id = m.stadium_id)
group
AS (
)
SELECT round_number
,stadium_name
,spectators
FROM (
SELECT round_number
,stadium_name
,spectators
,RANK() OVER (
PARTITION BY round_number ORDER BY spectators DESC
) AS rank1
FROM t1
) AS s1
WHERE rank1 = 1
<br>
Any smaller query than this?
I think you can just use window functions:
select ms.*
from (select m.round_number, s.stadium_name, m.no_spectators,
row_number() over (partition by m.round_number order by m.no_spectators desc) as seqnum
from public.stadium s join
public.match m
on s.stadium_id = m.stadium_id
) ms
where seqnum = 1
order by m.round_number;
I don't see why aggregation would be needed for the inner query.
You can use a subquery to get the max first
select m.round_number, s.stadium_name, MaxSpec
from public.stadium s
JOIN public.match m ON (s.stadium_id = m.stadium_id)
JOIN
(
select m.round_number, MAX(m.no_spectators) as MaxSpec
from public.stadium s
JOIN public.match m ON (s.stadium_id = m.stadium_id)
group by m.round_number
)a on m.no_spectators = a.MaxSpec
Just one more way to skin this cat. Throw your MAX(no_spectators) into a WHERE clause.
SELECT
m.round_number,
s.stadium_name,
m.no_spectators
FROM
PUBLIC.stadium s
JOIN
PUBLIC.match m
ON s.stadium_id = m.stadium_id
WHERE
m.no_spectators = (SELECT MAX(no_spectators) FROM PUBLIC.match);
That should do for an intro class.

Multiple subquery join in View with group by returns duplicate rows

I have created a view using subquery but I want this view to return few mendatory column which cant be added in group by subquery, so I have to create one more select statement and join with other group by subquery
I am come up with following query,
But problem I am facing is if group by seller has 28 rows it returns 28 duplicate rows, also I want whole query to order by TotalOrderItem.
Alter VIEW [dbo].[SellersPerformance] AS
Select
RequiredColumns.Id as Id,
aggrgateDT.SellerId as SellerId,
aggrgateDT.TenantId as TenantId,
aggrgateDT.Active as Active,
aggrgateDT.TotalOrderedItem as TotalOrderItem,
aggrgateDT.MoveToPurchase as MoveToPurchase,
aggrgateDT.GoodPurchase as GoodPurchase,
RequiredColumns.Created as Created,
RequiredColumns.Modified as Modified,
RequiredColumns.CreatorId as CreatorId,
RequiredColumns.ModifierId as ModifierId
From
(
(Select
sellerId, p.TenantId, p.Active, count(*) as TotalOrderedItem,
count(*) - count(o.Id) as MoveToPurchase,
count(o.Id) as GoodPurchase,
count(case when o.ApplicationStatus = 'Perfect' then 1 end) as Perfect,
count(case when o.ApplicationStatus = 'R-Perfect' then 1 end) as R_Perfect
FROM [dbo].[AmazonOrderPurchaseInfo] p
left join [dbo].[AmazonOrder] o
on p.AmazonOrderId = o.Id
AND p.Id = o.[AmazonOrderPurchaseInfoId]
group by SellerId, p.TenantId, p.Active
order by TotalOrderedItem offset 0 rows
) aggrgateDT
Left outer Join (
SELECT
NEWID() Id,
purchase.Created AS Created,
purchase.Modified AS Modified,
purchase.CreatorId AS CreatorId,
purchase.ModifierId AS ModifierId,
purchase.SellerId As SellerId
From dbo.AmazonOrderPurchaseInfo purchase
) RequiredColumns ON aggrgateDT.SellerId = RequiredColumns.SellerId
)
GO
You may try Group by for this.
Alter VIEW [dbo].[SellersPerformance] AS
select res.Id, res.SellerId, res.TenandId, res.Active, res.TotalOrderItem, res.MovetoPurchase, res.GoodPurchase, res.Created, res.Modified, res.CreatorId, res.ModifierId
from
(
Select
RequiredColumns.Id as Id,
aggrgateDT.SellerId as SellerId,
aggrgateDT.TenantId as TenantId,
aggrgateDT.Active as Active,
aggrgateDT.TotalOrderedItem as TotalOrderItem,
aggrgateDT.MoveToPurchase as MoveToPurchase,
aggrgateDT.GoodPurchase as GoodPurchase,
RequiredColumns.Created as Created,
RequiredColumns.Modified as Modified,
RequiredColumns.CreatorId as CreatorId,
RequiredColumns.ModifierId as ModifierId
From
(
(Select
sellerId, p.TenantId, p.Active, count(*) as TotalOrderedItem,
count(*) - count(o.Id) as MoveToPurchase,
count(o.Id) as GoodPurchase,
count(case when o.ApplicationStatus = 'Perfect' then 1 end) as Perfect,
count(case when o.ApplicationStatus = 'R-Perfect' then 1 end) as R_Perfect
FROM [dbo].[AmazonOrderPurchaseInfo] p
left join [dbo].[AmazonOrder] o
on p.AmazonOrderId = o.Id
AND p.Id = o.[AmazonOrderPurchaseInfoId]
group by SellerId, p.TenantId, p.Active
order by TotalOrderedItem offset 0 rows
) aggrgateDT
Left outer Join (
SELECT
NEWID() Id,
purchase.Created AS Created,
purchase.Modified AS Modified,
purchase.CreatorId AS CreatorId,
purchase.ModifierId AS ModifierId,
purchase.SellerId As SellerId
From dbo.AmazonOrderPurchaseInfo purchase
) RequiredColumns ON aggrgateDT.SellerId = RequiredColumns.SellerId
) as res
group by res.Id, res.SellerId, res.TenandId, res.Active, res.TotalOrderItem, res.MovetoPurchase, res.GoodPurchase, res.Created, res.Modified, res.CreatorId, res.ModifierId
)
GO
Here if Id, Created, Modified, CreatorId, ModifierId columns will have same id then you may get your expected result.

SQL Select TOP 1 for each group in subquery

Good morning,
I want to alter my query in such a way, that only the top 1, filtered from h.started asc is selected.
select h.started, * from wshhistory h
join asset a on h.assetid = a.uid
inner join
(
select Count(*) as TotalLatest, a.uid, a.deleted from asset a
join wshhistory h on a.uid = h.assetid
where h.latest = 1
group by a.uid, a.deleted
having Count(*) > 1
) X
on X.uid = h.assetid
where X.deleted = 0 and h.latest = 1
order by h.assetid desc
I searched all over, and found in most posts, to use:
ROW_NUMBER() OVER (PARTITION BY a.uid ORDER BY h.started asc) as rn
But I can't seem to use this since I need use group by, and this results in the error message:
Column 'wshhistory.started' is invalid in the select list because it
is not contained in either an aggregate function or the GROUP BY
clause.
To give some extra info about my query:
I need to search where I have duplicates of Latest = 1 (table: wshhistory), of the same assetid. And then I need to set the them all on 0 except the latest one.
I think you want something like this:
with toupdate as (
select h.*,
row_number() over (partition by h.assetid order by h.started desc) as seqnum
from wshhistory h
where h.latest = 1
)
update toupdate
set latest = 0
where seqnum > 1 and
exists (select 1
from asset a
where a.uid = toupdate.assetid and a.deleted = 0
);
Sample data and desired results are much easier to work with than non-working queries.

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