Calculate Page number based on two columns - sql-server

I have the below table I want to find the Page number.
The logic is if the sum of both col A and col b is greater than or equal to 15 then it should be page and it should be incremented.
Col A will be always 1 or 0. Only Col B will changed
Problem :
Col X
Col y
col A
Col B
Pagenumber
x
y
1
105
x
y
1
0
x
y
1
2
x
y
1
6
x
y
1
3
null
y
0
1
x
y
1
2
x
y
1
3
x
y
1
1
x
y
1
4
Expected output :
Col X
Col y
col A
Col B
Pagenumber
x
y
1
105
Page 1
x
y
1
0
Page 2
x
y
1
2
Page 2
x
y
1
6
Page 2
x
y
1
3
Page 2
null
y
0
1
Page 3
x
y
1
2
Page 3
x
y
1
3
Page 3
x
y
1
1
Page 3
x
y
1
4
Page 3
Query without pagenumber column:
SELECT
IIF(c2.isdeleted = 1 OR c2.approved = 0, NULL, c2.content) AS Content,
(SELECT STRING_AGG(c1.content, ', ')
FROM comments c1
WHERE c1.parentcommentid = c2.id
AND c1.isdeleted = 0
AND c1.approved = 1) ChildContent,
IIF(c2.isdeleted = 1 OR c2.approved = 0, 0, 1) AS Contentcount,
(SELECT COUNT(c1.content)
FROM comments c1
WHERE c1.parentcommentid = c2.id
AND c1.isdeleted = 0
AND c1.approved = 1) ChildContentcount
FROM
comments c2
WHERE
c2.discussionid = '402930'
AND c2.parentcommentid IS NULL
-- AND Content IS NOT NULL
ORDER BY
c2.pinned DESC,
c2.createddate

You need to specify the order of rows in which the cumulative sum should be calculated.
You can use a recursive CTE to calculate and partition the running sum.
with t(rn, x, y, a, b) as (
select row_number() over (order by ???), -- set the ordering columns here
x, y, a, b
from your_table
),
cte(rn, x, y, a, b, running_sum, page) as (
select t.rn, t.x, t.y, t.a, t.b, t.a + t.b, 1
from t where rn = 1
union all
select t.rn, t.x, t.y, t.a, t.b,
t.a + t.b + case when cte.running_sum >= 15 then 0 else cte.running_sum end,
case when cte.running_sum >= 15 then cte.page + 1 else cte.page end
from cte join t on t.rn = cte.rn + 1
where t.rn > 1
)
select *
from cte;
Result:

Related

Conditional ROW NUMBER to create a Column in SQL

I have two columns ID and FLAG as :
ID FLAG
1 Y
1 N
1 Y
1 N
1 N
1 N
1 N
1 Y
1 N
2 N
2 Y
2 N
2 N
2 Y
2 Y
2 N
Required Output:
ID FLAG REQ_COL
1 Y null
1 N 1
1 Y null
1 N 1
1 N 2
1 N 3
1 N 4
1 Y null
1 N 1
2 N null
2 Y null
2 N 1
2 N 2
2 Y null
2 Y null
2 N 1
Logic for required column :
For first occurence of ID , REQ_COL is null
If FLAG=Y then REQ_COL is null
IF previous value of FLAG is Y and there are consecutive N in FLAG , then the REQ_COL values are 1,2,3,4, 5.....
Else Null
I am trying to apply conditional row_number but not getting idea how to proceed.
Please help.
This might give you the result you are searching for...
Data Preparation
DECLARE #SOURCE_TABLE AS TABLE (realid int identity (1,1), ID int, FLAG CHAR(1))
INSERT INTO #SOURCE_TABLE (ID, FLAG)
VALUES (1, 'Y'),(1, 'N'),(1, 'Y'),(1, 'N'),(1, 'N'),(1, 'N'),
(1, 'N'),(1, 'Y'),(1, 'N'),(2, 'N'),(2, 'Y'),(2, 'N'),
(2, 'N'),(2, 'Y'),(2, 'Y'),(2, 'N')
Actual Select
SELECT ST2.ID, ST2.FLAG,
NULLIF(NULLIF (CHARINDEX('Y', REVERSE(
(
SELECT ST1.FLAG AS [text()]
FROM #SOURCE_TABLE ST1
WHERE ST1.ID = ST2.ID AND ST1.realid <= ST2.realid
ORDER BY ST1.realid
FOR XML PATH (''), TYPE
).value('text()[1]','VARCHAR(MAX)')
)), 1) - 1, -1) AS [REQ_COL]
FROM #SOURCE_TABLE AS ST2
ORDER BY ST2.realid

How to select k distinct value by a field?

How to select all infos from k distinct value of field X?
I have an idea to group by by some field X and then select like this
Table
id name
1 x
2 y
3 x
4 y
5 z
6 w
Group by name:
id name
1 x
3 x
2 y
4 y
5 z
6 w
Select k=3 distinct value of name:
id name
1 x
3 x
2 y
4 y
5 z
Any idea how to write this query?
Try this -
WITH CTE AS (SELECT DISTINCT name
FROM TAB
LIMIT 3)
SELECT * FROM TAB
WHERE NAME IN (SELECT name FROM CTE)
ORDER BY name;
select id, name
from (
select id, name, dense_rank() over (order by name) as ds
from t
) s
where ds <= 3

Query to identify contiguous ranges

