SQL Server : how to write the correct query? - sql

This is my query
SELECT
ROW_NUMBER() OVER (ORDER BY [OtpInfoId] ASC ) AS RowNumber,
[OtpInfoId] ,
[OtpStatusId]
INTO
#TempTable
FROM
RequestOTP.Main.TbOtpStatusHistory
And this is part of the results:
RowNumber OtpInfoId OtpStatusId
----------------------------------
1 1 2
2 1 1
3 1 9
4 1 5
1 2 2
2 2 1
3 2 9
4 2 5
1 3 2
2 3 1
3 3 9
4 3 5
5 3 7
I want write a query to return what OtpInfoId have OtpStatusId with at least one state 7
In this example, the query should return this result:
RowNumber OtpInfoId OtpStatusId
----------------------------------
1 3 2
2 3 1
3 3 9
4 3 5
5 3 7
But I don't know how to write it.

You can use a correlated subquery with a WHERE EXIST clause.
SELECT
ROW_NUMBER() OVER (ORDER BY [OtpInfoId] ASC ) AS RowNumber ,
[OtpInfoId] ,
[OtpStatusId]
INTO #TempTable
FROM RequestOTP.Main.TbOtpStatusHistory osh
WHERE EXISTS (
SELECT 1
FROM RequestOTP.Main.TbOtpStatusHistory
WHERE OtpStatusId = 7 AND OtpInfoId = osh.OtpInfoId
)

One method is to use an EXISTS.
SELECT *
FROM (SELECT row_number() OVER (ORDER BY [OtpInfoId] ASC) RowNumber,
[OtpInfoId],
[OtpStatusId]
FROM [RequestOTP].[Main].[TbOtpStatusHistory]) x
WHERE EXISTS (SELECT *
FROM [RequestOTP].[Main].[TbOtpStatusHistory] y
WHERE y.[OtpInfoId] = x.[OtpInfoId]
AND y.[OtpStatusId] = 7)
INTO #TempTable;

Try this:
SELECT * FROM RequestOTP.Main.TbOtpStatusHistory
WHERE OtpInfoId IN (
SELECT OtpInfoId FROM RequestOTP.Main.TbOtpStatusHistory WHERE OtpStatusId = 7
)
INTO #TempTable;
This subquery returns all the OtpInfoId that have OtpStatusId = 7

Here is one approach:
SELECT
RowNumber,
OtpInfoId,
OtpStatusId
FROM
(
SELECT
ROW_NUMBER() OVER (PARTITION BY [OtpInfoId] ORDER BY OtpInfoId) AS RowNumber,
COUNT(CASE WHEN OtpStatusId = 7 THEN 1 END) OVER (PARTITION BY OtpInfoId) cnt
[OtpInfoId],
[OtpStatusId]
FROM RequestOTP.Main.TbOtpStatusHistory
) t
WHERE cnt > 0
INTO #TempTable;
Note that the row numbering in your expected is not clear, because there is no obvious column which provides that ordering. What is missing is a partition on the OtpInfoId, so I added one.

Please try following script to see if it satisfies your requirement.
create table RequestOTP.Main.TbOtpStatusHistory
(
OtpInfoId int,
OtpStatusId int
)
insert into RequestOTP.Main.TbOtpStatusHistory values
(1,2),(1,1),(1,9),(1,5),(2,2),(2,1),
(2,9),(2,5),(3,2),(3,1),(3,9),(3,5),
(3,7)
;with cte as
(
SELECT
ROW_NUMBER() OVER (partition by OtpInfoId ORDER BY [OtpInfoId] ASC ) AS RowNumber,
[OtpInfoId] ,
[OtpStatusId]
FROM RequestOTP.Main.TbOtpStatusHistory
)
select * from cte
where OtpInfoId in
(select OtpInfoId from RequestOTP.Main.TbOtpStatusHistory where OtpStatusId=7)
/*
RowNumber OtpInfoId OtpStatusId
-------------------- ----------- -----------
1 3 2
2 3 1
3 3 9
4 3 5
5 3 7
*/
Best Regards,
Rachel

Related

How to give group numbers based on a condition in sql

