Using the database index of choices in vb.net comboboxes - vb.net

I have a question concerning indexing of choices in vb.net comboboxes.
Here is the scenario:
I have a database-table which is basically of the following structure:
| ID | Product | Property | .....
---------------------------------------
| 0 | Fork | Property A |
| 1 | Spoon | Property B |
| 2 | Knife | Proberty A |
| 3 | Chair | Property C |
| 4 | Candle | Property B |
| 5 | Plate | Property C |
and so on. I use the column "product" to fill a combobox in a vb.net application. Depending on some other choices, the user makes in advance, only products which have a certain property shall be shown in the combobox. I realized that wich my sql-query and then i assign "Product" to the combobox. So far this works (i hided all the sqlite-stuff here):
CB.DataSource = sqlite.SelectData("Select ID, Product from table where Property = "Property A" order by ID")
CB.ValueMember = "Product"
My Problem is now: How to store the selected value. I want to store the ID of the selected product in another table together with some other tings.
If i read the ID of the selected object using
id = CB.SelectedIndex
i get of course just the position in the combobox of that object, not the real database id. These numbers are the same when the property-filter is off but of course different, when it is on. Is there any simple straight forward way to read the corresponding database id out of the combobox or do i have to query for it before storing the value (that would be nasty altough possible as "Product" has the "unique" flag.)
Thank you very much in advance.
Luke

Related

Create and display table column hierarchy in Tableau

My table currently has a number of similar numerical columns I'd like to nest under a common label.
My current table is something like:
| Week | Seller count, total | Seller count, churned | Seller count, resurrected |
| ---- | ------------------- | --------------------- | ------------------------- |
| 1 | 100 | 10 | 4 |
| 2 | 105 | 12 | 5 |
And I'd like it to be:
| | Seller count |
| Week | Total | Churned | Resurrected |
| ---- | ----- | ------- | ----------- |
| 1 | 100 | 10 | 4 |
| 2 | 105 | 12 | 5 |
I've seen examples of this, including a related instructional video, but this video hides the actual creation of the nested object (called "Segment").
I also tried creating a hierarchy by dragging items in the "Data" tab on top of one another. This function appears to only be possible for dimensions (categorical data), not measures (numerical data) like mine.
Even so, I can drag my column names from the measures side onto the dimensions side to get them to be considered dimensions. Then I can drag to nest and create the hierarchy. But then when I drag the top item of the hierarchy ("Seller count" in the example below) into the "Columns" field, I get the warning "the field being added contains 92,000 members, and maximum recommended is 1,000". It thinks this is categorical data, and is maybe planning to create a subheading for each value (100, 105, etc.), instead of the desired hierarchy sub-items as subheadings.
Any idea how to accomplish this simple hierarchical restructuring of my column labels?
Actually, this is some data restructuring and Tableau isn't best suited for it. Still, it is simple one and you can do it like this-
I recreated one table like yours in excel, and imported it in Tableau
Rename the three cols, (removed seller count from their names)
selected these three columns at once, and select pivot to transform these like
Rename these columns again
create a text table in tableau, as you have shown in question

How to populate combobox in DataGridView with items referenced by specific row