I'm trying to write a query on the below data set to add a new column which has some sort of "period_id_group".
contiguous new_period row_nr new_period_starting_id
0 0 1 0
1 1 2 2
1 0 3 0
1 0 4 0
1 1 5 5
1 0 6 0
What I'm trying to get is:
contiguous new_period row_nr new_period_starting_id period_id_group
0 0 1 0 0
1 1 2 2 2
1 0 3 0 2
1 0 4 0 2
1 1 5 5 5
1 0 6 0 5
The logic is that for each 0 value in the new_period_starting_id, it has to get the >0 value from the row above.
So, for row_nr = 1 since there is no row before it, period_id_group is 0.
For row_nr = 2 since this is a new perid (marked by new_period = 1), the period_id_group is 2 (the id of this row).
For row_nr = 3 since it's part of a contiguous range (because contiguous = 1), but is not the start of the range, because it's not a new_period (new_period = 0), its period_id_group should inherit the value from the previous row (which is the start of the contiguous range) - in this case period_id_group = 2 also.
I've tried multiple versions but couldn't get a good solution for SQL Server 2008R2, since I can't use LAG().
What I have, so far, is a shameful:
select *
from #temp2 t1
left join (select distinct new_period_starting_id from #temp2) t2
on t1.new_period_starting_id >= t2.new_period_starting_id
where 1 = case
when contiguous = 0
then 1
when contiguous = 1 and t2.new_period_starting_id > 0
then 1
else 1
end
order by t1.rn
Sample data script:
declare #tmp2 table (contiguous int
, new_period int
, row_nr int
, new_period_starting_id int);
insert into #tmp2 values (0, 0, 1, 0)
, (1, 1, 2, 2)
, (1, 0, 3, 0)
, (1, 0, 4, 0)
, (1, 1, 5, 5)
, (1, 0, 6, 0);
Any help is appreciated.
So, if I'm understanding you correctly, you just need one additional column.
SELECT t1.contiguous, t1.new_period, t1.row_nr, t1.new_period_starting_id,
(SELECT TOP 1 (new_period_starting_id)
FROM YourTable t2
WHERE t2.row_nr <= t1.row_nr
AND t2.period_id_group > 0 /* optimization */
ORDER BY t2.row_nr DESC /* optimization */) AS period_id_group
FROM YourTable t1
Here is yet another option for this.
select t1.contiguous
, t1.new_period
, t1.row_nr
, t1.new_period_starting_id
, x.new_period_starting_id
from #tmp2 t1
outer apply
(
select top 1 *
from #tmp2 t2
where (t2.row_nr = 1
or t2.new_period_starting_id > 0)
and t1.row_nr >= t2.row_nr
order by t2.row_nr desc
) x
Found the solution:
select *
, case
when contiguous = 0
then f1
when contiguous = 1 and new_periods = 1
then f1
when contiguous = 1 and new_periods = 0
then v
else NULL
end [period_group]
from (
select *
, (select max(f1) from #temp2 where new_period_starting_id > 0 and rn < t1.rn) [v]
from #temp2 t1
) rs
order by rn

SQL Server view for calc ParentId column

I have a table with following sampled rows:
Id CompanyId value
1 X a
2 X b
3 X c
4 X d
5 Y e
6 Y f
7 z g
8 Z h
9 X i
10 X j
I want to have a view with following result :
Id CompanyId ParentId
1 X NULL
2 X NULL
3 X NULL
4 X NULL
5 Y 1
6 Y 1
7 z 5
8 Z 5
9 X 7
10 X 7
On this result calculated ParentId for each row. ParentId for each row equal to Id of first row from previous companyId.
I hope that SQL Server 2012 tag is here for reason :)
;with x as (
select *, lag(companyid) over(order by id) as prev
from #t1
),
y as (
select *, sum(case when prev = companyid then 0 else 1 end) over(order by id) as grp
from x
)
select y.id, y.companyid, min(y1.id)
from y
left join y y1 on y1.grp = y.grp-1
group by y.id, y.companyid

What would be my SqlServer query?

Table1
P R E Value
X 1 10 1
Y 2 30 2
Z 3 CR 3
X 1 30 4
Table2
P R E Value
X 1 CR 4
Y 2 10 5
Y 3 CR 6
W 1 30 7
Query1 - Merge these two tables. I'm able to achieve this using union clause.
Query2 - On the merged table select all records except for entries where for a combination of P, R & E; there are similar records with the only mismatch of 'E' as 30 & 10, then ignore record with E as 30. In case only 30 is present then consider it.
Conditions:
10 & 30 - consider only 10, ignore 30
10 - consider it
30 - consider it
CR - consider it
10 & CR - consider both
30 & CR - consider both
10 & 30 & CR - consider 10 & CR
Expected Output table
P R E Value
X 1 10 1
Z 3 CR 3
X 1 CR 4
Y 2 10 5
Y 3 CR 6
W 1 30 7
Ignored records
Y 2 30 2
X 1 30 4
I was able to achieve your desired result set with the following query.
insert into #Table1
values ('X','1','10','1'),
('Y','2','30','2'),
('Z','3','CR','3'),
('X','1','30','4')
insert into #Table2
values ('X','1','CR','4'),
('Y','2','10','5'),
('Y','3','CR','6'),
('W','1','30','7')
--Query2
select * from(
--Query1
select * from #Table1 union select * from #Table2) x
where E != '30' OR
(
E = '30' AND P+':'+R NOT IN
(
--Modified Query1
select P+':'+R from #Table1 where E = '10'
union
select P+':'+R from #Table2 y where E = '10'
)
)
order by Value

Resources