Oracle SQL Query Assistance - sql

Given a table:
ID NUMBER
OBJECTID NUMBER
CATEGORYID NUMBER
SCORE NUMBER
SCOREDATE DATE
Is it possible to efficiently retrieve the last score (based on SCOREDATE) in each distinct category for a given object in one query?

Try:
select v.* from (
select category_id,
score,
scoredate,
row_number() over (partition by category_id order by scoredate desc) rn
from MyTable) v
where rn=1

What you want falls into the [greatest-n-per-group] tag. One way to achieve the result:
SELECT
t.CategoryId
, t.Score
FROM
( SELECT
CategoryId
, MAX(ScoreDate) AS LastScoreDate
FROM
TableX
WHERE
ObjectId = #ObjectId
GROUP BY
CategoryId
) AS grp
JOIN
TableX AS t
ON grp.Category = t.CategoryId
AND grp.LastScoreDate = t.ScoreDate
WHERE
t.ObjectId = #ObjectId

Related

Turn these temp tables into one longer subquery (can't use Temp tables in Power BI)

Currently I have created these temp tables to get the desired output I need. However, Power BI doesn't allow the use of temp tables so I need to get this all into 1 query using inner selects.
drop table if exists #RowNumber
Select Date, ID, ListID
, row_number() over (partition by ID order by ID) as rownum
into #RowNumber
from Table
where Date= cast(getdate()-1 as date)
group by Date, ID, ListID
order by ID
drop table if exists #1stListIDs
select ListID as FirstID, ID, Date
into #1stListIDs
from #RowNumber
where rownum = 1
drop table if exists #2ndlistids
Select ListID as SecondListID, ID, Date
into #2ndlistids
from #RowNumber
where rownum = 2
--Joins the Two Tables back together to allow the listids to be in the same row
drop table if exists #FinalTableWithTwoListIDs
select b.FirstListID, a.SecondListID, a.ID, a.Date
into #FinalTableWithTwoListIDs
from #2ndlistids a
join #1stListIDs b on a.ID= b.ID
order by ID
This code is simple and straight forward. However I can't seem to figure out using a subquery. Here is what I have. It works for the FirstListID select statement, but not the SecondListID portion. I believe this is because you can't reference the inner most select statement with multiple different outer select statements, but I could be wrong.
Select a.ListId as SecondListID, a.ID, a.Date
from (
select a.ListId as FirstListID, a.ID, a.Date
from (
Select Date, ID, ListId
, row_number() over (partition by ID order by ID) as rownum
from Table
where Date = cast(getdate()-1 as date)
group by Date, ID, ListId
order by ID) a
where a.rownum = 1) b
where a.rownum = 2) c
Just to show, for completeness, how you could use CTEs to replace the #temp tables, it would be something along the lines of
with RowNumber as (
select Date, ID, ListID
, row_number() over (partition by ID order by ID) as rownum
from Table
where Date= cast(dateadd(day,-1,getdate()) as date)
group by Date, ID, ListID
),
FirstListIDs as (
select ListID as FirstID, ID, Date
from RowNumber
where rownum = 1
),
SecondListIDs as (
select ListID as SecondID, ID, Date
from RowNumber
where rownum = 2
)
select f.FirstID, s.SecondID, s.ID, s.Date
from Secondlistids s
join FirstListIDs f on s.ID=f.ID
order by s.ID
Note the use of dateadd which is recommended over the ambiguousdate +/- value assumed to be days, and where relevant meaningful table aliases.
You could do it with a CTE and joining the two together, but that is inefficient and unnecessary.
It looks like you just need LAG to get the previous ListID
I note that PARTITION BY ID ORDER BY ID is non-deterministic and the ordering will be random. I strongly suggest you find a deterministic ordering.
SELECT
PrevID AS b.FirstListID,
ListID AS a.SecondListID,
ID,
Date
FROM (
SELECT
Date,
ID,
ListID,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ID) AS rownum,
LAG(ListID) OVER (PARTITION BY ID ORDER BY ID) AS PrevID
from [Table]
where Date = cast(getdate() - 1 as date)
group by Date, ID, ListID
) AS WithRowAndLag
WHERE rownum = 2;
ORDER BY ID;

SQL Return MAX Values from Multiple Rows

