Keep the order of current and future posts - database

One of my curiosities these days is how to order some posts. I will give you a clear example, maybe one the majority of you experimented in the past.
The Facebook Timeline, which you can add posts and events to, at any point in time you want. In this case, I assume, the posts are ordered by the date. When you add a new status for the past, you have to assign it a date, so it is easy to get them in order.
What I want to do is to have posts and the option to add a new post after a specific one. I don't have the option to add a date to it but I have to have a way to get them in that order.
So, if every post has an id and a date (the creation date). If a new post is added between 2 posts, I can't increment all the ids of the "upper" posts, so that I can order by the id. Neither is the date, because I can add a post between two older posts in the future.
What solution do you imagine for this? What criteria should I order by (I am ready to make some database scheme changes if needed)?

OK, there's another possible solution. Use two columns for ordering: Order1 is basic order, and Order2 is order within group defined by Order1. You assign your posts to some arbitrary groups (i.e. all posts from single day or every 100 posts) by setting Order1. Within each group posts are ordered according to value in Order2.
If a new post must be inserted into some group you only need to renumber Order2 values for posts in this particular group - not all posts in table.
Of course when retrieving the rows you order by Order1, Order2.
So your table looks like this:
PostName Order1 Order2
------------------------
A 1 1
B 1 2
C 1 3
D 1 4
E 2 1
F 2 2
G 2 3
Now if you want to insert X between F and G you renumber only items in group Order1 = 2, so that rows become:
PostName Order1 Order2
------------------------
A 1 1
B 1 2
C 1 3
D 1 4
E 2 1
F 2 2
G 2 4
X 2 3
Now, if you want to insert Z between A and B you only renumber Order2 in posts in group Order1 = 1:
PostName Order1 Order2
------------------------
A 1 1
B 1 3
C 1 4
D 1 5
E 2 1
F 2 2
G 2 4
X 2 3
Z 1 2

IF you're not going order by a criteria (Date, for example), you will need something to order them. Not necessary have to use column Id to order, you could add a column that is not the PK, and makes the function of ordinalPosition.
So, when you insert at the end, you will get the max ordinalPosition, and then do ordinalPosition+1.
If you want to insert between two of those, then you look the ordinal position of the two post you have (to insert between them), update incrementing in 1 all ordinalColumns, from the major of those two post, and then (now you got a "hole" in the ordinalPosition), insert the new ordinalPosition, and that will be the the minor of those two post + 1 (which equally the mayor of those two post)
Then, you will get the posts ordered by your ordinalPosition:
Select fields from Posts
-- where your criteria goes here
order by ordinalPosition
Maybe you consider that's not a good way, because everytime you insert a post between two another one, you will have to do an update - but the Db is not magic, has to order by some criteria. And have to make sure there is no posts with same order id, so probably will have to add some Unique Constraint or something as you want.
You're not gonna update very old posts probably, so I don't think will be so much update's everytime you add a posts between other two.

Related

Change formula array for every X number of rows in Excel