Here is my table. I am using Snowflake
CREATE TABLE testx
(
c_order int,
c_condition varchar(10)
);
INSERT INTO testx
VALUES (1, 'and'), (2, 'and'), (3, 'or'), (4, 'and'), (5, 'or');
SELECT * FROM testx
c_order c_condition
--------------------
1 and
2 and
3 or
4 and
5 or
I am trying to write a query which will give me group numbers based on the fact that consecutive 'and's should be with same group number. when 'or' comes, it should increase the group number. by the way, we should maintain the c_order also.
Here is the expected result:
c_order c_condition group_no
-------------------------------
1 and 1
2 and 1
3 or 2
4 and 2
5 or 3
I have tried using dense_rank like this:
SELECT
*,
DENSE_RANK() OVER (ORDER BY c_condition)
FROM testx
But it doesn't return exactly what I want. Can somebody please help?`
Idea is to use same value for C_ORDER as group_no if
C_ORDER is more then previous OR's c_order.
In CTE we only select rows with OR and assign them a
group number using ROW_NUMBER() generator -
Main query -
with temp_cte as
(
select c_order,
case -- to check if 'or' is the first row or not
when (select min(c_order) from testx where c_condition='or') =
(select min(c_order) from testx)
then row_number() over (order by c_order)
else
row_number() over (order by c_order)+1
end rn
from testx, table(generator(rowcount=>1))
where c_condition='or'
)
select x.c_order, x.c_condition,
case
when x.c_order = w.c_order
then w.rn
when x.c_order > (select min(c_order) from temp_cte)
then (select max(rn) from temp_cte where c_order < x.c_order)
else 1
end seq1
from testx x left join temp_cte w
on x.c_order = w.c_order
order by x.c_order;
Output -
C_ORDER
C_CONDITION
SEQ1
1
and
1
2
and
1
3
or
2
4
or
3
5
and
3
6
and
3
7
or
4
8
and
4
9
or
5
For data-set
select * from testx;
C_ORDER
C_CONDITION
1
and
2
and
3
or
4
or
5
and
6
and
7
or
8
and
9
or
Or, just use CONDITIONAL_TRUE_EVENT. Refer
with data(C_ORDER,C_CONDITION) as(
select * from values
(1,'and'),
(2,'and'),
(3,'or'),
(4,'or'),
(5,'and'),
(6,'and'),
(7,'or'),
(8,'and'),
(9,'or')
)select c_order, c_condition,
conditional_true_event(c_condition='or') over (order by c_order) grp
from data;
C_ORDER
C_CONDITION
GRP
1
and
0
2
and
0
3
or
1
4
or
2
5
and
2
6
and
2
7
or
3
8
and
3
9
or
4

sql numbering the partition of Numbers

I have a set of numbers like this
ID
===
1
2
3
1
2
1
1
2
3
4
5
...
I want to select a new row that increase when fetch next 1 like this
ID number
=== ========
1 1
2 1
3 1
1 2
2 2
1 3
1 4
2 4
3 4
4 4
5 4
Any suggestion ?
Assuming that you have a column o which specify the ordering then you can use a self-join like this:
select d1.o, d1.id, count(*)
from data d1
join data d2 on d1.o >= d2.o and d2.id = 1
group by d1.o, d1.id
DBFiddle DEMO
You can solve this with use of cte and window functions, as follows:
DECLARE #t TABLE (ID INT);
INSERT INTO #t VALUES (1),(2),(3),(1),(2),(1),(1),(2),(3),(4),(5);
WITH cte AS(
SELECT ID, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) rn
FROM #t
),
cte1 AS(
SELECT ID, rn, ROW_NUMBER() OVER (ORDER BY rn) rn2
FROM cte
WHERE ID = 1
)
SELECT c.ID, MAX(rn2) OVER (ORDER BY c.rn) rn
FROM cte c
LEFT JOIN cte1 c1 ON c1.rn = c.rn
ORDER BY c.rn

Update sort Column linked with group