I have tried many solutions and nothing seems to work. I am trying to return the MAX status date for a project. If that project has multiple items on the same date, then I need to return the MAX ID. So far I have tried this:
SELECT PRJSTAT_ID, PRJSTAT_PRJA_ID, PRJSTAT_STATUS, PRJSTAT_DATE
From Project_Status
JOIN
(SELECT MAX(PRJSTAT_PRJA_ID) as MaxID, MAX(PRJSTAT_DATE) as MaxDate
FROM Project_Status
Group by PRJSTAT_PRJA_ID)
On
PRJSTAT_PRJA_ID = MaxID and PRJSTAT_DATE = MaxDate
Order by PRJSTAT_PRJA_ID
It returns the following:
I am getting multiple records for PRJSTAT_PRJA_ID, but I only want to return the row with the MAX PRJSTAT_ID. Any thoughts?
Take out the MAX on the ID on the subquery:
SELECT PRJSTAT_ID, PRJSTAT_PRJA_ID, PRJSTAT_STATUS, PRJSTAT_DATE
From Project_Status
JOIN
(SELECT PRJSTAT_PRJA_ID as ID, MAX(PRJSTAT_DATE) as MaxDate
FROM Project_Status
Group by PRJSTAT_PRJA_ID)
On
PRJSTAT_PRJA_ID = ID and PRJSTAT_DATE = MaxDate
Order by PRJSTAT_PRJA_ID
Or remove the need to join:
SELECT * FROM
(SELECT PRJSTAT_ID, PRJSTAT_PRJA_ID, PRJSTAT_STATUS, PRJSTAT_DATE,
ROW_NUMBER() OVER (PARTITION BY PRJSTAT_PRJA_ID ORDER BY PRJSTAT_DATE DESC)
AS SEQ,
ROW_NUMBER() OVER (PARTITION BY PRJSTAT_PRJA_ID ORDER BY PRJSTAT_PRJA_ID
DESC) AS IDSEQ
From Project_Status
)PR
WHERE SEQ = 1
AND IDSEQ = 1
Your problem is ties. You want the record with the maximum date per PRJSTAT_PRJA_ID and in case of a tie the record with the highest ID. The easiest way to rank records per group and only keep the best record is ROW_NUMBER:
select prjstat_id, prjstat_prja_id, prjstat_status, prjstat_date
from
(
select
project_status.*,
row_number() over (partition by prjstat_prja_id
order by prjstat_date desc, prjstat_id desc) as rn
from project_status
)
where rn = 1
order by prjstat_prja_id;

SQL for each group find column order by another column

Here's the data:
studentid,state,score,date,modno,transactionno
1,IL,10,20170101,0,0
1,VA,20,20170102,1,1
1,FL,30,20170103,2,2
2,VA,40,20170101,0,0
2,IL,50,20170102,1,1
2,IN,60,20170103,2,2
Here's how the output should be:
studentid,state,score,date
1,IL,20,20170101
2,VA,60,20170102
So basically we want to group by studentid.
Find the first state based on the lowest modno and transactionno.
Find the first score based on the highest modno and transactionno.
select studentid,
(select top 1 state from student s1 where s.studentid = s1.studentid order by modno, transactionno) as state,
(select top 1 score from student s1 where s.studentid = s1.studentid order by modno desc, transactionno desc) as score,
(select top 1 date from student s1 where s.studentid = s1.studentid order by modno, transactionno) as date
from student s
group by studentid
Above is my query in SQL 2008. Are there other ways to write this query to get better performance? It really shows down when working with large data sets and with pulling out more than two columns per group.
I think I would approach this with conditional aggregation:
select studentid,
max(case when seqnum_asc = 1 then state end) as state,
max(case when seqnum_desc = 1 then score end) as score,
max(case when seqnum_asc = 1 then date end) as date
from (select s.*,
row_number() over (partition by studentid order by modno, transactionno) as seqnum_asc,
row_number() over (partition by studentid order by modno desc, transactionno desc) as seqnum_desc
from student s
) s
group by studentid;
Guess your output is not correct or we havn't unserdtood Date part in your output.
Try this other sample data and let us know,
declare #t table(studentid int,states varchar(20), score int
,dates date,modno int,transactionno int)
insert into #t VALUES
(1,'IL',10,'20170101',0,0)
,(1,'VA',20,'20170102',1,1)
,(1,'FL',30,'20170103',2,2)
,(2,'VA',40,'20170101',0,0)
,(2,'IL',50,'20170102',1,1)
,(2,'IN',60,'20170103',2,2)
;with CTE as
(
select studentid from #t
group by studentid
)
SELECT t.studentid,ca.states,ca1.score,ca.dates
from CTE t
cross apply(select top 1 t1.states,t1.dates from #t t1
where t.studentid=t1.studentid
order by modno,transactionno )ca
cross apply(select top 1 t1.score from #t t1
where t.studentid=t1.studentid
order by modno desc,transactionno desc )ca1
--cross apply(select top 1 t1.dates from #t t1
--where t.studentid=t1.studentid
--order by modno ,transactionno )ca2

