SQL update order in relation ship based on ID - sql

I wonder how to update order in this table for many-to-many relationship using SQL based on PostsId.
So my table now looks like:
I'm using SQL Server
BlogsId
PostsId
Order
1
1
1
0
2
2
1
0
3
3
2
0
3
4
2
0
3
5
3
0
3
6
3
0
but I want to update Order using SQL to this:
BlogsId
PostsId
Order
1
1
1
1
2
2
1
2
3
3
2
1
3
4
2
2
3
5
3
1
3
6
3
2
So for example: Blog with Id 3 is the first blog in Post with Id 2, Blog with Id 4 is the second Blog in Post with Id 2 and etc...
I've tried this:
DECLARE #myVar int
SET #myVar = 0
UPDATE [dbo].[BlogPost]
SET #myVar = [Order] = #myVar + 1
but then I got this:
BlogsId
PostsId
Order
1
1
1
1
2
2
1
2
3
3
2
3
3
4
2
4
3
5
3
5
3
6
3
6
So, I think I should do something in WHERE part (with Distinct maybe) but I don't know exactly what. I could write something in C# to do what I want but I don't know how to write something like this in SQL.

Physically maintaining an order or sequence of rows is rarely a good idea and can lead to data inconsistencies and other unforseen issues.
You would be better off creating a view that provides the additional Order column which you can do using row_number()
Create view BlogPosts as
select *,
Row_Number() over(partition by PostsId order by BlogsId) as [Order]
from blogpost;
If you really want to update an actual column in the table you could use a CTE
with b as (
select *,
Row_Number() over(partition by PostsId order by BlogsId) as seq
from blogpost
)
update b
set [Order] = seq;

You can update from a calculated row_number.
update t
set [Order] = rn
from (
select BlogsId, PostsId, [Order]
, rn = row_number() over (partition by PostsId order by BlogsId asc)
from BlogPost
) t
where ([Order] is null or [Order]!=rn);
select *
from BlogPost
order by BlogsId, PostsId
BlogsId
PostsId
Order
1
1
1
2
1
2
3
2
1
4
2
2
5
3
1
6
3
2
Demo on db<>fiddle here

Related

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

Updating column based on another column's value

How do i update table structured like this:
id[pkey] | parent_id | position
1 1
2 1
3 1
4 1
5 1
6 2
7 2
8 2
9 2
10 3
11 3
12 3
...and so on
to achieve this result:
id[pkey] | parent_id | position
1 1 1
2 1 2
3 1 3
4 1 4
5 1 5
6 2 1
7 2 2
8 2 3
9 2 4
10 3 1
11 3 2
12 3 3
...and so on
I was thinking about somehow mixing
SELECT DISTINCT parent_id FROM cats AS t;
with
CREATE SEQUENCE dpos;
UPDATE cats t1 SET position = nextval('dpos') WHERE t.parent_id = t1.parent_id;
DROP SEQUENCE dpos;
although im not really experienced with postgres, and not sure how to use some kind of FOREACH. I appreciate any help
You can get the incremental number using row_number(). The question is how to assign it to a particular row. Here is one method using a join:
update cats
set position = c2.newpos
from (select c2.*, c2.ctid as c_ctid,
row_number() over (partition by c2.parent_id order by NULL) as seqnum
from cats c2
) c2
where cats.parent_id = c2.parent_id and cats.ctid = c2.c_ctid;
Use row_number function
select parent_id,
row_number() over (partition by parent_id order by parent_id) as position_id from table
Try this:
UPDATE table_name set table_name.dataID = v_table_name.rn
FROM
(
SELECT row_number() over (partition by your_primaryKey order by your_primaryKey) AS rn, id
FROM table_name
) AS v_table_name
WHERE v_table_name.your_primaryKey = v_table_name.your_primaryKey;

SQL query to take top elements of ordered list on Apache Hive

