I am using following query to return a list of records:
Select DISTINCT A.Id Questionid,
A.Created_Date Questiondate,
Row_Number() Over ( Order By A.Created_Date Desc) Row_Id,
B.Id Answerid,
COUNT(*) OVER (partition by a.id) QCOUNT,
B.Created_Date Answerdate
From Question_Table A
Inner Join Answers_Table B
ON A.Id = B.Question_Id
AND A.Is_Active = 1
AND A.Is_Delete = 0
And B.Is_Active = 1
And B.Is_Delete = 0
And A.Category_Id = 1318221772
Answers_Table.question_id is mapped to question_table.id
Hence, for a particular question id, there can be more than one rows on answers_table.
The Output now displaying is:
QUESTIONID QUESTIONDATE ROW_ID ANSWERID QCOUNT ANSWERDATE
52776 08-DEC-12 1 31383 2 09-DEC-12
52776 08-DEC-12 2 31482 2 10-DEC-12
52719 07-DEC-12 3 31321 1 07-DEC-12
But my requirement to display output as:
QUESTIONID QUESTIONDATE ROW_ID ANSWERID QCOUNT ANSWERDATE
52776 08-DEC-12 1 31383 2 09-DEC-12
52719 07-DEC-12 3 31321 1 07-DEC-12
How can I display unique questionid (like 52776,52719) on to the output?
Depending on what you are trying to do you may be able to rewrite this with a Group By statement. However, if you want to keep your existing query, try changing this line:
Row_Number() Over (Order By A.Created_Date Desc) Row_Id,
to this:
Row_Number() Over ( partition by a.id Order By B.Created_Date ASC) Row_Id,
And then make the whole thing a subquery selecting where row_id = 1. This should just return one row per Question and only the earliest Answer for that Question.
Select * From (
Select DISTINCT A.Id Questionid,
A.Created_Date Questiondate,
Row_Number() Over ( partition by a.id Order By B.Created_Date ASC) Row_Id,
B.Id Answerid,
COUNT(*) OVER (partition by a.id) QCOUNT,
B.Created_Date Answerdate
From Question_Table A
Inner Join Answers_Table B
ON A.Id = B.Question_Id
AND A.Is_Active = 1
AND A.Is_Delete = 0
And B.Is_Active = 1
And B.Is_Delete = 0
And A.Category_Id = 1318221772
) Where ROW_ID = 1
Related
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.
My query is giving me result from grouped data but now I want only two rows
I have tried HAVING COUNT(*) <= 2 but issue is is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
my query is
select f.CompanyName, f.EmployeeCity, f.PrioritySL ,f.EmployeeSeniorityLevel ,f.EmployeeID
from (
select ConcatKey, min(PrioritySL) as PSL
from dbo.WalkerItContacts group by ConcatKey
) as x inner join dbo.WalkerItContacts as f on f.ConcatKey = x.ConcatKey and f.PrioritySL = x.PSL
where f.PrioritySL != '10'
Company apple have 9 records I want only 2 records
my data
company name priority
a 10
a 1
a 3
b 2
b 4
b 3
b 5
c 1
c 10
c 2
my expected data
company name priority
a 1
a 3
b 2
b 3
c 1
c 2
Add a 'top 2' clause to the outer query:
select top 2 f.CompanyName, f.EmployeeCity, f.PrioritySL ,f.EmployeeSeniorityLevel ,f.EmployeeID
from (
select ConcatKey, min(PrioritySL) as PSL
from dbo.WalkerItContacts group by ConcatKey
) as x inner join dbo.WalkerItContacts as f on f.ConcatKey = x.ConcatKey and f.PrioritySL = x.PSL
where f.PrioritySL != '10'
and f.CompanyName= 'Apple'
will give you two rows. Add a order clause by in the outer query so you can control which two rows are returned.
You can phrase this more succinctly and with better performance as:
select top (2) wic.*
from (select wic,
rank() over (partition by CompanyName, ConcatKey order by PrioritySL) as seqnum
from dbo.WalkerItContacts wic
) wic
where seqnum = 1 and
wic.PrioritySL <> 10 and
wic.CompanyName = 'Apple';
I think you could solve your problem using the ROW_NUMBER() function to count the rows and filter it in the WHERE clause to only show 2 rows per group.
I think something like this might work for you:
SELECT rownum, f.CompanyName, f.EmployeeCity, f.PrioritySL,
f.EmployeeSeniorityLevel, f.EmployeeID
FROM ( SELECT ConcatKey, MIN(PrioritySL) AS PSL, ROW_NUMBER() OVER(PARTITION BY
f.CompanyName) AS rownum
FROM dbo.WalkerItContacts
GROUP BY ConcatKey) AS x
INNER JOIN dbo.WalkerItContacts AS f ON f.ConcatKey = x.ConcatKey
AND f.PrioritySL = x.PSL
WHERE f.PrioritySL != '10' AND rownum <= 2
ORDER BY f.CompanyName ASC;
Hope this helps some.
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
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.
I have a query that I'm trying to optimize but haven't had much success. There are two tables, one with the main data and one with timestamps of when specific events occurred. The tables are relational using a common key of adID. I am trying to perform a query that pulls in all of the timestamps and other data from the main table. I have it working but I am trying to optimize so it runs faster.
SELECT a.ID,a.repID,a.artistID,
(
SELECT TOP 1 c.timestamp
FROM Tracking AS c
WHERE statusID = 4
AND c.ID = a.ID
ORDER BY c.timestamp ASC
)
AS created,
(
SELECT TOP 1 d.timestamp
FROM Tracking AS d
WHERE statusID = 5
AND d.ID = a.ID
ORDER BY d.timestamp ASC
)
AS claimed,
(
SELECT TOP 1 p.timestamp
FROM Tracking AS p
WHERE statusID = 6
AND p.ID = a.ID
ORDER BY p.timestamp ASC
)
AS proof,
(
SELECT TOP 1 v.timestamp
FROM Tracking AS v
WHERE statusID = 8
AND v.ID = a.ID
ORDER BY v.timestamp ASC
)
AS approved,
(
SELECT count(ID)
FROM Tracking AS t
WHERE statusID = 6
AND t.ID = a.ID
)
AS proofcount
FROM Advertising AS a
WHERE a.statusID = 8
Any help on this is appreciated. I'm not too familiar with SQL Server so I am not too well versed in optimizing queries such as these.
You should be able to use the following:
SELECT a.ID,
a.repID,
a.artistID,
min(case when t.statusID = 4 then t.timestamp end) created,
min(case when t.statusID = 5 then t.timestamp end) claimed,
min(case when t.statusID = 6 then t.timestamp end) proof,
min(case when t.statusID = 8 then t.timestamp end) approved,
count(case when t.statusID = 6 then id end) proofcount
FROM Advertising AS a
LEFT JOIN Tracking t
on a.id = t.id
WHERE a.statusID = 8
GROUP BY a.ID, a.repID, a.artistID;
I think the following query gets to what you want:
select id, repid, artistid,
max(case when statusId = 4 and seqnum = 1 then timestamp end),
max(case when statusId = 5 and seqnum = 1 then timestamp end),
max(case when statusId = 6 and seqnum = 1 then timestamp end),
max(case when statusId = 8 and seqnum = 1 then timestamp end),
sum(case when statusId = 6 then 1 else 0 end)
from (select a.ID, a.repID, a.artistID, t.statusId, t.timestamp
row_number() over (partition by a.id, t.statusId order by timestamp) as seqnum
from advertising a left outer join
tracking t
on a.id = t.id
) t
where seqnum = 1
group by id, repid, artistid
It joins the tables together and identifies the earliest record using row_number(). It then selects only these records and groups by the other fields.
Your query also filters only those records that have statusid = 8. I'm not sure if this is intentional. If so, then you want this having clause at the end of the query:
having sum(case when statusId = 8 then 1 else 0 end) > 0