How to perform reference a window function inside current table?

I have this part in a larger query which consume lot of RAM:
TopPerPost as
(
select Id,
CloseReasonTypeId,
Name,
ReasonsPerPost.TotalByCloseReason,
row_number() over(partition by Id order by TotalByCloseReason desc) seq -- Get the most common Id (The most common close Reason)
from ReasonsPerPost
where Name is NOT NULL and TopPerPost.seq=1 -- Remove useless results here, instead of doing it later
)
but I got The multi-part identifier "TopPerPost.seq" could not be bound.
Last detail... I only Use theNamecolumn in a laterINNER JOINof that table.
You can't reference a window function in the where of the same query. Just create a second cte.
with TopPerPost as
(
select Id,
CloseReasonTypeId,
Name,
ReasonsPerPost.TotalByCloseReason,
row_number() over(partition by Id order by TotalByCloseReason desc) seq -- Get the most common Id
from ReasonsPerPost
where Name is NOT NULL
)
, OnlyTheTop as
(
select *
from TopPerPost
where seq = 1
)
Or you can do it like this.
select * from
(
select Id,
CloseReasonTypeId,
Name,
ReasonsPerPost.TotalByCloseReason,
row_number() over(partition by Id order by TotalByCloseReason desc) seq -- Get the most common Id
from ReasonsPerPost
where Name is NOT NULL
) s
where seq = 1
Here is another option that should eliminate the need for so many rows being returned.
select Id,
CloseReasonTypeId,
Name,
s.TotalByCloseReason
from ReasonsPerPost rpp
cross apply
(
select top 1 TotalByCloseReason
from ReasonsPerPost rpp2
where rpp2.Id = rpp.Id
order by TotalByCloseReason desc
) s
where Name is NOT NULL
Attempt #4...this would be a LOT easier with a sql fiddle to work with.
select Id,
CloseReasonTypeId,
Name,
s.TotalByCloseReason
from ReasonsPerPost rpp
inner join
(
select top 1 TotalByCloseReason
from ReasonsPerPost rpp2
where rpp2.Id = rpp.Id
and Name is NOT NULL
order by TotalByCloseReason desc
) s on s.Id = rpp.Id
where Name is NOT NULL
The below might work for your need.
But without looking at the data is hard to tell it will or not.
;with t as
(
Select Id, max(totalbyclosereason) TC from reasonsperpost where name is not null group by id
)
Select T.id,t.tc,c.closereasontypeid,c.name
From t join reasonsperpost c on t.id = c.id and t.tc = c.totalbyclosereason

Group by clause with min

I am having the following table
I used following query and i got error message. I can identify why the error is but how can i solve it
select min(id),customer_id,created_at from thunderbolt_orders
group by customer_id
I need the minimum id's customer_id and created_at how can i achieve it.
select distinct on (customer_id)
customer_id, id, created_at
from thunderbolt_orders
order by customer_id, id
with cte as (
select
*, row_number() over(partition by customer_id order by id) as row_num
from Table1
)
select *
from cte
where row_num = 1
SELECT id,customer_id,created_at
FROM thunderbolt_orders
WHERE id IN
(SELECT MIN(id) FROM thunderbolt_orders GROUP BY customer_id);
Depending on whether or not you just want the minimum ID or whether you want the minimum ID for each customer these are the solutions.
Minimum ID:
select top 1 id,customer_id,created_at from thunderbolt_orders order by id asc
Minimum ID for each customer:
with cte as (
select min(id) as id
from thunderbolt_orders
group by customer_id
)
select *
from cte c
inner join thunderbolt_orders t on t.id = c.id