Change Y-axis label VB:net - vb.net

I have a program that renders a chart that calculates the time of a work day.
It shows only 3 days ahead, and shows the numbers in percent.
Some thing like this:
400-|-----------------------------------
|
300-|-----------------------------------
| | 55% |
200-|-----------------------------------
| | 100% | | 98% |
100-|-----------------------------------
| | 100% | | 100% |
0---|-----------------------------------
| STATION 1 STATION 2
This data tells me that station 1 has 100% to do day 1 & 2 and only 55% of work 3 days from now. What i would like to change here, is just the Y-axis labels to "Day" with numbers. Something like this:
Day 4-|-----------------------------------
|
Day 3-|-----------------------------------
| | 55% |
Day 2-|-----------------------------------
| | 100% | | 98% |
Day 1-|-----------------------------------
| | 100% | | 100% |
----0-|-----------------------------------
| STATION 1 STATION 2
How can i do this? I guess something like
For Each YAxis in TheChart
YAxis.Label = "Day " & YAxis.Label / 100
End For
How do i do this more specific, or is there any other way?
Thanx in advance

Well im thinking you are using text. To do this you would first declare a variable called C1:
Dim C1 = [label that contains the number]/100.
repeate this with c2 c3 and c4.
Use the variables in the labels.
I did not really understand your question. So i may be way off as to what you're asking.

Related

Database design for partially changing data points, with history and snapshot functionality?

