Home > Enterprise >  Change SQL query: Partition By
Change SQL query: Partition By

Time:04-09

I have a TABLE, for that TABLE I want to retrieve table data for max of DATE<01-01-2021 & max of DATE<01-01-2022.

Table Query is:

  select * from TABLE where ENTITY ID=47 order by DATE

TABLE DATA:

AuditID DATE ENTITY ID
78632 11/14/2017 47
82181 12/12/2017 47
110243 7/6/2018 47
134478 4/24/2019 47
154082 8/19/2019 47
154083 4/3/2021 47
154084 5/3/2021 47
222971 6/3/2021 47

Result required:

AuditID DATE ENTITY ID
154082 8/19/2019 47
222971 6/3/2021 47

For the above result I've used below query:

**

select * from TABLE where DATE =
(select max(DATE) from TABLE where DATE <DATEFROMPARTS(YEAR(GETDATE())-1,1,1) and ENTITY ID=47 )
OR DATE =
(select max(DATE) from TABLE where DATE < DATEFROMPARTS(YEAR(GETDATE()),1,1) and ENTITY ID=47 )
and ENTITY ID=47

**

But the due to performance issue for millions of records, I want to write above query using "OVER PARTITION BY "

CodePudding user response:

You can use top and union. If date needs to be calculated do it before the query. ie:

declare @thisYear datetime = datefromparts(year(getdate()),1,1);
declare @lastYear datetime = datefromparts(year(getdate())-1,1,1);
declare @entityId int = 47;

select * from
    (select top(1) * from myTable
    where entitiyId = @entityId and [date] < @lastYear
    order by [date] desc) t1
    union all
select * from
    (select top(1) * from myTable
    where entitiyId = @entityId and [date] < @thisYear
    order by [date] desc) t2;

CodePudding user response:

I'm pretty sure a union all would be far more efficient than those subqueries:

DECLARE @EntityID int = 47,
        @thisyear date = DATEFROMPARTS(YEAR(GETDATE()),1,1);

SELECT * FROM 
(
  SELECT TOP (1) * FROM dbo.table 
  WHERE DATE < @thisyear
    AND EntityID = @EntityID
  ORDER BY DATE DESC
) AS t2021
UNION ALL
SELECT * FROM 
(
  SELECT TOP (1) * FROM dbo.table
  WHERE DATE < DATEADD(YEAR, -1, @thisyear)
    AND EntityID = @EntityID
  ORDER BY DATE DESC
) AS t2020;

If you really, really, really want to use a window function:

DECLARE @EntityID int = 47,
        @thisyear date = DATEFROMPARTS(YEAR(GETDATE()),1,1);

; /* previous statement terminator, see sqlblog.org/cte */
WITH cte AS
(
  SELECT AuditID, DATE, EntityID, y = YEAR([Date]),
    rn = ROW_NUMBER() OVER (PARTITION BY YEAR([Date]) ORDER BY [Date] DESC)
  FROM dbo.table
  WHERE EntityID = @EntityID
    AND DATE < @thisyear
)
SELECT TOP (2) AuditID, DATE, EntityID
   FROM src 
   WHERE rn = 1 ORDER BY y DESC;

CodePudding user response:

Though the union all from the other answers is IMHO the most easy to read and understand solution, I would still like to offer another way to write it

select t.*
from   table1 t
  cross apply (select top 1 [Date]
               from   table1 t2
               where  t2.[Date] < '20210101'
               order by t2.[Date] desc
              ) m21
  cross apply (select top 1 [Date]
               from   table1 t2
               where  t2.[Date] < '20220101'
               order by t2.[Date] desc
              ) m22
where  t.[Date] in (m21.[Date], m22.[Date])
and    t.EntityID = 47

You can see it in this DBFiddle

  • Related