Hello!
I was wondering if maybe one of you guys could help me with this, I'm a student and I usually find my way to solve this kind of problems by doing some Google searches, but now I'm completely lost.
I have two tables in a database:
PERSONS PHONES
+----+-------+ +-----------+----------+
| ID | Name | | Person_ID | Phone |
+----+-------+ +-----------+----------+
| 1 | John | | 1 | 47281923 |
| 2 | Paul | | 1 | 92145694 |
| 3 | Chris | | 2 | 12345678 |
+----+-------+ | 3 | 83929171 |
+-----------+----------+
So, in order to get all phones from all persons, I have to execute this sentence:
SELECT name, phone FROM Persons, Phones WHERE Persons.ID = Phones.Person_ID
So the output of that SQL query should be:
+-------+----------+
| Name | Phone |
+-------+----------+
| John | 47281923 |
| John | 92145694 |
| Paul | 12345678 |
| Chris | 83929171 |
+-------+----------+
So far, so good. The problem is that I'm showing that result in a DataGridView (VB.NET) and I want the phones to populate a ComboBox in a cell of the DataGridView, so the DataGridView would be like:
+-----+----------+------------------------------------------------+
| ROW | NAME | PHONE |
+-----+----------+------------------------------------------------+
| 1 | John | (ComboBox, with phones 47281923 and 92145694) |
| 2 | Paul | (ComboBox, with phone 12345678) |
| 3 | Chris | (ComboBox, with phone 83929171) |
+-----+----------+------------------------------------------------+
I know that I can create a DataGridViewComboBoxColumn, and assign a DataSource to that column, but that would be a DatasSource to the entire column and not each individual "Phone cell" of each row.
How can I achieve this? I'm using Visual Basic, using Windows Forms, working with ODBC and an Informix database to store/get the data.
EDIT 1:
I tried this, a modified version of one of the answers, so I can add data from a table instead of a list:
For i = 0 To dgvPersons.Rows.Count
'The cell with index 1 has the IDNumber of that person.
Dim PersonID As String = connection.ExecuteSelect("SELECT PersonID FROM Persons where IDNumber = '" + dgvPersons.Rows(i).Cells(1).Value.ToString() + "'").Rows(0)(0).ToString()
'It seems I need to convert the Phone to Varchar(20) in the query because the phone is a BigInt and I get an error if I do not convert it.
Dim PersonPhones = connection.ExecuteSelect("SELECT phone::varchar(20) phone from Phones where PersonID = '" + PersonID + "'")
setCellComboBoxItems(dgvClientes, i, 7, TelefonosCliente)
Next
Private Sub setCellComboBoxItems(dataGrid As DataGridView, rowIndex As Integer, colIndex As Integer, itemsToAdd As DataTable)
Dim dgvcbc As DataGridViewComboBoxCell = DirectCast(dataGrid.Rows(rowIndex).Cells(colIndex), DataGridViewComboBoxCell)
For Each row As DataRow In itemsToAdd.Rows
dgvcbc.Items.Add(row.Item(0))
Next
End Sub
When I do that, the program takes forever to load (I have 105 rows) and I have no items in the ComboBoxes, even when I click the ComboBox, it doesn't do anything.
The executeSelect function is in another class, I wrote it.
The "IDNumber" is a number that identifies the person. IDNumber is a Unique Key, but PersonID is a serial Primary Key. I show only the IDNumber in the DataGridView, but the IDNumber exists in the database table.
My DataGridView is already populated with attributes of the Persons table so the DataSource from the DataGridView itself is already set. I suppose I cannot change the contents of the Phone column if that's the case?
Maybe there is a way to create a binding source that allows the DataGridView to put the ComboBoxes automatically?
Thanks!

Organizing & normalising RSS Feed categories data

