Change order whilst keeping ID field unchanged - vb.net

i am struggling to find a solution for following. It is hard to find a title for it by the way :)
I am making a tool where i want to track subscriptions to an event. For managing that I have a table with x (25+) number of positions to be filled.
This tool is in VB.net with an underlying MSSQL Database
That Position will be assigend with a 'userid' and some attributes as 'getradio1' , 'getsradio2' etc.
All of that is easy. So you will get something like this in the 'position' table.
Now it comes - and the questions is twofold : Can it be done and if yes how ?
Every UserID has a kind of priority ranking (in the UserID Database)
Now what i want to is to have the position filled in by order of that ranking . Lets assume that the ranking is as follows
UserID101 = Ranking 14
UserID103 = Ranking 5
UserID106 = Ranking 11
UserID102 = Ranking 39
UserID118 = Ranking 1
UserID114 = Ranking 6
Then i want the table updated so that the position is 'reassigned' according to rank as follows (also including the 'getradio' colums
Ideally would be that if a new PositionID was assigned it would automatically do the 'reordering'.
I tried to descridbe the problem as simple and complete as possible. But if you have more question donot hesitate.
Thanks already for your help

Related

Maintaining auto ranking as a column in MongoDB

I am using MongoDB as my database.
I have data which contains rank and name as columns. Now a new row can be updated with a rank different from ranks already existing or can be same.
If same then the ranks of other rows must be adjusted .
Rows having lesser rank than the to be inserted one must be incremented by one and the rows which are having ranks can remain as it it.
Feature is something like number bulleted list in MS Word type of applications. Where inserting a row in between adjust the numbering of other rows below it.
Rank 1 is the highest rank.
For e.g. there are 3 rows
Name Rank
A 1
B 2
C 3
Now i want to update a row with D as name and 2 as rank. So now after the row insert, the DB should like below
Name Rank
A 1
B 3
C 4
D 2
Probably using Database triggers i can achieve this by updating the other rows.
I have couple of questions
(a) Is there any other better way than using database trigger for achieving this kind of scenario ? Updating all the rows might be a time consuming job.
(b) Does MongoDB support database trigger natively ?
Best Regards,
Saurav
No, MongoDB, does not provide triggers (yet). Also I don't think trigger is really a great way to achieve this.
So I would just like to throw some ideas, see if it makes sense.
Approach 1
Maybe instead of disturbing those many documents, you can create a collection with only one document (Let's call the collection ranking). In that document, have an array field call ranks. Since it's an array it's already maintaining a sequence.
{
_id : "RANK",
"ranks" : ["A","B","C"]
}
Now if you want to add D to this rank at 2nd position
db.ranking.update({_id:"RANK"},{$push : {"ranks":{$each : ["D"],$position:1}}});
it would add D to index 1 which is 2nd position considering index starts at 0.
{
_id : "RANK",
"ranks" : ["A","D","B","C"]
}
But there is a catch, what if you want to change C position to 1st from 4th, you need to remove it from end and put it in the beginning, I am sure both operation can't be achieved in single update (didn't dig in the options much), so we can run two queries
db.ranking.update({_id:"RANK"},{$pull : {"ranks": "C"}});
db.ranking.update({_id:"RANK"},{$push : {"ranks":{$each : ["C"],$position:0}}});
Then it would be like
{
_id : "RANK",
"ranks" : ["C","A","D","B"]
}
maintaining the rest of sequence.
Now you would probably want to store id instead of A,B,C etc. one document can be 16MB so basically this ranks array can store more than 1.3 million entries of id, if id is MongoDB ObjectId of 12 bytes each. if that is not enough, we still have option to have followup document(s) with further ranking.
Approach 2
you can also, instead of having rank as number, just have two field like followedBy and precededBy.
so your user document would look
{
_id:"A"
"followedBy":"B",
}
{
_id:"B"
"followedBy":"C",
"precededBy":"A"
}
{
_id:"c"
"precededBy":"B",
}
if you want to add D at second position, then you need to change the current 2nd position and you need to insert the new One, so it would be change in only two document
{
_id:"A"
"followedBy":"B",
}
{
_id:"B"
"followedBy":"C",
"precededBy":"D" //changed from A to D
}
{
_id:"c"
"precededBy":"B",
}
{
_id:"D"
"followedBy":"B",
"precededBy":"A"
}
The downside of this approach is that you cannot sort in query based on the ranking until and unless you get all these in application and create a linkedlist sort of structure.
This approach just preserve the ranking with minimum DB changes.

Trying to include ID column in Grouped SQL SELECT statement in order to drill down in web page

I know there has been a lot of discussion around this subject but I cannot find anything that points me in the direction of a definitive answer.
I have the below sql statement within a .net page in Webmatrix:
SELECT vehicle, vehicleDescription, count(vehicleDescription) AS 'Total'
FROM vehicles
WHERE (branchRequirement = 'Manchester')
AND (deliveryBranch = 'Manchester' OR deliveryBranch IS NULL)
AND (dateDeliveredToBranch > GETDATE() OR dateDeliveredToBranch IS NULL)
AND (vgc LIKE 'B_') GROUP BY vehicle,vehicleDescription
The output is obviously GROUPED data for the chosen conditions.
What I am trying to do is provide a link in my Webgrid on the .net page which allows the user to open a child page with details of the GROUPED vehicles.
Where I'm getting stuck is I cannot include the vehicleID in the GROUP BY because they are obviously all UNIQUE.
Has anybody come across this or something similar with any degree of success as I am pulling my hair out with it which I can ill afford to do!
Thanks
M
I have come across similar issues and the solution I came up with was to use the information you already have. When the user clicks on the link, you know the vehicle and the vehicleDescription that the user wants to see. You should not need the vehicleId because you are not going to have one unique result. If they click on a vehicle that has a count of 3, the child page should have details about all 3 results.
In order to find the 3 results the user would want to see, you can alter your existing query and use it for the child page. The altered query should take the vehicle and vehicleDesciption as parameters.
SELECT *
FROM vehicles
WHERE (branchRequirement = 'Manchester')
AND (deliveryBranch = 'Manchester' OR deliveryBranch IS NULL)
AND (dateDeliveredToBranch > GETDATE() OR dateDeliveredToBranch IS NULL)
AND (vgc LIKE 'B_')
AND vehicle = #vehicle
AND vehicleDesciption = #vehicleDescription
Pass the parameters in .Net and you should end up with the same data that you summed in your last query, since this query is essentially the same.

Remove the dynamically generated blank columns from rdl

I have a SQL server result set which I need to display using SSRS rdl.
The result set id like:
SpeakerId Product Topic
16 a A
16 a B
16 b C
16 a D
17 b B
17 c C
17 c E
18 a B
18 c A
19 c C
I need to display this information in different tabs in excel based on Products.
Each speaker will have a only one row and the topics will be displayed in different coulmns based on alphabetical order.
When I tried to implement this dynamic pages and columns in rdl, I am facing following issue:
I am getting blank columns for the topics, if the product and the speaker in that tab is not having the topic which other Product and speaker(in other tabs) have.
Please suggest any way to resolve this.
I tried to use Rank but the concept does not helps in this case as we have multiple pages in the excel.
Thank You.
In this sort of situation, you need to make sure that all required topics are returned for all speakers so that SSRS knows to display the topics.
One way of doing this is with a PIVOT query, something like:
select SpeakerId
, [A],[B],[C],[D],[E]
from ResultSet
pivot
(
max(Product)
for Topic in ([A],[B],[C],[D],[E])
) p
SQL Fiddle with demo.
You can see here that each speaker has a column for each Topic in the result.
This means that in the report, you can use a Table instead of a Matrix to display the data.
Unknown number of Topics?
You may still run into issues if you don't know the required Topics before writing the report query - in this case I would suggest making sure that you include an OUTER JOIN to the Topic table.
This depends on your data, obviously. But this is useful as it means that each Speaker will have a row for each Topic, which is what you require... Here you would use a Matrix to display results in the report.
Whatever approach you use, the goal is to get a DataSet to SSRS that includes every possible Speaker/Topic combination, even if the actual value for the Topic is NULL, so the report always displays the same Topic columns for each Speaker.

How Do I Get Total 1 Time for Multiple Rows

I've been asked to modify a report (which unfortunately was written horribly!! not by me!) to include a count of days. Please note the "Days" is not calculated using "StartDate" & "EndDate" below. The problem is, there are multiple rows per record (users want to see the detail for start & enddate), so my total for "Days" are counting for each row. How can I get the total 1 time without the total in column repeating?
This is what the data looks like right now:
ID Description startdate enddate Days
REA145681 Emergency 11/17/2011 11/19/2011 49
REA145681 Emergency 12/6/2011 12/9/2011 49
REA145681 Emergency 12/10/2011 12/14/2011 49
REA146425 Emergency 11/23/2011 12/8/2011 54
REA146425 Emergency 12/9/2011 12/12/2011 54
I need this:
ID Description startdate enddate Days
REA145681 Emergency 11/17/2011 11/19/2011 49
REA145681 Emergency 12/6/2011 12/9/2011
REA145681 Emergency 12/10/2011 12/14/2011
REA146425 Emergency 11/23/2011 12/8/2011 54
REA146425 Emergency 12/9/2011 12/12/2011
Help please. This is how the users want to see the data.
Thanks in advance!
Liz
--- Here is the query simplified:
select id
,description
,startdate -- users want to see all start dates and enddates
,enddate
,days = datediff(d,Isnull(actualstardate,anticipatedstartdate) ,actualenddate)
from table
As you didn't provide the data of your tables I'll operate over your result as if it was a table. This will result in what you're looking for:
select *,
case row_number() over (partition by id order by id)
when 1 then days
end
from t
Edit:
Looks like you DID added some SQL code. This should be what you're looking for:
select *,
case row_number() over (partition by id order by id)
when 1 then
datediff(d,Isnull(actualstardate,anticipatedstartdate) ,actualenddate)
end
from t
That is a task for the reporting tool. You will have to write something like he next code in teh Display Properties of the Days field:
if RowNumber > 1 AND id = previous_row(id)
then -- hide the value of Days
Colour = BackgroundColour
Days = NULL
Days = ' '
Display = false
... (anything that works)
So they want the output to be exactly the same except that they don't want to see the days listed multiple times for each ID value? And they're quite happy to see the ID and Description repeatedly but the Days value annoys them?
That's not really an SQL question. SQL is about which rows, columns and derived values are supposed to be presented in what order and that part seems to be working fine.
Suppressing the redundant occurrences of the Days value is more a matter of using the right tool. I'm not up on the current tools but the last time I was, QMF was very good for this kind of thing. If a column was the basis for a control break, you could, in effect, select an option for that column that told it not to repeat the value of the control break repeatedly. That way, you could keep it from repeating ID, Description AND Days if that's what you wanted. But I don't know if people are still using QMF and I have no idea if you are. And unless the price has come way down, you don't want to go out and buy QMF just to suppress those redundant values.
Other tools might do the same kind of thing but I can't tell you which ones. Perhaps the tool you are using to do your reporting - Crystal Reports or whatever - has that feature. Or not. I think it was called Outlining in QMF but it may have a different name in your tool.
Now, if this report is being generated by an application program, that is a different kettle of Fish. An application could handle that quite nicely. But most people use end-user reporting tools to do this kind of thing to avoid the greater cost involved in writing programs.
We might be able to help further if you specify what tool you are using to generate this report.

Dynamic user ranks

I have a basic karma/rep system that awards users based on their activities (questions, answers, etc..). I want to have user ranks (title) based on their points. Different ranks have different limitations and grant powers.
ranks table
id rankname points questions_per_day
1 beginner 150 10
2 advanced 300 30
I'm not sure if I need to have a lower and upper limit, but for the sake of simplicity I have only left a max points limit, that is, a user below 150 is a 'beginner' and below or higher than 300, he's an 'advanced'.
For example, Bob with 157 points would have an 'advanced' tag displayed by his username.
How can I determine and display the rank/title of an user? Do I loop through each row and compare values?
What problems might arise if I scale this to thousands of users having their rank calculated this way? Surely it will tax the system to query and loop each time a user's rank is requested, no?
You could better cache the rank and the score. If a user's score only changes when they do certain activities, you can put a trigger on that activity. When the score changes, you can recalculate the rank and save it in the users record. That way, retreiving the rank is trivial, you only need to calculate it when the score changes.
You can get the matching rank id like this; query the rank that is closest (but below or equal to) the user schore. Store this rank id in the user's record.
I added the pseudovariable {USERSCORE} because I don't know if you use parameters or any other way to enter values in a query.
select r.id
from ranks r
where r.points <= {USERSCORE}
order by r.points desc
limit 1
A little difficult without knowing your schema. Try:
SELECT user.id, MIN(ranks.id) AS rankid FROM user JOIN ranks ON (user.score <= ranks.points) GROUP BY user.id;
Now you know the ranks id.
This is non-trivial though (GROUP BY and MAX are pipeline breakers and so quite heavyweight operations), so GolezTrol advice is good; you should cache this information and update it only when a users score changes. A trigger sounds fine for this.