Row_number skip values - sql

I have a table like this:
The idea were to count only when I have "Include" at column include_appt, when it finds NULL, it should skip set is as "NULL" or "0" and on next found "Include" back to counting where it stopped.
The screenshot above I was almost able to do it but unfortunately the count didn't reset on next value.
PS: I can't use over partition because I have to keep the order by id ASC

I suggest using the DENSE_RANK() with the columns you have hidden (--*,):
SELECT
row_num AS id,
include_appt,
CASE WHEN include_appt is not null
THEN ROW_NUMBER() OVER(ORDER BY (SELECT 0))
+ 1
- DENSE_RANK() OVER(
PARTITION BY /*some hidden columns*/
ORDER BY/*some hidden columns*/)
ELSE NULL
END AS row_num2
FROM C
ORDER BY row_num
Then the result will be:
enter image description here

If you are trying to prevent row numbers being added for NULL/0 values, why not try a query like this instead?
SELECT
row_num AS id,
include_appt,
ROW_NUMBER() OVER
(
ORDER BY (SELECT 0)
) AS row_num2
FROM C
WHERE ISNULL(C.include_appt, 0) <> 0
ORDER BY row_num
I would recommend reconsidering the column names/aliases you want to have displayed in your final result to avoid confusion, but the above should effectively do what you are wanting.

You need a PARTITION BY clause
SELECT
row_num AS id,
include_appt,
CASE WHEN include_appt IS NULL
THEN 0
ELSE
ROW_NUMBER() OVER (PARTITION BY include_appt ORDER BY (SELECT 0))
END AS row_num2
FROM C
ORDER BY row_num

SELECT id, include_appt,
CASE WHEN include_appt IS NULL THEN 0
ELSE ROW_NUMBER() OVER (PARTITION BY include_appt ORDER BY id ASC)
END AS row_num
FROM #1 ORDER BY id asc

This can be easily done with a partition by include_appt as in another answer below, yet after playing around with the query plans I've decided that it is still worthwhile to consider this slightly different approach which might offer a performance boost. I believe the benefit is gained by being able to use the clustered index without involving a sort on the flag column:
select id, flag,
case when flag is not null
then row_number() over (order by id)
- count(case when flag is null then 1 end) over (order by id)
else 0 end /* count up the skips */ as new_rn
from T
order by id
Examples (including a "reset" behavior): https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=c9f4c187c494d2a402e43a3b24924581
Performance comparison:
https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=719f7bd26135ab498d11c786f1b1b28b

Related

Flag "yes/No" if the subsequent row has same ID

I have data like this. If the same id is present in the next row, I want to flag as Yes. If it is not present then Make it as 'No'. Can you kindly help me with the query?
Thanks
The problem with multiple rows for the same ID and no other column that can be used to futher narrow the sort sequence is that you need an order you can rely on. As the typical sulution for the general task to compare with the next row's ID is LEAD, you'll have two ORDER BY clauses in your query, one for LEAD and one for the query result, and you want to force them somehow to obey the same sort order. ORDER BY id is not sufficent.
The best and easiest approach is probably to number the rows first, and then work on this data set.
with numbered
(
select
id,
row_number() over (order by id) as rn
from mytable
)
select
id,
case when id = lead(id) over (order by rn) then 'yes' else 'no' end as flag
from numbered
order by rn;
You can use LEAD, which gets the value of the next row.
SELECT
CASE
WHEN ID = LEAD(ID) OVER (ORDER BY ID) THEN 'yes'
ELSE 'no'
END
FROM [MyTableName]
ORDER BY ID
You can read more about LEAD here.
select ID, Lag(ID) OVER(Order by ID desc) as [NextVal],
case when
Lag(ID) OVER(Order by ID desc) = ID THEN 'yes'
ELSE 'no'
END as 'FLAG'
from tableName
order by 1 , 2

SQL Server : return all rows in set if one row has value equal to target value