I have the table below in an SQL database.
user rating
1 10
1 7
1 6
1 2
2 8
2 3
2 2
2 2
I would like to keep only the best two ratings by user to get:
user rating
1 10
1 7
2 8
2 3
What would be the SQL query to do that? I am not sure how to do it.
It will work
;with cte as
(select user,rating, row_number() over (partition by user order by rating desc) maxval
from yourtable)
select user,rating
from cte
where maxval in (1,2)

Count occurrences of field values as they are displayed in order

thanks in advance for the help and sorry for how the "table" looks. Here's my question...
Let's say I have a subquery with this table (imagine the bold as column headers) as its output -
id 1 1 2 3 3 3 3 4 5 6 6 6
action o c o c c o c o o c c c
I would like my new query to output -
id 1 1 2 3 3 3 3 4 5 6 6 6
action o c o c c o c o o c c c
ct 1 2 1 1 2 3 4 1 1 1 2 3
#c 0 1 0 1 2 2 3 0 0 1 2 3
#o 1 1 1 0 0 1 1 1 1 0 0 0
where ct stands for count. Basically, I want to count (for each id) the occurrences of consecutive id and action as they happen. Let me know if this makes sense, and if not, how I can clarify my question.
Note: I realize the lag/lead functions may be helpful in this situation, along with the row_number() function. Looking for as many creative solutions as possible!
You are looking for the row_number() analytic function:
select id, action, row_number() over (partition by id order by id) as ct
from table t;
For #c and #o, you want cumulative sum:
select id, action, row_number() over (partition by id order by id) as ct,
sum(case when action = 'c' then 1 else 0 end) over
(partition by id order by <some column here>) as "#c",
sum(case when action = 'c' then 1 else 0 end) over
(partition by id order by <some column here>) as "#o"
from table t;
The one caveat is that you need a way to specify the order of the rows -- an id or date time stamp or something. SQL result sets and tables are inherently unordered, so there is no idea that one row comes before or after another.
SQL> select id, action,
2 row_number() over(partition by id order by rowid) ct,
3 sum(decode(action,'c',1,0)) over(partition by id order by rowid) c#,
4 sum(decode(action,'o',1,0)) over(partition by id order by rowid) o#
5 from t1
6 /
ID A CT C# O#
---------- - ---------- ---------- ----------
1 o 1 0 1
1 c 2 1 1
2 o 1 0 1
3 c 1 1 0
3 c 2 2 0
3 o 3 2 1
3 c 4 3 1
4 o 1 0 1
5 o 1 0 1
6 c 1 1 0
6 c 2 2 0
6 c 3 3 0
P.S. Sorry Gordon, didn't see your post.

How to select a random row when 2 rows have an equal property

I have a table containing items in a priority order as such:
id priority
1 1
2 2
3 3
4 8
5 3
6 4
Currently I retrieve items (SQL Server) in priority order, although a random item when there are matching priorities using the following query:
select item
from table
order by priority, newid()
This will return
id priority
1 1
2 2
3 3
5 3
6 4
4 8
or
id priority
1 1
2 2
5 3
3 3
6 4
4 8
So it's approximately 50/50 traffic
I now have a requirement to only retrieve one row of the rows when there are two matching priorities, for example..
id priority
1 1
2 2
3 3
6 4
4 8
or
id priority
1 1
2 2
5 3
6 4
4 8
You can use ROW_NUMBER, presuming SQL-Server (because of NEWID):
WITH CTE AS
(
SELECT t.*, RN = ROW_NUMBER() OVER (PARTITION BY Priority
ORDER BY ID)
FROM dbo.table t
)
SELECT * FROM CTE WHERE RN = 1
If these are all columns you could also use this sql:
SELECT MIN(t.ID) AS ID, t.Priority
FROM dbo.table t
GROUP BY t.priority
Update "No, I need to be able to get a random row when two (or more) priorities match"
Then i have misunderstood your requirement. You can use ORDER BY NEWID:
WITH CTE AS
(
SELECT t.*, RN = ROW_NUMBER() OVER (PARTITION BY Priority
ORDER BY NEWID())
FROM dbo.table t
)
SELECT * FROM CTE WHERE RN = 1