I am having trouble normalising data from a RSS Feed into a database.
Each post would have id and categories.
The problem I am having is that categories is a list which is not predefined in size. By 1NF I should split a list up such that each column only has atomic data:
+----+----------+
| id | name |
+----+----------+
| 1 | flying |
| 2 | swimming |
| 3 | throwing |
| 4 | sleeping |
| 5 | etc |
+----+----------+
However, blog posts can have more than one category tagged. This means that the posts table can have a list of ids of the categories tagged.
Alternatively, the categories table can have two ids:
+----+--------+----------+
| id | postId | name |
+----+--------+----------+
| 1 | 1 | flying |
| 2 | 1 | swimming |
| 3 | 1 | throwing |
| 4 | 2 | flying |
| 5 | 2 | swimming |
| 6 | 2 | etc |
+----+--------+----------+
And the posts table id will reference the postId column. However, there is repeated data, which is not good.
Lastly, another method I had thought of was to put all the categories in one table:
+----+--------+----------+----------+----------+-----+
| id | flying | swimming | throwing | sleeping | etc |
+----+--------+----------+----------+----------+-----+
| 1 | 1 | 1 | 1 | 1 | 1 |
| 2 | 0 | 1 | 0 | 0 | 0 |
| 3 | 1 | 1 | 0 | 0 | 1 |
| 4 | 0 | 0 | 1 | 1 | 1 |
+----+--------+----------+----------+----------+-----+
1s representing present and 0s representing absent, the id in the posts table references id. This method would not have any repeated data. However, categories from blogs can be created at will, making it hard to maintain such a table as I would need to update it every time there is a new category.
How do I put my database in 3NF, eliminating repetition while keeping it maintainable?
TL;DR "Repeated data" is a bugbear. Learn about design and normalization. Start with rows/tables that make clear straightforward relevant statements about an arbitrary situation. So far all you need is:
-- [id] identifies a post with ...
Post(id, ...)
-- post [id] is tagged [name]
Post_Category(id, name)
there is repeated data, which is not good
What exactly do you think "repeated data" is? And why exactly do you think it's "not good"?
There is nothing intrinsically bad about having the same value appear multiple times as a column of a row or part of a value for a column of a row. What matters is whether rows in tables say overlapping things about a situation in certain ways.
Normalization replaces a table by projections of it that join back to it. That means that it replaces tables whose rows say (ie have predicate) "some stuff AND other stuff" about column values by tables whose rows say "some stuff" and "other stuff" separately. Having "AND"s in such a row/table meaning isn't always bad. When there's only one AND, normalization says to decompose to a particular pair of tables exactly when no shared column set always holds a unique set of values in either of the two tables.
put all the categories in one table
Although there is nothing about such a design that would cause normalization to decompose it, your last table is a "bad" design. (Sometimes this kind of design with repeated similar columns is said to violate some notion of "1NF" or "normalization", but that is a misconception.) Eg its rows say "(post [id] is tagged 'flying' and [flying] = 1 OR post [id] is not tagged 'flying' AND [flying] = 0) AND (post [id] is tagged 'swimming' and [swimming] = 1 OR post [id] is not tagged 'swimming' AND [swimming] = 0) AND ..." when instead we could just have a table Post_Category with rows saying "post [id] is tagged [name]". Eg we cannot write queries that ask about all categories without mentioning all categories explicitly. Eg if we add a new category then we must add a new column to the table and then if we want our past queries re all categories to mean the same thing then they we must add the new column to still be referring to all categories.
PS It's not clear why you introduced ids. There are reasons we do so, but you should do it for a reason. (Normalization does not introduce ids.) Eg introducing post ids if posts are not uniquely identifiable by other information we want to record.

LINQ OrderBy. Does it always return the same ordered list?

