-2

I have been given a task which I should look on items table and grab first item of 2019 and last item for 2019 and set the active flags on them as active , the query I wrote only I can grab one by one depends on the store, and it takes days to finish if I have no other choice, here is my query in SQL Server:

SELECT *
FROM NODES 
WHERE NODE ID = 5562 
  AND DATE BETWEEN '2019/01/01' AND '2019/12/30' 

Basically I need the first and the last item for the year, but the problem is every Node is a specific store which has many record and I have run the query for million of records in many Nodes, is it possible if I for example say OK SQL from the given nodes take first and last item for 2019 and display to me and then update their active flag = 'Y'

Is it possible with a CTE, do I need a CTE at all?

Thank you

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 1
    You will need to provide more detail about your table and how you interpret the values it contains in all these rows. We don't know what "item" means when your table is named "nodes". This requires explanation. Note that the **last** day of 2019 is Dec 31, not Dec 30. – SMor Jul 21 '22 at 16:51

1 Answers1

0

If I understood correctly, you could try using a CTE with a windowed function to fetch only the first row from each store after ordering by date in ascending order and the first row from each store after ordering by date in descending order.

For instance :

CREATE TABLE NODES (NodeId int,NodeDate DATETIME2,status NVARCHAR(128))

INSERT INTO NODES(NodeId,NodeDate,Status) VALUES 
(1,'2019/01/01','inactive'),
(1,'2019/03/01','inactive'),
(1,'2019/06/01','inactive'),
(1,'2019/09/01','inactive'),
(1,'2019/12/01','inactive'),
(2,'2019/01/01','inactive'),
(2,'2019/03/01','inactive'),
(2,'2019/06/01','inactive'),
(2,'2019/09/01','inactive'),
(2,'2019/12/01','inactive'),
(3,'2019/01/01','inactive'),
(3,'2019/03/01','inactive'),
(3,'2019/06/01','inactive'),
(3,'2019/09/01','inactive'),
(3,'2019/12/01','inactive')


;WITH cte AS
(
   SELECT status,
         ROW_NUMBER() OVER (PARTITION BY NodeId ORDER BY NodeDate ASC) AS FirstDate,
         ROW_NUMBER() OVER (PARTITION BY NodeId ORDER BY NodeDate DESC) AS LastDate         
   FROM NODES
   WHERE NodeDate >= '2019/01/01' AND NodeDate < '2020/01/01'
)
UPDATE CTE SET status = 'active'
WHERE FirstDate = 1 OR LastDate = 1 


SELECT * FROM NODES

Try it online

Please do note however that this operation can be non deterministic if multiple rows have the same date.

See also : Get top 1 row of each group

Random User
  • 341
  • 3
  • 6
  • Really helpful, one thing I have realised the query didn't activate the last date, only it activate the first date on the last line instead of OR I put WHERE FirstDate = 1 AND LastDate = 1 still didn't activate it the last date from the give NODES – Shahab16667 Jul 21 '22 at 17:42
  • Indeed, I hade inadvertently forgotten to fix a small mistake in my fiddle. I edited the post to fix this. – Random User Jul 21 '22 at 18:13
  • Big help, you have solved it in the best way possible, I tested it and it's working just fine – Shahab16667 Jul 21 '22 at 18:40