replacement of Offset Limit in SQL Server - sql-server-2012

We have DataTemp table which has the records in desc order.
select * from (
select 9,'a',3 union
select 8,'a',2 union
select 7,'b',3 union
select 6,'a',1 union
select 5,'b',2 union
select 4,'c',3 union
select 3,'c',2 union
select 2,'b',1 union
select 1,'c',1
) door (sno,id, N_th_Reocord)
sno - Auto Id.
id - code of the Doors*.
N_th_Record - for denoting the n the record.
At a time, only three* records per Door are need to store on this table. For example Door 'a' has new entry(means 4th record) then first of 'a' Door need to delete.
4th record:
select * from (
select 10,'a',4 union --- new entry
select 9,'a',3 union
select 8,'a',2 union
select 7,'b',3 union
select 6,'a',1 union -- need to delete
select 5,'b',2 union
select 4,'c',3 union
select 3,'c',2 union
select 2,'b',1 union
select 1,'c',1
) door (sno,id, N_th_Reocord)
I do following query. But I need easiest way for deleting the row. Because, we are try to reduce the time consumption of over all project.
delete from door where sno = (
select sno from (
select 10,'a',4 union
select 9,'a',3 union
select 8,'a',2 union
select 7,'b',3 union
select 6,'a',1 union
select 5,'b',2 union
select 4,'c',3 union
select 3,'c',2 union
select 2,'b',1 union
select 1,'c',1
) door (sno,id, N_th_Reocord)
where id = 'a'
order by sno desc -- For 'DataTemp' *order by* is no needed.
offset 3 rows fetch next 1 rows only
)
Note:
Three rows and three Door are given for example. Actually we work with 144 rows per 12 Doors.
Before this delete, we check lot of Business rules.
Version: SQL Server 2012

You could use ROW_NUMBER:
WITH cte AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY id ORDER BY sno DESC) rn FROM t)
DELETE FROM cte WHERE rn > 3;
db<>fiddle demo

Related

SQL Select query optimization with indexing

A posts table contains 1 million rows. This table has a field with the name poster_id.
I have a list of followers by this poster_id.
I am trying to get a list of all activities from this followers (35 in this case but less or more is possible) in the last 48 hours.
I use this query:
SELECT post_id
, topic_id
, poster_id
, post_time
FROM posts
WHERE post_time > 1606833542
AND poster_id IN (80202, 74247, 79290, 72488,
111751, 85040, 100256, 68025,
101088, 101598, 101950, 103252,
103071, 80063, 100372, 102530, 109961,
109854, 105626, 108967, 110391, 104423,
113243, 111673, 113979, 104670, 127318,
68252, 109606, 121393, 122991, 124489,
127723, 126525)
ORDER
by post_time
LIMIT 100
Problem:
This query takes too long (0.4000 seconds) to execute.
The poster_id has an index of the post table.
How can I make this query faster?
try avoid the IN clause and use a join
SELECT
p.post_id
, p.topic_id
, p.poster_id
, p.post_time
FROM posts p
INNER JOIN (
SELECT 80202 poster_id
UNION SELECT 74247
UNION SELECT 79290
UNION SELECT 72488
UNION SELECT 111751
UNION SELECT 85040
UNION SELECT 100256
UNION SELECT 68025
UNION SELECT 101088
UNION SELECT 101598
UNION SELECT 101950
UNION SELECT 103252
UNION SELECT 103071
UNION SELECT 80063
UNION SELECT 100372
UNION SELECT 102530
UNION SELECT 109961
UNION SELECT 109854
UNION SELECT 105626
UNION SELECT 108967
UNION SELECT 110391
UNION SELECT 104423
UNION SELECT 113243
UNION SELECT 111673
UNION SELECT 113979
UNION SELECT 104670
UNION SELECT 127318
UNION SELECT 68252
UNION SELECT 109606
UNION SELECT 121393
UNION SELECT 122991
UNION SELECT 124489
UNION SELECT 127723
UNION SELECT 126525
) t ON t.poster_id = p.poster_id
AND p.post_time > 1606833542
ORDER by p.post_time LIMIT 100
could be the value in the IN clause are form some subquery in this case ypou could use the related subquery instead of the UNION .....
WHERE IN clase is the same as serverl OR condition (several internal subquery) .. instead INNER JOIN just check the values in a single operation
for better performance, instead of you actual index on poster_id, you could try using a redundant index adding all the columns you select in your index eg:
create index my_index on posts (poster_id, post_id, topic_id , post_time )
in this way all the query value are obtained using the index and the query don't need to access at the table ..

Oracle Select max where a certain key is matched