I was trying out a simple OrderBy statement.
The target data to order is something like below:
[
{"id":40, "description":"aaa", "rate":1},
{"id":1, "description":"bbb", "rate":1},
{"id":4, "description":"ccc", "rate":2},
{"id":19, "description":"aaa", "rate":1}
]
Then I order items by the rate property.
The odd thing is that if I 'order' them, it 'skips' some items by a given offset and then 'take' only portion of the data.
For example,
var result = items.OrderBy(i => i.rate);
var result = result.Skip(2);
var result = result.Take(2);
The result looks fine for the most of it, but the 'edge case' item is not returned at all.
For example,
if the first result came back as
[{"id":40, "description":"aaa", "rate":1}, {"id":1, "description":"bbb", "rate":1}]
the second result comes back like
[{"id":1, "description":"bbb", "rate":1}, {"id":4, "description":"ccc", "rate":2}]
Item "id: 19" has not been returned with the second query call. Instead item "id: 1" has returned twice.
My guess is that the SQL OrderBy statement doesn't produce the same ordered list every single time OrderBy orders by a given property, but the exact order within a group that shares the same property can change.
What is the exact mechanism under the hood?
Short answer: LINQ to Objects uses a stable sort algorithm, so we can say that it is deterministic, and LINQ to SQL depends on the database implementation of Order By that is usually nondeterministic.
A deterministic sort algorithm is one that have always the same behavior on different runs.
In you example, you have duplicates in your OrderBy clause. For a guaranteed and predicted sort, one of the order clauses or the combination of order clauses must be unique.
In LINQ, you can achieve it by adding another OrderBy clause to refer your unique property, like in
items.OrderBy(i => i.Rate).ThenBy(i => i.ID).
Long answer:
LINQ to Objects uses a stable sort, as documented in this link: MSDN.
In LINQ to SQL, it depends on the sort algorithm of the underlying database and it is usually an unstable sort, like in MS SQL Server (MSDN).
In a stable sort, if the keys of two elements are equal, the order of the elements is preserved. In contrast, an unstable sort does not preserve the order of elements that have the same key.
So, for LINQ to SQL, the sorting is usually nondeterministic because the RDMS (Relational Database Management System, like MS SQL Server) may directly use a unstable sort algorithm with a random pivot selection or the randomness can be related with which row the database happens to access first in the file system.
For example, imagine that the size of a page in the file system can hold up to 4 rows.
The page will be full if you insert the following data:
Page 1
| Name | Value |
|------|-------|
| A | 1 |
| B | 2 |
| C | 3 |
| D | 4 |
If you need to insert a new row, the RDMS has two options:
Create a new page to allocate the new row.
Split the current page in two pages. So the first page will hold the Names A and B and the second page will hold C and D.
Suppose that the RDMS chooses option 1 (to reduce index fragmentation). If you insert a new row with Name C and Value 9, you will get:
Page 1 Page 2
| Name | Value | | Name | Value |
|------|-------| |------|-------|
| A | 1 | | C | 9 |
| B | 2 | | | |
| C | 3 | | | |
| D | 4 | | | |
Probably, the OrderBy clause in column Name will return the following:
| Name | Value |
|------|-------|
| A | 1 |
| B | 2 |
| C | 3 |
| C | 9 | -- Value 9 appears after because it was at another page
| D | 4 |
Now, suppose that the RDMS chooses option 2 (to increase the insert performance in a storage system with many spindles). If you insert a new row with Name C and Value 9, you will get:
Page 1 Page 2
| Name | Value | | Name | Value |
|------|-------| |------|-------|
| A | 1 | | C | 3 |
| B | 2 | | D | 4 |
| C | 9 | | | |
| | | | | |
Probably, the OrderBy clause in column Name will return the following:
| Name | Value |
|------|-------|
| A | 1 |
| B | 2 |
| C | 9 | -- Value 9 appears before because it was at the first page
| C | 3 |
| D | 4 |
Regarding your example:
I believe that you have mistyped something in your question, because you have used items.OrderBy(i => i.rate).Skip(2).Take(2); and the first result do not show a row with Rate = 2. This is not possible since the Skip will ignore the first two rows and they have Rate = 1, so your output must show the row with Rate = 2.
You've tagged your question with database, so I believe that you are using LINQ to SQL. In this case, results can be nondeterministic and you could get the following:
Result 1:
[{"id":40, "description":"aaa", "rate":1},
{"id":4, "description":"ccc", "rate":2}]
Result 2:
[{"id":1, "description":"bbb", "rate":1},
{"id":4, "description":"ccc", "rate":2}]
If you had used items.OrderBy(i => i.rate).ThenBy(i => i.ID).Skip(2).Take(2); then the only possible result would be:
[{"id":40, "description":"aaa", "rate":1},
{"id":4, "description":"ccc", "rate":2}]

How should I implement items that are normalized in the database in object oriented design?

How should I implement items that are normalized in the database in object oriented classes? In the database I have a table of items and Groups. Each item belongs to one group:
+----------------------------------------+
| Inventory |
+----+------+-------+----------+---------+
| Id | Name | Price | Quantity | GroupId |
+----+------+-------+----------+---------+
| 43 | Box | 34.00 | 456 | 4 |
| 56 | Ball | 56.50 | 3 | 6 |
| 66 | Tin | 23.00 | 14 | 4 |
+----+------+-------+----------+---------+
Totally 3000 lines
+----------------------+
| Groups |
+---------+------+-----+
| GroupId | Name | VAT |
+---------+------+-----+
| 4 | Mini | 0.2 |
| 6 | Big | 0.3 |
+---------+------+-----+
Totally 10 lines
I will use the OOP classes in a GUI where the user can edit items and groups in the inventory. It should also be easy to do calculations with a bunch of items. Group information like VAT is needed for calculations.
I will write an Item class, but do I need a Group class? If so, should I keep them in a global location or how do I access them when I need it for item calculations? Is there any design pattern for this case?
First of all, the most common practice is to use an ORM (object-relational mapping) tool. These are available to most any modern OO language, and they take care of generating the classes needed to interact with the database, managing retrieval and updating, and managing connection lifetime.
That aside, yes, you need a Group class that has a collection of Items, and (ideally) a reference from Item to its parent Group. This is one of the areas where an ORM can help, since it can ensure that these two references (the collection of children and the parent reference) stay in sync.
Yes, you need a Group class. It looks like it has a 1:many relationship with Inventory, where Group is the parent. Group will have a reference to a collection or set of Inventory.