How can i change the position of one row to change the order
Best to explain with example
I have following table with statuses
Id Name StatusOrder StatusGroup
1 Open 1 1
2 Start 2 1
3 Load 3 1
4 Close 4 1
5 Begin 1 2
6 Open 2 2
7 Close 3 2
I would like to Switch from group one only Status order 2 with 3.
The jump can be more than one row, ex. its also possible that within the same group the order from open moves to status order 3
Sow when i do following select
SELECT * FROM Status WHERE (StatusGroup =1)
Result Set:
Id Name StatusOrder StatusGroup
1 Open 1 1
3 Load 2 1
2 Start 3 1
4 Close 4 1
5 Begin 1 2
6 Open 2 2
7 Close 3 2
I already found example with following article but i do not succeed in it to intgrate that only for one group the order changes
Using a sort order column in a database table
How Can help me?
If correctly understood, here you go:
QUERY
create table #t
(
Id INT,
Name VARCHAR(20),
StatusOrder INT,
StatusGroup INT
)
insert into #t values
(1 ,'Open', 1 , 1),
(2 ,'Start', 2 , 1),
(3 ,'Load', 3 , 1),
(4 ,'Close', 4 , 1),
(5 ,'Begin', 1 , 2),
(6 ,'Open', 2 , 2),
(7 ,'Close', 3 , 2)
;with cte as (
select *, row_number() over(partition by StatusGroup order by Id) rn
from #t
)
select case when StatusOrder = 2 then 3 when StatusOrder = 3 then 2 else Id end as Id,
case when StatusOrder = 2 then 'Load' when StatusOrder = 3 then 'Start' else Name end as Name,
StatusOrder,
StatusGroup
from cte
where rn = id
union all
select Id, Name, StatusOrder, StatusGroup
from cte
where rn <> id
drop table #t
OUTPUT
Id Name StatusOrder StatusGroup
1 Open 1 1
3 Load 2 1
2 Start 3 1
4 Close 4 1
5 Begin 1 2
6 Open 2 2
7 Close 3 2
UPDATE
So if you have table where you need update records you can do something like:
;with cte as (
select *, row_number() over(partition by StatusGroup order by Id) rn
from #t
)
update t
set t.Id = (case when cte.StatusOrder = 2 then 3
when cte.StatusOrder = 3 then 2 else t.Id end),
t.Name = (case when cte.StatusOrder = 2 then 'Load'
when cte.StatusOrder = 3 then 'Start' else t.Name end)
from cte
join #t t on cte.id = t.id
where cte.rn = cte.id

Group by every 3 record

How to achieve this(SQL)?
My Table
id sub
1 1
2 1
3 1
4 1
5 1
6 2
7 2
8 2
The result should be like below
groupid id sub groupid id sub
0 1 1 0 1 1
0 2 1 0 2 1
0 3 1 0 3 1
1 4 1 or 1 6 2
1 5 1 1 7 2
2 6 2 1 8 2
2 7 2
2 8 2
My current query is
SELECT (id - 1) / 3 groupid, id, point FROM student
EDIT: The first DENSE_RANK() in my original answer could be eliminated to simply end up with;
WITH cte AS (
SELECT ROW_NUMBER() OVER (PARTITION BY SUB ORDER BY ID) as rn, id, sub
FROM student)
SELECT DENSE_RANK() OVER (ORDER BY sub,(rn-1)/3) as groupid, id, sub FROM cte;
An SQLfiddle to test with.
-- original answer --
Assuming SQL server, you can use DENSE_RANK() to your advantage;
WITH cte AS (
SELECT DENSE_RANK() OVER (ORDER BY sub) AS rank,
ROW_NUMBER() OVER (PARTITION BY SUB ORDER BY ID) as rn,
id, sub
FROM student)
SELECT DENSE_RANK() OVER (ORDER BY sub,rank,(rn-1)/3) as groupid,
id,sub FROM cte;
An SQLfiddle to test with.
SELECT (id - 1) div 3 as groupid, id, point FROM student

Select and aggregate last records base on order

I have different versions of the charges in a table. I want to grab and sum the last charge grouped by Type.
So I want to add 9.87, 9.63, 1.65.
I want the Parent ID , sum(9.87 + 9.63 + 1.65) as the results of this query.
We use MSSQL
ID ORDER CHARGES TYPE PARENT ID
1 1 6.45 1 1
2 2 1.25 1 1
3 3 9.87 1 1
4 1 6.54 2 1
5 2 5.64 2 1
6 3 0.84 2 1
7 4 9.63 2 1
8 1 7.33 3 1
9 2 5.65 3 1
10 3 8.65 3 1
11 4 5.14 3 1
12 5 1.65 3 1
WITH recordsList
AS
(
SELECT Type, Charges,
ROW_NUMBER() OVER (PArtition BY TYPE
ORDER BY [ORDER] DESC) rn
FROM tableName
)
SELECT SUM(Charges) totalCharge
FROM recordsLIst
WHERE rn = 1
SQLFiddle Demo
Use row_number() to identify the rows to be summed, and then sum them:
select SUM(charges)
from (select t.*,
ROW_NUMBER() over (PARTITION by type order by id desc) as seqnum
from t
) t
where seqnum = 1
Alternatively you could use a window aggregate MAX():
SELECT SUM(Charges)
FROM (
SELECT
[ORDER],
Charges,
MaxOrder = MAX([ORDER]) OVER (PARTITION BY [TYPE])
FROM atable
) s
WHERE [ORDER] = MaxOrder
;
SELECT t.PARENT_ID, SUM(t.CHARGES)
FROM dbo.test73 t
WHERE EXISTS (
SELECT 1
FROM dbo.test73
WHERE [TYPE] = t.[TYPE]
HAVING MAX([ORDER]) = t.[ORDER]
)
GROUP BY t.PARENT_ID
Demo on SQLFiddle