Partition by without Re-ordering the data - sql

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

Related

Row_number skip values

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

SQL Server : using CTE row partition to serialize sequential timestamps

I think I just need a little help with this but is there a way to incrementally count steps in SQL using some type of CTE row partition? I'm using SQL Server 2008 so won't be able to use the LAG function.
In the below, I am trying to find a way to calculate the Step Number as pictured below where for each unique ITEM in my table, in this case G43251, it calculates the process Step_Number based on the Date (timestamp) and the process type. For those with the same timestamp & process_type, it would label them both as the same Step_Number as there other fields that could cause the timestamp to repeat twice.
Right now I am playing around with this below and seeing how maybe I could fit in a DISTINCT timestamp methodology ? So that it doesn't count each row as something new.
WITH cte AS
(
SELECT
*,
ROW_NUMBER() OVER (ORDER BY Timestamp_Posted DESC)
- ROW_NUMBER() OVER (PARTITION BY Item ORDER BY Timestamp_Posted Desc) rn
FROM
#t1
)
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY Item, rn ORDER BY Timestamp_Posted DESC) rn2
FROM
cte
ORDER BY
Timestamp_Posted DESC
Please use dense_rank() instead of row_number()
SELECT *, dense_rank() OVER(Partition By Item ORDER BY Timestamp_Posted, Process_Type ) Step_Number
FROM #t1
ORDER BY Timestamp_Posted DESC

SQL - How to sort values in special order?

For example, I have a table ordered by column "code". Also, I now exact number of rows of my table (6 for this case).
I need to create one more column with rank using next rules:
The first value has the first code (1)
The second value has the last code (6)
The third value has the second code (2)
The forth value has penultimate code (5) etc.
How can I create this order? Even if you have just an idea without query, share it with me, please.
You could use:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER(ORDER BY code ASC) rn1,
ROW_NUMBER() OVER(ORDER BY code DESC) rn2
FROM tab
)
SELECT *
FROM cte
ORDER BY ABS(rn2 - rn1) DESC, code;
db<>fiddle demo
How it works: two counters based on code, calculate difference so first and last has the same value, when tie prefer code.
I would use row_number() too, but I think the logic you want is more:
select *
from (
select t.*,
row_number() over(order by code asc ) rn_asc,
row_number() over(order by code desc) rn_desc
from tab t
) t
order by case when rn_asc <= rn_desc then rn_asc else rn_desc end, rn_asc;
This ranks records in both directions, and then uses the smallest of the two ranks for ordering. The second sorting criteria ensures that the smallest value of the two consistently comes first.

Can Db2 LAG function refer to itself?

I'm trying to put information to identify GROUP ID by replicating this Excel formula:
IF(OR(A2<>A1,AND(B2<>"000",B1="000")),D1+1,D1)
This formula is written when my cursor is in "D2", meaning I've referred to the newly added column value in the previous row to generate the current value.
I'd like to this with Db2 SQL, but I'm not sure how to because I'll need to do LAG function on the column I'm going to add and referring their value.
Kindly advise if having better way to do.
Thanks.
You need nested OLAP-functions, assuming ORDER BY SERIAL_NUMBER, EVENT_TIMESTAMP returns the order shown in Excel:
with cte as
(
select ...
case --IF(OR(A2<>A1,AND(B2<>"000",B1="000"))
when (lag(OPERATION)
over (order by SERIAL_NUMBER, EVENT_TIMESTAMP) = '000'
and OPERATION <> '000')
or lag(SERIAL_NUMBER,1,'')
over (order by SERIAL_NUMBER, EVENT_TIMESTAMP) <> SERIAL_NUMBER
then 1
else 0
end as flag -- start of new group
from tab
)
select ...
sum(flag)
over (order by SERIAL_NUMBER, EVENT_TIMESTAMP
rows unbounded preceding) as GROUP_ID
from cte
Your code is counting the number of "breaks" in your data, where a "break" is defined as 000 or the value in the first column changing.
In SQL, you can do this as a cumulative sum:
select t.*,
sum(case when prev_serial_number = serial_number or operation <> '000'
then 0 else 1
end) over (order by event_timestamp rows between unbounded preceding and current row) as column_d
from (select t.*,
lag(serial_number) over (order by event_timestamp) as prev_serial_number
from t
) t

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;