I'm looking for a best practice or solution, on a conceptual level, to a problem I'm working on.
I have a collection of data points (around 500) which are partially changed, by a user, over time. It is important to able to tell, which values have been changed at what point in time. The data might look like this:
Data changed over time:
+--------------------------------------------------------------------------------------+
| Date | Value no. 1 | Value no. 2 | Value no. 3 | ... | Value no. 500 |
|------------+---------------+---------------+---------------+-------+-----------------|
| 1/1/2018 | | | 2 | | 1 |
| 1/3/2018 | 2 | 1 | | | |
| 1/7/2018 | | | 4 | | 8 |
| 1/12/2018 | 5 | 3 | | | |
....
It must be possible to take a snapshot at a certain point in time, to get a complete set of data points, that were valid for that particular point in time, like this:
Snapshot taken 1/3/2018 will yield:
+---------------------------------------------------------+
| Value 1 | Value 2 | Value 3 | ... | Value 500 |
|-----------+-----------+-----------+-------+-------------|
| 2 | 1 | 2 | 0 | 1 |
Snapshot taken 1/9/2018 will yield:
+---------------------------------------------------------+
| Value 1 | Value 2 | Value 3 | ... | Value 500 |
|-----------+-----------+-----------+-------+-------------|
| 2 | 1 | 4 | 0 | 8 |
Snapshot taken 1/13/2018 will yield:
+---------------------------------------------------------+
| Value 1 | Value 2 | Value 3 | ... | Value 500 |
|-----------+-----------+-----------+-------+-------------|
| 5 | 3 | 4 | 0 | 8 |
and so on...
I'm not bound by a particular database technology, so either SQL or NoSQL will do. It is probably not possible to satisfy all the requirements in the DB-domain - some will probably have to be addressed in code. But my main question is what database technology is best suited for this task?
I'm not quite sure this fits a time-series database (TSDB), since only a portion of the values are changed at a given time, and it is important to know which values changed. Maybe I'm wrong?
/Chris
My suggestion would be to model this in a sparse format, something like:
CREATE TABLE DataPoint (
DataID int, /* 1 to 500 in your example, or whatever you need to identify it*/
ValidFrom timestamp, /*default value 01/01/1970-00:00:00 or a suitable "Epoch" */
ValidUntil timestamp, /*default value 31/12/3999-00:00:00 or again something that is in the far future for your case */
value Number (7,5) /* again, this may be any data type, or even more than one field if needed, like Price & Currency
);
What we have just defined is a set of data and the "interval" in which each data has a specific value, so if you measured DataPoint 1 yesterday and got a value of 89.768 you will insert:
DataId=1
ValidFrom=26/11/2018-14:52:41
ValidUntil=31/12/3999-00:00:00
Value=89.768
Then you measure it again tomorrow and get:
DataId=1
ValidFrom=28/11/2018-14:51:23
ValidUntil=31/12/3999-00:00:00
Value=89.443
(Let assume that you have also logic so that when you record a new value you update the current value record and assign ValidUntil=28/11/2018-14:51:23 this is not really needed but will make the example query simpler).
One month from now you have accumulated more measurements for data #1, and the same, on different moments, for data #2 to 500.
You now want to find out what the values were at noon today (i.e. one month "ago") i.e. at 27/11/2018:12:00:00:00
Select DataID, Value from DataPoint where ValidFrom <= 27/11/2018:12:00:00 and ValidUntil > 27/11/2018:12:00:00
This will return:
001,89.768
002,45.678
...,...
500,112.809
Regarding logging who did this, or for what reason, you can either log it separately (saving for example DataPoint Id, Timestamp, UserId...) or make it part of the original table, so that whenever you register a new datapoint you also log who measured it.
Have a look at SQL Server temporal tables engine which may be a solution in your case. This approach allow to run the queries mentioned in the question, for example
SELECT *
FROM my_data
FOR SYSTEM_TIME AS OF '2018-01-01'
However, the table in the example seems to be very large (maybe denormalized). I would suggest to group columns by some technical or functional characteristics (vertical partitioning) to avoid further maintenance drawbacks.

SQL: Calculating a new column in Postgres that refers to its own rows

Let' say I have the following table where percent_leave is the percentage of people from the previous period that leave in the current period:
| Period | percent_leave |
----------------------
| 1 | 0.05 |
| 2 | 0.05 |
| 3 | 0.05 |
| 4 | 0.05 |
I want to calculate a new column that will contain the percentage of people left at the end of that period. For example, if we start with 100 people, 5 people leave in the first period, therefore we are left with 95. 5% of 95 would leave in the second period, which leaves us with 90.25 people, and so forth. Then the table would look like:
| Period | percent_leave | percent_remaining
-----------------------------------------
| 1 | 0.05 | 0.95
| 2 | 0.05 | 0.9025
| 3 | 0.05 | 0.857375
| 4 | 0.05 | 0.81450625
As you can see, the calculation of a new row in percent_remaining refers to the previous row in percent_remaining. Normally I would export this raw data into Excel and do this calculation there, but I would like to automate this task in SQL so I need to figure out how to do this in Postgres.
Any ideas?
You can do this with a cumulative sum . . . and some arithmetic:
select t.*,
exp(sum(ln(1-percent_leave)) over (order by period))
from t;
This is essentially implementing product() as a window function. This assumes that percent_leave is always less than 1 and greater than or equal to 0.
You can also simply use the pow function.
select period,percent_leave,pow((1-percent_leave),period) as percent_remaining
from t
If period values are not consecutive, use row_number as the second argument to pow.
select period,percent_leave
,pow((1-percent_leave),row_number() over(order by period)) as percent_remaining
from t

Find a subset of numbers that equals to the target weighted average and target sum

There is a SQL server table containing 1 million of rows. A sample data is shown below.
Percentage column is computed as = ((Y/X)* 100)
+----+--------+-------------+-----+-----+-------------+
| ID | Amount | Percentage | X | Y | Z |
+----+--------+-------------+-----+-----+-------------+
| 1 | 10 | 9.5 | 100 | 9.5 | 95 |
| 2 | 20 | 9.5 | 100 | 9.5 | 190 |
| 3 | 40 | 5 | 100 | 5 | 200 |
| 4 | 50 | 5.555555556 | 90 | 5 | 277.7777778 |
| 5 | 70 | 8.571428571 | 70 | 6 | 600 |
| 6 | 100 | 9.230769231 | 65 | 6 | 923.0769231 |
| 7 | 120 | 7.058823529 | 85 | 6 | 847.0588235 |
| 8 | 60 | 10.52631579 | 95 | 10 | 631.5789474 |
| 9 | 80 | 10 | 100 | 10 | 800 |
| 10 | 95 | 10 | 100 | 10 | 950 |
+----+--------+-------------+-----+-----+-------------+
Now I need to find the rows such that their amount value add up to a given Amount and weighted average matches to the given Percentage.
For example, if the target Amount =365 and target Percentage=9.84, then from the given dataset, we can say that rows with ID=1,2,6,8,9,10 form the subset which will match the given targets.
Amount = 10+20+100+60+80+95
= 365
Percentage = Sum of (product of Amount and Percentage)/Sum of (Amount)
(I am using Z column to store the products of Amount and Percentage to make the calculations easier)
= ((10*9.5)+(20*9.5)+(100*9.23077)+(60*10.5264)+(80*10)+(95*10))/ (10+20+100+60+80+95)
= 9.834673618
So the rows 1,2,6,8,9,10 matches the given target sum and target weighted average.
Proposed algorithm should work on the 1 million rows and main objective is to achieve the match on the weighted average (Percentage) with Amount as much close as possible to the target Amount.
I found few questions on the stackoverflow which are related to match the target sum. But my problem is to match two target attributes Sum and weighted average.
Which algorithm can be used to achieve this?
Since the target "Percentage" is only approximate (therefore not an actual constraint), let's try removing it and find a solution for Amount. This can only make the problem easier.
What's left is the Subset Sum Problem, which is NP-complete. There are simple exponential-time solutions, and sneaky pseudo-polynomial-time solutions, but I don't think any of them will be practical for a table with 106 rows.
If this is an academic exercise, I suggest you write up the cleverest pseudo-polynomial-time solution you can come up with. If it's a task in the real world, I suggest you go back to the person who gave it to you, explain that an exact solution is impractical, and negotiate for an approximate solution.

Sybase select distinct on one column, do not care about others

I have seen many similar questions but none that meet my needs exactly, and I cannot seem to deduce a solution on my own from inspecting the other questions.
I have the following (mock) table below. My actual table has many more columns.
TableA:
ID | color | feel | size | alive | age
------------------------------------------
1 | blue | soft | large | true | 36
2 | red | soft | large | true | 36
2 | blue | hard | small | false | 37
2 | blue | soft | large | true | 36
2 | blue | soft | small | false | 39
15 | blue | soft | medium | true | 04
15 | blue | soft | large | true | 04
15 | green | soft | large | true | 15
40 | pink | sticky | large | true | 83
51 | brown | rough | tiny | false | 01
51 | gray | soft | tiny | true | 59
34 | blue | soft | large | true | 02
I want the result to look like:
Result of query on TableA:
ID | color | feel | size | alive | age
-------------------------------------------
1 | blue | soft | large | true | 36
2 | red | soft | large | true | 36
15 | blue | soft | medium | true | 04
40 | pink | sticky | large | true | 83
51 | brown | rough | tiny | false | 01
34 | blue | soft | large | true | 02
I want one row for every unique ID column, but I do not want to check the other columns. I need the other columns returned in my result set, but I do not want to filter on them. I just need one row for every unique ID - I do not care which row.
In my example, I selected the first row of every unique ID.
I have tried variations of
select *
from TableA
group by ID having ID = max(ID)
Most examples I have seen with group by and max and/or min functions involve only 2 columns. I have many more columns, however.
I have also seen examples using CTE, but I am not using SQL Server (I am using Sybase).
How can I achieve the result set described?
EDIT
We are using Sybase version 15.1.
Your solution with MIN has some drawbacks. It doesn't return you a specific row but MIN values from the group of rows. You can get as result rows which are not in database. Is it OK for you ?
Row_number is supported in sybase 15.2
http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc38151.1520/html/iqrefbb/iqrefbb262.htm
It's sad if it is not supported in 15.1. You can use then identity column and temporary table to achieve what you want.
There are a variety of ways to do this. If you have a more recent version of Sybase, you can use row_number():
select t.*
from (select t.*, row_number() over (partition by id order by id) as seqnum
from table t
) t
where seqnum = 1;
The solution I have come up with is below.
It "feels" like a poor solution - I am still open to new answers:
SELECT
ID,
min(color),
min(feel),
min(size),
min(alive),
min(age)
FROM TableA
group by ID
I do not like how verbose I am with the application of the min function to every column, but this returns the desired result set.

Grand Total value doesn't match with Top N Filtered values in SSRS

I have a report in reporting services. In this report, I am displaying the Top N values. But my Grand Total is displaying the sum of all the values.
Right now I am getting something like this.Here N = 2
+-------+------+-------------+
| Area |ID | Count |
+-------+------+-------------+
| - A | | 4 |
| | a1 | 1 |
| | b1 | 1 |
| | c1 | 1 |
| | d1 | 1 |
| | | |
| - B | | 3 |
| | a2 | 1 |
| | b2 | 1 |
| | c2 | 1 |
| | | |
|Grand | | 10 |
|Total | | |
+-------+------+-------------+
The correct Grand Total should be 7 instead of 10. A and B are toggle items(You can expand and contract)
How can I display the correct Grand Total using Top N filter?
I also want to use the filter in the report and not in the SQL query.
You should use the filter on the Dataset. Filtering the report object itself only turns off the items (rows, for example) visibility. The item / row itself will still be part of the group and will be used for calculations.
I found a way to solve my question. As Ido said I worked on the dataset. I am using Analysis Cube. So in this cube I created a Named Set Calculation.
In this set I used the TopCount() function. It filters out the TOP N values where N can be integer according to your choice.
So the final Named Set in this case is :-
TopCount([Dim Area].[Area].[Area], 2, ([Measures].[Count]))
This will give you Grand total of Top N filtered values.