I'm currently working on a SQL query that searches an "archive" database and returns a row for each change that occurred on an order from the beginning of time to today.
What I would like to do with this query is only return the orders that are currently or have been associated with a specific order handler. The best way for me to explain it is that every order is currently grouped in a "set" with a row number for each change, but if one of the rows ever holds the value I'm looking for either "handler" columns, I want it to return all the rows, not just the one with that target value.
Here is what I have so far.
SELECT
ROW_NUMBER() OVER (PARTITION BY OrderId ORDER BY EventDateTime) AS RowNumber,
ace.[OrderId],
ace.[OrderHandler],
ace.[EventDateTime],
ace.[OrderStatus],
LAG(ace.[OrderHandler], 1) OVER (PARTITION BY [OrderId] ORDER BY ace.[EventDateTime]) AS PreviousOrderHandler,
LAG(ace.[EventDateTime], 1) OVER (PARTITION BY [OrderId] ORDER BY ace.[EventDateTime]) AS PreviousEventDateTime,
LAG(ace.[OrderStatus], 1) OVER (PARTITION BY [OrderId] ORDER BY ace.[EventDateTime]) AS PreviousOrderStatus
FROM
Archive AS ace
Here is the sample data I receive when running the above query:
So instead of just returning row number 9 where the OrderHandler = POOL, I want to query if the OrderId has an OrderHandler of POOL at ANY TIME in history, return all the rows.
I figured I could potentially use a WHERE EXISTS but I'm not sure how I could return the whole set of results instead of just the results that match.
Any help is extremely appreciated!
You can use exists like this:
select a.*
from ace a
where exists (select 1
from ace a2
where a2.orderid = a.orderid and
a2.orderhandler = #orderhandler
);
Script for solution:
SELECT ROW_NUMBER() OVER (PARTITION BY ace.OrderId ORDER BY ace.EventDateTime) AS RowNumber
,ace.[OrderId]
,ace.[OrderHandler]
,ace.[EventDateTime]
,ace.[OrderStatus]
,LAG(ace.[OrderHandler], 1) OVER ( PARTITION BY ace.[OrderId] ORDER BY ace.[EventDateTime] ) as PreviousOrderHandler
,LAG(ace.[EventDateTime], 1) OVER ( PARTITION BY ace.[OrderId] ORDER BY ace.[EventDateTime] ) as PreviousEventDateTime
,LAG(ace.[OrderId], 1) OVER (PARTITION BY ace.[OrderId] ORDER BY ace.[OrderId] ) as PreviousOrderId
,LAG(ace.[OrderStatus], 1) OVER ( PARTITION BY ace.[OrderId] ORDER BY ace.[EventDateTime] ) as PreviousOrderStatus
FROM Archive as ace
WHERE EXISTS
(SELECT * FROM
(
SELECT ROW_NUMBER() OVER (PARTITION BY OrderId ORDER BY EventDateTime) AS RowNumber
,ace.[OrderId]
,ace.[OrderHandler]
,ace.[EventDateTime]
,ace.[OrderStatus]
FROM Archive as ace
GROUP BY ace.[OrderId]
,ace.[OrderHandler]
,ace.[EventDateTime]
,ace.[OrderStatus]
HAVING ace.OrderHandler LIKE '%POOL%'
)x
WHERE ace.OrderId = x.OrderId)

Partition by without Re-ordering the data

My current data is as follows:
And I want Data to be
When I use the row_number function it is reordering itself and giving me the wrong row_number,as below
If we See "Adjusted conversion COst" value 0.160 is coming top of result and is numbered 1 which is wrong as per the first screenshot it should be numbered 3
Thanks
MYSQL Using Variable
Result - http://www.sqlfiddle.com/#!9/406f64/8/0
select
colo1,f7,
if(colo1='Total Adj. Conversion Spend',#initVal:=#initVal+1,1) as RowNumber
from temp,(select #initVal:=0) vars
MS-SQL Using Rank and Row Number
I've used Row_Number() to preserve the order and then using Rank() inside a case statement
http://www.sqlfiddle.com/#!18/fde9f/15/0
select subquery_1.colo1,subquery_1.f7
,case when subquery_1.colo1='Total Adj. Conversion Spend' then
rank() over (partition by colo1 order by rownum) else 1 end as rnk
from
(select *,row_number() OVER (ORDER BY (Select 0)) as rownum from temp) as subquery_1
order by subquery_1.rownum

Oracle LEAD - return next matching column value

I having below data in one table.
And I want to get NEXT out data from OUT column. So used LEAD function in below query.
SELECT ROW_NUMBER,TIMESTAMP,IN,OUT,LEAD(OUT) OVER (PARTITION BY NULL ORDER BY TIMESTAMP) AS NEXT_OUT
FROM MYTABLE;
It gives data as below NEXT_OUT column.
But I need to know the matching next column value in sequential way like DESIRED columns. Please let me know how can i achieve this in Oracle LEAD FUNCTION
THANKS
Assign row number to all INs and OUTs separately, sort the results by placing them in a single column and calculate LEADs:
WITH cte AS (
SELECT t.*
, CASE WHEN "IN" IS NOT NULL THEN COUNT("IN") OVER (ORDER BY "TIMESTAMP") END AS rn1
, CASE WHEN "OUT" IS NOT NULL THEN COUNT("OUT") OVER (ORDER BY "TIMESTAMP") END AS rn2
FROM t
)
SELECT cte.*
, LEAD("OUT") OVER (ORDER BY COALESCE(rn1, rn2), rn1 NULLS LAST) AS NEXT_OUT
FROM cte
ORDER BY COALESCE(rn1, rn2), rn1 NULLS LAST
Demo on db<>fiddle
Enumerate in the "in"s and the "out"s and use that information for matching.
select tin.*, tout.out as next_out
from (select t.*,
count(in) over (order by timestamp) as seqnum_in
from t
) tin left join
(select t.*,
count(out) over (order by timestamp) as seqnum_out
from t
) tout
on tin.in is not null and
tout.out is not null and
tin.seqnum_in = tout.seqnum_out;

Window functions assume null sorts low - expected behavior?

The following will not properly count nulls within a window...
select *,
sum(case when value is null then 1 else 0 end)
over(partition by id
order by coalesce(value,9999999)) as NumNulls,
row_number()
over(partition by id
order by coalesce(value,9999999)) as RN
from temp
Obviously, the problem can be solved using rows between unbounded preceding and unbounded following, so it's not a big deal. But, given my understanding of SQL, I would not have expected this result. Have I missed a finer point of the language, or is this unexpected behavior?
Here's a SQL Fiddle: http://sqlfiddle.com/#!6/98285/3
To reach your expected results you need to this
SELECT *
,SUM(CASE WHEN value IS NULL THEN 1 ELSE 0
END) OVER ( PARTITION BY id ORDER BY value ) AS NumNulls
,ROW_NUMBER() OVER ( PARTITION BY id ORDER BY value) AS RN
FROM #temp
because you used coalesce it could not partition properly this your count was off.