I have large number of rows of data in Excel where I need to change the row array of the formula for every 3 rows but I can't figure out how to adjust the formula without an error.
How do I add a formula like this to the formula below?
=INT(((ROW(a1)-1)/11))*1+1
This is the formula I have been using, but I need to change it for every 3 rows.
=IF(COUNTIF($N$4:$N$6, ""), "",MAX($N$4:$N$6))
=IF(COUNTIF($N$7:$N$9, ""), "",MAX($N$7:$N$9))
And so on
Example
I have 3 approvers, if "product" is approved, the date is for the approval date of last said approval, if no approval has been made then the cell is blank. Outcome is what I want to collect from column 3 when product was approved from all 3 approvers which is the newest date of the 3 rows, if one approver has not approved, then I'd like column 4 to be blank.
Product
Approvers
Dates
Outcome
A
1
04.01.2016
04.01.2016
A
2
17.12.2015
04.01.2016
A
3
21.12.2015
04.01.2016
B
1
11.04.2017
11.04.2017
B
2
30.01.2017
11.04.2017
B
3
04.04.2017
11.04.2017
C
1
C
2
13.10.2016
C
3
14.02.2017
D
1
01.03.2022
01.03.2022
D
2
02.12.2019
01.03.2022
D
3
30.01.2020
01.03.2022
Picture of data
Two options:
To answer the original question, to make your formula change every n rows, use =-MOD(ROW()+c, n) to adjust this (where 'c' is a constant just to get them in line, if your data starts on row 2 then c would be 1).
Your formula for row 2 would be:
=IF(COUNTIF(OFFSET($N2,-MOD(ROW($N2)+1,3),0,3),""),"",MAX(OFFSET($N2,-MOD(ROW($N2)+1,3),0,3)))
Another option, not as direct an answer to the question but potentially useful if the number of products changed in future from 3 to something else, would be:
=IF(COUNTIFS(L:L, L2, N:N, ""), "", MAX(IF(L:L=L2, L:L)))
and click Ctrl+Shift+Enter after typing that in (because it's an Array formula, see here, here and here).
The advantage of this approach is that it looks at all rows where the product column is the same (I'm assuming unique products), so no need to limit it to 3 rows per product or have those 3 rows next to each other.

How to model arbitrarily ordering items in database?

I accepted a new feature to re-order some items by using Drag-and-Drop UI and save the preference for each user to the database. What's the best way to do so?
After reading some questions on StackOverflow, I found this solution.
Solution 1: Use decimal numbers to indicate order
For example,
id item order
1 a 1
2 b 2
3 c 3
4 d 4
If I insert item 4 between item 1 and 2, the order becomes,
id item order
1 a 1
4 d 1.5
2 b 2
3 c 3
In this way, every new order = order[i-1] + order[i+1] / 2
If I need to save the preference for every user, then I need to another relationship table like this,
user_id item_id order
1 1 1
1 2 2
1 3 3
1 4 1.5
I need num_of_users * num_of_items records to save this preference.
However, there's a solution I can think of.
Solution 2: Save the order preference in a column in the User table
This is straightforward by adding a column in the User table to record the order. Each value would be parsed as an array of item_ids that ranked by the index of the array.
user_id . item_order
1 [1,4,2,3]
2 [1,2,3,4]
Is there any limitation of this solution? Or is there any other ways to solve this problem?
Usually, an explicit ordering deals with the presentation or some specific processing of data. Hence, it's a good idea to separate entities of theirs presentation/processing. For example
users
-----
user_id (PK)
user_login
...
user_lists
----------
list_id, user_id (PK)
item_index
item_index can be a simply integer value :
ordered continuously (1,2...N): DELETE/INSERT of the whole list are normally required to change the order
ordered discretely with some seed (10,20...N): you can insert new items without reordering the whole list
Another reason to separate entity data and lists: reordering lists should be done in transaction that may lead to row/table locks. In case of separated tables only data in list table is impacted.

Select Row values based on values in another row

I have a table that has an auto-incrementing identity "Reference" field and a pair of other fields that determine the sort order. What I need to do is find the 'next' item in the table when sorted based on the pair of fields based on the reference field of an initial item.
So my data looks like this when sorted by SortParent.SortChild:
Reference SortParent SortChild Data
------------------------------------------
9 1 2 Fred
7 1 3 Jim
11 1 4 Sheila
4 2 1 Micro
5 2 2 Archimedes
12 2 3 Electron
So in this example the "Jim" row (Reference=7) comes after "Fred" (Reference=9) even though it's reference is smaller.
So i want to be able to find which row comes after Fred by searching based on Jim's reference
At the moment in code I do a query to find the values for Fred's row:
SELECT SortParent,SortChild From MyTable WHERE Reference=9
Which returns 1,2. Then do a search for the first row that comes after 1,2:
SELECT * FROM MyTable
WHERE ((SortParent=1 and SortChild>2) OR (SortParent>2))
ORDER BY SortParent,SortChild
Which will therefore come back with the row having reference 7 and sort values 1,3
I'm pretty sure this can be done in a single query, but i'm stumped on the best way.
Incidentally, if anyone has any suggestions on alternate way of handling the two part sort columns that would make this easier, please feel free to help!
I believe You are looking at the LEAD or LAG windowed function:
https://msdn.microsoft.com/en-US/library/hh213125.aspx
SELECT
NextReference
FROM
(SELECT
reference
, LEAD(reference, 1,0) OVER (ORDER BY SortParent,SortChild) AS NextReference
, *
FROM
mytable
) newTable
WHERE
reference = 9
I used LEAD, but try it with LAG if you are looking in the other direction for the row
I havn't tested this particular query, so my not be syntactically sound, but let me know if you have any troubles with it and I'll go over it a bit more once I'm back at my desk
EDIT: Used the wrong sql from your question as my base
EDIT2: Put the lead into a subquery to allow us to query on it

How do I have a Row Group "under" a Column Group in SSRS?

I have some data that relates to some production inputs and outputs.
What I want to do is, for each production run, show what went in and what came out.
I have, at this point, something that looks like this:
Run# Item Input Output
1 X 1
Y 1
2 A 2
B 3 2
C 3
Where Input/Output is derived from a 'direction' column group, and there are row groups on Run# and Item.
What I want is something like this:
Run# Item Input Item Output
1 X 1 Y 1
2 A 2 B 2
B 3 C 3
Is this even possible? I feel like it should be, but as you can probably see from the title, I don't even know what to begin searching.
The way to do this is to add a rank() over the query like so:
dense_rank() OVER (Run#, Direction Order By ItemCode) as rank
You can then perform a row grouping by the rank field (you don't have to display the column), and add ItemCode as a column in the column grouping.

yet another tsql question

i have three tables
documents
attributes
attributevalues
documents can have many attributes
and these atributes have value in attributevalue table
what i want in single query get all documents and assigned atributes of relevant documents in row each row
(i assume every documents have same attributes assigned dont need complexity of diffrent attribues now)
for example
docid attvalue1 attvalue2
1 2 2
2 2 2
3 1 1
how can i do that in single query
Off the top if my head, I don't think you can do this without dynamic SQL.
The crux of the Entity-Attribute-Value (EAV) technique (which is what you are using) is to store columns as rows. What you want to do is convert those rows back to columns for the purpose of this query. Using PIVOT makes this possible. However, PIVOT requires knowing the number of rows that need to be converted to columns at the time the query is written. So assuming you are using EAV because you need flexible attributes/values, you won't know this information when you write the query.
So the solution would be to use dynamic SQL in conjunction with PIVOT. Did a quick search and this looks promising (didn't really read the whole thing):
http://www.simple-talk.com/community/blogs/andras/archive/2007/09/14/37265.aspx
For the record, I am not a fan of dynamic SQL and would recommend finding another approach to the larger problem (e.g. pivoting in application code).
If you know all the attributes (and their IDs) at design-time:
SELECT d.docid,
a1.attvalue AS attvalue1
a2.attvalue AS attvalue2
FROM documents d
JOIN attributevalues a1 ON d.docid = a1.docid
JOIN attributevalues a2 ON d.docid = a2.docid
WHERE a1.attrid = 1
AND a2.attrid = 2
If you don't, things get quite a bit messier and difficult to answer without knowing your schema.
lets make example
documents table's columns
docid,docname,createddate,createduser
and values
1 account.doc 10.10.2010 aeon
2 hr.doc 10.11.2010 aeon
atributes table's columns
attid,name,type
and values
1 subject string
2 recursive int
attributevalues table's columns
attvalueid,docid,attid,attvalue(sql_variant)
and values
1 1 1 "accounting doc"
1 1 2 0
1 2 1 "humen r doc"
1 2 2 1
and I want query result
docid,name,atribvalue1,atribvalue1,atribvalueN
1 account.doc "accounting doc" 0
2 hr.doc "humen r doc" 1

Resources