i'm working with oracle, plSql, i need to query a table and select the max id where a key is matched, now i have this query
select t.* from (
select distinct (TO_CHAR(I.DATE, 'YYMMDD') || I.AUTH_CODE || I.AMOUNT || I.CARD_NUMBER) as kies, I.SID as ids
from transactions I) t group by kies, ids order by ids desc;
It's displaying this data
If i remove the ID from the query, it displays the distinct keys (in the query i use the alias KIES because keys was in blue, so i thought it might be a reserved word)
How can i display the max id (last one inserted) for every different key without displaying all the data like in the first image??
greetings.
Do you just want aggregation?
select thekey, max(sid)
from (select t.*,
(TO_CHAR(t.DATE, 'YYMMDD') || t.AUTH_CODE || t.AMOUNT || t.CARD_NUMBER) as thekey,
t.SID
from transactions t
) t
group by thekey
order by max(ids) desc;
Since you haven't provided data in text format, its difficult to type such long numbers and recreated the data.
However I think you can simply use the MAX analytical function to achieve your results.
with data as (
select 1111 keys,1 id from dual
union
select 2222, 1 from dual
union
select 1111, 2 from dual
union
select 2222,3 from dual
union
select 9999, 1 from dual
union
select 1111, 5 from dual
)
select distinct keys, max(id) over( partition by (keys)) from data
This query returns -
KEYS MAX(ID)OVER(PARTITIONBY(KEYS))
1111 5
9999 1
2222 3

SQL assigning incremental ID to subgroups

As the title says, I'm trying to add an extra column to a table which autoincrements everytime a different string in another column changes.
I would like to do this in a query.
Example:
MyCol GroupID
Cable 1
Cable 1
Foo 2
Foo 2
Foo 2
Fuzz 3
Fizz 4
Tv 5
Tv 5
The GroupID column is what I want to accomplish.
We can be sure that MyCol's strings will be the same in each subgroup (Foo will always be Foo, etc).
Thanks in advance
If I understand correctly, you can use dense_rank():
select t.*, dense_rank() over (order by col1) as groupid
from t;
You could make a temporal table with the distinct value of the MyCol and get the groupId throught the RowNumber of the temp table, and join the rownumbered result with your table.
This is a raw example in oracle:
WITH data AS
(SELECT 'Cable' MyCol FROM dual
UNION ALL
SELECT 'Cable' FROM dual
UNION ALL
SELECT 'Foo' FROM dual
UNION ALL
SELECT 'Foo' FROM dual
UNION ALL
SELECT 'Foo' FROM dual
UNION ALL
SELECT 'Fuzz' FROM dual
UNION ALL
SELECT 'Fizz' FROM dual
UNION ALL
SELECT 'Tv' FROM dual
UNION ALL
SELECT 'Tv' FROM dual
),
tablename AS
(SELECT * FROM data
),
temp AS
( SELECT DISTINCT mycol FROM tablename
),
temp2 AS
( SELECT mycol, rownum AS groupid from temp
)
SELECT tablename.mycol, temp2.groupid FROM temp2 JOIN tablename ON temp2.mycol = tablename.mycol
You could also check for a way to implement the tabibitosan method knowing that your column condition is string.

Oracle SQL Query IN

I have following query, that's not working.
select * from table where id in (
1,2, (select id from another_table)
)
How i can rewrite it?
How about
select * from table
where id in (1,2)
or id in (select id from another_table)
Take care and use parentheses when adding additional WHERE-conditions using and!!!
select *
from table
where id in (1,2) OR id in(
select id from another_table
)
select * from table where id in (
select 1 as id from dual
union all
select 2 as id from dual
union all
select id from another_table
)
select * from table where id in (
select 1 from dual
union all
select 2 from dual
union all
select id from another_table);
I'm using union because this is faster than using an OR clause which also can be used.

Union Select Only One Row

I Have a query with Two Select Clause combines with UNION.I want to select only top first row. How can i do that Using Union ?
Select Fault,OccurredOn From ATMStatus Where Ticket=189703 // This Will retrieve single record as the primary key is applied
Union
Select Fault,OccurredOn From ATMStatusHistory Where Resolved=0 AND Ticket=189703 Order By OccurredOn Desc
select top 1 * from
(
Select Fault,OccurredOn
From ATMStatus
Where Ticket=189703
Union
Select Fault,OccurredOn
From ATMStatusHistory
Where Resolved=0 AND Ticket=189703
) x
Order By OccurredOn Desc
This returns 2 rows:
select 1 as id
union
select 2 as id
This returns 1 row:
select top 1 * from (
select 1 as id
union
select 2 as id
) as x
order by id