I currently have an access database with a table which stores items bought by each customer and the quantity of the item that's bought. So multiple customers can buy the same item with different quantities. I want to display the total quantity bought by all customers for each item and display it in a chart on Vb.net Form. This is what I have so far. When I run this it shows the repeated data in my table for quantity, when I want it to add all the quantities together to display one value single value for each item. There is a way to do this? I've researched this a lot and I can't seem to find a way to do this. Do I have to query the database first so it selects the quantity of each item, adds it together and then displays it in the chart? if so how do I do this?
Thanks a lot!
Me.OrderItemTableAdapter1.Fill(Me.POS_system1DataSet5.OrderItem)
'TODO: This line of code loads data into the 'POS_system1DataSet3.OrderItem' table. You can move, or remove it, as needed.
Me.OrderItemTableAdapter.Fill(Me.POS_system1DataSet3.OrderItem)
OrdersGraph.ChartAreas(0).AxisX.LabelStyle.Interval = 1
' Axis X
OrdersGraph.ChartAreas(0).AxisX.TitleFont = New Font("Oswald", 18.0F, FontStyle.Regular, GraphicsUnit.Pixel)
OrdersGraph.ChartAreas(0).AxisX.Title = "Menu Items"
' Axis Y
OrdersGraph.ChartAreas(0).AxisY.TitleFont = New Font("Oswald", 18.0F, FontStyle.Regular, GraphicsUnit.Pixel)
OrdersGraph.ChartAreas(0).AxisY.Title = "Quantity"
'Hide legend label
OrdersGraph.Series("Orders").IsVisibleInLegend = False
'Show number value in bar / column chart
OrdersGraph.Series("Orders").IsValueShownAsLabel = True
' value member
OrdersGraph.Series("Orders").XValueMember = "ItemID"
OrdersGraph.Series("Orders").YValueMembers = "Quantity"
Your problem is not really with the chart. It is how to select the data you need from your datasource. So I guess when you select, you have some properties which correspond to the table. I made a class which can represent that. For testing
Public Class OrderItem
Public Property ItemID As Integer
Public Property OrderNo As Integer
Public Property Quantity As Integer
Public Property OrderID As Integer
Public Sub New(itemID As Integer, orderNo As Integer, quantity As Integer, orderID As Integer)
Me.ItemID = itemID
Me.OrderNo = orderNo
Me.Quantity = quantity
Me.OrderID = orderID
End Sub
End Class
Then I added the data in your table to a list of that class
Dim orderItems As New List(Of OrderItem)()
orderItems.Add(New OrderItem(3, 84118, 33, 3))
orderItems.Add(New OrderItem(6, 63940, 4, 16))
orderItems.Add(New OrderItem(6, 77996, 6, 17))
orderItems.Add(New OrderItem(5, 77996, 8, 18))
orderItems.Add(New OrderItem(8, 48475, 3, 21))
orderItems.Add(New OrderItem(13, 48475, 2, 22))
orderItems.Add(New OrderItem(2, 93914, 4, 25))
orderItems.Add(New OrderItem(6, 93914, 4, 26))
orderItems.Add(New OrderItem(5, 77590, 5, 31))
orderItems.Add(New OrderItem(2, 93946, 4, 32))
orderItems.Add(New OrderItem(6, 93946, 3, 33))
orderItems.Add(New OrderItem(2, 89181, 4, 38))
orderItems.Add(New OrderItem(6, 89181, 4, 39))
orderItems.Add(New OrderItem(3, 98014, 4, 40))
Now the important part, grouping the data by the ItemID and taking the count of items. You can use LINQ for this
Dim groupedOrderItems = orderItems.GroupBy(Function(oi) oi.ItemID).Select(Function(oig) New With {oig.Key, oig.Count()})
And applying the dataset to the chart
OrdersGraph.Series("Orders").Points.DataBindXY(
groupedOrderItems.Select(Function(oig) oig.Key).ToArray(),
groupedOrderItems.Select(Function(oig) oig.Count).ToArray())
Related
I want to update the multiple balance according to their invoice number in just one query. But the code below seems like the FoxPro not accepting it.
PS: I'm only using Visual FoxPro 6 as a database on my Classic ASP website.
UPDATE accounts_receivables SET balance =
CASE invoice_no
WHEN 3 THEN 6
WHEN 4 THEN 8
ELSE balance
END
WHERE invoice_no IN (3,4)
You must use ICASE() function instead. Like this:
UPDATE accounts_receivables SET balance =
ICASE (
invoice_no = 3, 6,
invoice_no = 4, 8,
"balance"
)
WHERE invoice_no IN (3,4)
This would work with VFP6:
UPDATE accounts_receivables SET balance = iif(invoice_no=3, 6, iif(invoice_no=4, 8, balance)) WHERE invoice_no IN (3,4)
That is also logically the same as writing as:
UPDATE accounts_receivables SET balance = iif(invoice_no=3, 6, 8)) WHERE invoice_no IN (3,4)
as long as you are only filtering on 3, 4.
However, you could also use do this via VFPOLEDB (even from within VFP6), and then you could as well write as a VFP9 supported query (since you say "ASP" likely you are already accessing the data via a VFP driver instead of direct access, you might simply use VFPOLEDB and utilize VFP9 supported SQL).
Sample in VFP (almost the same code from within ASP or VBA):
Local oCon, oCmd
oCon = Createobject("ADODB.Connection")
oCmd = Createobject("ADODB.Command")
oCmd.CommandType = 1
oCmd.CommandText = "UPDATE accounts_receivables"+;
" SET balance = icase(invoice_no=3, 6, invoice_no=4, 8, balance)"+;
" WHERE invoice_no IN (3,4)"
oCon.ConnectionString = "Provider=VFPOLEDB;Data Source=c:\MyDataFolder"
oCon.Open()
oCmd.ActiveConnection = oCon
oCmd.Execute
And saying ASP, if you really meant ASP.Net at this tiem rather than the old classic ASP, then you could even do that simpler like:
string sql = #"UPDATE accounts_receivables
SET balance = icase(invoice_no=3, 6, invoice_no=4, 8, balance)
WHERE invoice_no IN (3,4)";
using(OleDbConnection con = new OleDbConnection(#"Provider=VFPOLEDB;Data Source=c:\MyDataFolder"))
using(OleDbCommand cmd = new OleDbCommand(sql,con))
{
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
Using SSIS I am bringing in raw text files that contain this in the output:
I use this data later to report on. The Key columns get pivoted. However, I don't want to show all those columns individually, I only want to show the total.
To accomplish this my idea was calculate the Sum on insert using a trigger, and then insert the sum as a new row into the data.
The output would look something like:
Is what I'm trying to do possible? Is there a better way to do this dynamically on pivot? To be clear I'm not just pivoting these rows for a report, there are other ones that don't need the sum calculated.
Using derived column and Script Component
You can achieve this by following these steps:
Add a derived column (name: intValue) with the following expression:
(DT_I4)(RIGHT([Value],2) == "GB" ? SUBSTRING([Value],1,FINDSTRING( [Value], " ", 1)) : "0")
So if the value ends with GB then the number is taken else the result is 0.
After that add a script component, in the Input and Output Properties, click on the Output and set the SynchronousInput property to None
Add 2 Output Columns outKey , outValue
In the Script Editor write the following script (VB.NET)
Private SumValues As Integer = 0
Public Overrides Sub PostExecute()
MyBase.PostExecute()
Output0Buffer.AddRow()
Output0Buffer.outKey = ""
Output0Buffer.outValue = SumValues.ToString & " GB"
End Sub
Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
Output0Buffer.AddRow()
Output0Buffer.outKey = Row.Key
Output0Buffer.outValue = Row.Value
SumValues += Row.intValue
End Sub
I am going to show you a way but I don't recommend adding total to the end of the detail data. If you are going to report on it show it as a total.
After source add a data transformation:
C#
Add two columns to your data flow: Size int and type string
Select Value as readonly
Here is the code:
string[] splits = Row.value.ToString().Split(' '); //Make sure single quote for char
int goodValue;
if(Int32.TryParse(splits[0], out goodValue))
{
Row.Size = goodValue;
Row.Type = "GB";
}
else
{
Row.Size = 0;
Row.Type="None";
}
Now you have the data with the proper data types to do arithmatic in your table.
If you really want the data in your format. Add a multicast and an aggregate and SUM(Size) and then merge back into your original flow.
I was able to solve my problem in another way using a trigger.
I used this code:
INSERT INTO [Table] (
[Filename]
, [Type]
, [DeviceSN]
, [Property]
, [Value]
)
SELECT ms.[Filename],
ms.[Type],
ms.[DeviceSN],
'Memory Device.Total' AS [Key],
CAST(SUM(CAST(left(ms.[Value], 2) as INT)) AS VARCHAR) + ' GB' as 'Value'
FROM [Table] ms
JOIN inserted i ON i.Row# = ms.Row#
WHERE ms.[Value] like '%GB'
GROUP BY ms.[filename],
ms.[type],
ms.[devicesn]
I have a form containing a combBox and a textBox. The comboBox is getting it's data from a table witch has only three values (JED,RUH and DMM). What I want is when the user pick any of the three values in the comboBox, the textBox will be filled automatically with a special format of autoNumbering. For example if the user picked JED the format will be j0000a ("j": is static and it's a shotcut of JED, "0000": is a regular number that increases sequentially, "a": is an alphabetical letter that will never change unless the 0000 reaches it's limit witch is 9999). Note that each value in the comboBox has it's special format of autoNumbering and it's unique.
How can I do it ?
Thanks in advance.
If you are storing the value in a table then some VBA code in the drop down's afterupdate() event would do it.
I will take some liberties here because I don't know your exact structure.
Table_ABRV
ID | ABRV
1 | JED
2 | RUH
3 | DMM
And another table.
Table_Auto
ID | CustomID | ABRVID
1 | j0000a | 1
And the code to make this work is
Private Sub cmbABRV_AfterUpdate()
Dim seed, autoVal, autoRemainder, autoAlpha
'[ABRV][####][a]
seed = DCount("ID", "Table_Auto", "ABRVID = " & DLookup("ID", "Table_ABRV", "ABRV = '" & cmbABRV.Text & "'"))
autoVal = Round(seed / 10000, 0) + 1 'this will be used for the alpha character
autoRemainder = seed Mod 10000 'this will be used for numeric value
autoRemainder = Format(autoRemainder, "000#") 'Add preceeding 0's
autoAlpha = ConvertToLetter(autoVal) 'convert the autoVal to Alpha
txtAuto.Value = Left(cmbABRV.Text, 1) & autoRemainder & autoAlpha 'Create string
End Sub
Function ConvertToLetter(Val) As String
'Convert a letter to a numeric equivalent
Dim iAlpha As Integer
Dim iRemainder As Integer
iAlpha = Int(Val / 27)
iRemainder = Val - (iAlpha * 26)
If iAlpha > 0 Then
ConvertToLetter = Chr(iAlpha + 64)
End If
If iRemainder > 0 Then
ConvertToLetter = ConvertToLetter & Chr(iRemainder + 64)
End If
End Function
The form text box will display the auto number after a value is picked from the drop down.
I can't find any good documentation about dataset(), so that's why I want to ask you guys, I'll keep the question short:
Can I set headers (column titles) in a dataset, without entering data into the dataset yet? I guess not, so the 2nd part of the question would be:
Can I make a one-row dataset, in which I name the headers, with empty data, and overwrite it later?
Let me show you what I was trying, but did not work:
dmsdb = dataset({ 'John','Name'},{'Amsterdam','City'},{10,'number' });
produces:
Name City number
John Amsterdam 10 --> Headers are good!
Problem is, that when I am going to add more data to the dataset, it expects all strings to be of the same length. So I use cellstr():
dmsdb(1,1:3) = dataset({ cellstr('John'),'Name'},{cellstr('Amsterdam'),'City'},{10,'number' });
Produces:
Var1 Var2 Var3
'John' 'Amsterdam' 10
Where did my headers go? How do I solve this issue, and what is causing this?
You can set up an empty dataset like either
data = dataset({[], 'Name'}, {[], 'City'}, {[], 'number'});
or
data = dataset([], [], [], 'VarNames', {'Name', 'City', 'number'});
Both will give you:
>> data
data =
[empty 0-by-3 dataset]
But we can see that the column names are set by checking
>> get(data, 'VarNames')
ans =
'Name' 'City' 'number'
Now we can add rows to the dataset:
>> data = [data; dataset({'John'}, {'Amsterdam'}, 10, 'VarNames', get(data, 'VarNames'))]
data =
Name City number
'John' 'Amsterdam' 10
You had the basic idea, but just needed to put your string data in cells. This replacement for your first line works:
>> dmsdb = dataset({ {'John'},'Name'},{{'Amsterdam'},'City'},{10,'number' });
dmsdb =
Name City number
'John' 'Amsterdam' 10
The built-in help for dataset() is actually really good at laying out the details of these and other ways of constructing datasets. Also check out the online documentation with examples at:
http://www.mathworks.com/help/toolbox/stats/dataset.html
One of the Mathworks blogs has a nice post too:
http://blogs.mathworks.com/loren/2009/05/20/from-struct-to-dataset/
Good luck!
Here is an example:
%# create dataset with no rows
ds = dataset(cell(0,1),cell(0,1),zeros(0,1));
ds.Properties.VarNames = {'Name', 'City', 'number'};
%# adding one row at a time
for i=1:3
row = {{'John'}, {'Amsterdam'}, 10}; %# construct new row each iteration
ds(i,:) = dataset(row{:});
end
%# adding a batch of rows all at once
rows = {{'Bob';'Alice'}, {'Paris';'Boston'}, [20;30]};
ds(4:5,:) = dataset(rows{:});
The dataset at the end looks like:
>> ds
ds =
Name City number
'John' 'Amsterdam' 10
'John' 'Amsterdam' 10
'John' 'Amsterdam' 10
'Bob' 'Paris' 20
'Alice' 'Boston' 30
Note: if you want to use concatenation instead of indexing, you have to specify the variable names:
vars = {'Name', 'City', 'number'};
ds = [ds ; dataset(rows{:}, 'VarNames',vars)]
I agree, the help for dataset is hard to understand, mainly because there are so many ways to create a dataset and most methods involve a lot of cell arrays. Here are my two favorite ways to do it:
% 1) Create the 3 variables of interest, then make the dataset.
% Make sure they are column vectors!
>> Name = {'John' 'Joe'}'; City = {'Amsterdam' 'NYC'}'; number = [10 1]';
>> dataset(Name, City, number)
ans =
Name City number
'John' 'Amsterdam' 10
'Joe' 'NYC' 1
% 2) More compact than doing 3 separate cell arrays
>> dataset({{'John' 'Amsterdam' 10} 'Name' 'City' 'number'})
ans =
Name City number
'John' 'Amsterdam' [10]
Lets say I have Id (primary key) list that I want to delete (e.g 1, 2, 3, 4).
Using this query :
Console.WriteLine ("DELETE DATA :");
ActiveRecordMediator<PostgrePerson>.DeleteAll ("Id IN (1, 2, 3, 4)");
I expect the console output is :
DELETE DATA :
NHibernate: DELETE FROM Person WHERE Id IN (1, 2, 3, 4)
but, the actual console output is (I use showsql option) :
DELETE DATA :
NHibernate: select postgreper0_.Id as Id5_, postgreper0_.Name as Name5_, postgreper0_.Age as Age5_, postgreper0_.Address as Address5_ from Person postgreper0_ w
here postgreper0_.Id in (1 , 2 , 3 , 4)
NHibernate: DELETE FROM Person WHERE Id = :p0;:p0 = 1
NHibernate: DELETE FROM Person WHERE Id = :p0;:p0 = 2
NHibernate: DELETE FROM Person WHERE Id = :p0;:p0 = 3
NHibernate: DELETE FROM Person WHERE Id = :p0;:p0 = 4
What should I do to make Castle ActiveRecord generate the expected (optimized) query?
Update
This is my implementation based on accepted answer.
int[] idList = GetIdList ();
ActiveRecordMediator<PostgrePerson>.Execute ((session, obj) => {
string hql = "DELETE PostgrePerson WHERE Id IN (:idList)";
return session.CreateQuery (hql)
.SetParameterList ("idList", idList)
.ExecuteUpdate ();
}, null);
Use the Execute callback method and run a DML-style HQL DELETE on the NHibernate ISession.