Order a column by pair of values - sql

I have 2 simple columns:
one column is simply an ID column and the other column is some sort of boolean type column.
ID V
0 1
1 0
2 0
3 1
4 1
5 0
I want to order the rows by pair of values (0,1) of column V
(while still keeping the ID as minimal as possible):
ID V
1 0
0 1
2 0
3 1
5 0
4 1
How do I do that ?

Seems you want get rows for 0 and 1 in turn:
select id, v
from tab
order by
row_number()
over (partition by v
order by id)
,v

Related

Number of Rows Between Polarity Changes SQL

I want to count the number of rows between polarity changes grouped by id in SQL. I'm thinking that there may be a clever way to use window functions to get the job done but I don't know what it is.
Consider data like this:
id
polarity
date
1
0
12/1
1
1
12/2
1
0
12/3
1
0
12/4
1
1
12/5
2
0
12/1
2
0
12/2
2
0
12/3
2
1
12/4
2
0
12/5
2
0
12/6
2
0
12/7
2
1
12/8
Is there a way to count the number of rows between each change in polarity to get something like this :
id
n
1
1
1
2
2
3
2
3
You can do:
select id, count(*) as n
from (
select *,
sum(i) over(partition by id order by date) as g
from (
select *, case when polarity <> lag(polarity)
over(partition by id order by date)
then 1 else 0 end as i
from t
) x
) y
group by id, g
having max(polarity) = 0

Creating duplicating rank over multiple columns

I have data as below where for one customer ID there are several orders (KEY) which is the primary key. I have also have a activity flag as below (either 0 or 1).
CUST_ID KEY FLAG
1 1 1
1 2 1
1 3 1
1 4 0
1 5 0
1 6 1
1 7 1
1 8 0
1 9 0
Now I want to create ranks as below based on the FLAG. The idea is to give same Rank as preceding row if the FLAG is same as preceding row. The Rank increments if the current value is different from preceding value.
CUST_ID KEY FLAG RN
1 1 1 1
1 2 1 1
1 3 1 1
1 4 0 2
1 5 0 2
1 6 1 3
1 7 1 3
1 8 0 4
1 9 0 4
I'm new to SQL, so please let me know if I need to reframe my question.
Use LAG() window function to get each row's previous flag and then use SUM() window function to create the rankings:
SELECT CUST_ID, KEY, FLAG,
SUM(CASE WHEN FLAG <> prev_FLAG THEN 1 END) OVER (PARTITION BY CUST_ID ORDER BY KEY) RN
FROM (
SELECT *, LAG(FLAG, 1, FLAG - 1) OVER (PARTITION BY CUST_ID ORDER BY KEY) prev_FLAG
FROM tablename
) t;
See the demo.
The code could be simplified, depending on the specific database that you use.

Identify a FK which has the highest value from a list of values in its source table

I have following tables.
Part
id
name
1
Part 1
2
Part 2
3
Part 3
Operation
id
name
part_id
order
1
Op 1
1
10
2
Op 2
1
20
3
Op 3
1
30
4
Op 1
2
10
5
Op 2
2
20
6
Op 1
3
10
Lot
id
part_id
Operation_id
10
1
2
11
2
5
12
3
6
I am selecting the results from Lot table and I want to select a column last_Op which is based on the order value of the operation_id. If value of order for the operation_id is the highest for the respective part_id, return 1 else return 0
SELECT
id,
part_id,
operation_id,
last_Op
FROM Lot
expected result set based on the tables above.
id
part_id
operation_id
last_op
10
1
2
0
11
2
5
1
12
3
6
1
In above example, first row returns last_op = 0 because operation_id = 2 is associated with part_id = 1 and it has the highest order = 30. Since operation_id for this part is not pointing towards the highest order value, 0 is returned.
The other two rows return 1 because operation_id 5 and 6 are associated with part_id 2 and 3 respectively and they are pointing towards the highest 'order' value.
If value of order for the operation_id is the highest for the respective part_id, return 1 else return 0
This sounds like window functions will help:
select l.*,
(case when o.order = o.max_order then 1 else 0 end) as last_op
from lot l left join
(select o.*,
max(o.order) over (partition by o.part_id) as max_order
from operations o
) o
on l.operation_id = o.id;
Note: order is a very poor name for a column because it is a SQL keyword.

oracle - no partition in window function but fill sequential numbers for acd properties

I have acd properties table with 3 columns - id, acd and rpt. The rpt is set to 1 when it is first reported for the acd property, but if any consequent acd properties are repeating, it is set to 0. The id column is always incrementing (sort of pk). Now for the continous zeros, I need the sequential numbers starting from 2,3... as shown in the wanted column.
id acd rpt wanted
1 a 1 1
2 b 1 1
3 b 0 2
4 a 1 1
5 a 0 2
6 a 0 3
7 d 1 1
8 d 0 2
9 d 0 3
10 c 1 1
11 c 0 2
12 c 0 3
13 c 0 4
14 c 0 5
15 d 1 1
16 a 1 1
I tried the window function, but when I use "value" column in partition clause it is grouping all a's which is not desired. Is it possible to get the results as in "wanted" column given rpt and id incrementing.
When rpt = 1, then you want 1. Then you want the 0s enumerated for each acd. If this is correct, then the logic is:
select t.*,
(case when rpt = 1 then 1
else 1 + row_number() over (partition by acd, rpt order by id)
end) as wanted
from t;
You need nested OLAP-funtions:
SELECT dt.*,
Row_Number() Over (PARTITION BY grp ORDER BY id)
FROM
( -- calculate a group number using a Cumulative Sum over 0/1 (for partitioning in next step)
SELECT prop.*, Sum(rpt) Over (ORDER BY id ROWS Unbounded Preceding) AS grp
FROM prop
) dt

What is the best way to initialize a SortOrder column (e.g. 0, 1, 2, 3) where there are multiple groups based on another field?

I have a table of list items. There is a ListID column used as an identifier to group the list items together. Is there a sane way to give every item a sort order, starting at 0 per list and incremental by one per item.
Basically, I need to populate the following SortOrder Column values for a large number of entries/ListIDs.
ID ListID SortOrder
1 1 0
2 0 0
3 1 1
4 0 1
5 1 2
6 0 2
7 2 0
8 2 1
9 2 2
You can use ROW_NUMBER() with a PARTITION on the ListId field for this:
Select Id, ListId,
Row_Number() Over (Partition By ListId Order By Id) -1 As SortOrder
From YourTable
Order By Id
I think you want:
WITH toupdate as (
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY ListId Order By id) as new_SortOrder
FROM tableName
)
UPDATE toupdate a
SET sortorder = new_sort_order;
SQL Server has the nice ability to update a subquery or CTE under some circumstances.
Do you need to persist the order of lists containing items that are shared between lists? If so, perhaps variations on this schema would work for you.
Item
id label
1 A
2 B
3 C
4 D
List
id listName
1 abc list
2 cbd list
3 aaa list
ListMembership
id listId itemId order
1 1 1 1
2 1 2 2
3 1 3 3
4 2 2 2
5 2 3 1
6 2 4 3
7 3 1 1
8 3 1 2
9 3 1 3
usage:
select i.label from listMembership as lm
join Item as i on i.id=lm.itemId
where lm.listId=2
order by lm.order
yields:
label
C
B
D