I'm trying to convert a very simple linq tabular query into a crosstab.
dim q results
Zone Cube QTY
100 LARGE 19
100 MEDIUM 4
100 SMALL 2
100 TINY 1
200 TINY 9
200 LARGE 1
200 TINY 2
linq to crosstab
Dim b = From f In (From x In q Group x By x.Zone Into Group) _
Let MEDIUM As Object = (From r In f.Group Where _
r.Cube = "MEDIUM" Select r.QTY).Sum _
Let SMALL As Object = (From r In f.Group Where _
r.Cube = "SMALL" Select r.QTY).Sum _
Select New With {f.Zone ,SMALL,MEDIUM}
This should give me a crosstab table however I'm only getting the group column and the object columns are not showing up.
I tried different things but I'm stuck. any ideas?
Related
I am new to writing in asp and vb and am stuck on a piece of logic where I need to retrieve data from a web form, count the number of entries and then order them alphanumerically.
I have a webform with the multiple text boxes that can be filled out and submitted that looks a little like this: (excuse the spreadsheet, it's a visual aid only)
I have made an array that contains their values like this:
myArray = array(town, medal, record, sport)
I would like to count and order (everything alphanumerically) the total medals, how many of each medal each town won and the number of records set by each town.
My psuedocode looks a little like this, hopefully I am a little on the right track in terms of logic. The main area I am a little short in is knowing what statements would be good and where, especially to order them alphanumerically.
'this is the psuedocode for the total medals per town
tally = 0 'Set tally to 0
for myArray(town) 'For each town
for myArray(medal) 'For each medal
tally = tally + 1 'Add 1 to the total tally
response.write(myArray(town) "has" tally "medals" & "<br>")
next
next
'this is the pseudocode for the individual medals
for myArray(town) 'For each town
for myArray(medal) 'For each medal
goldTally = 0
silverTally = 0
bronzeTally = 0
if medal = "G"
goldTally = goldTally + 1
elseif medal = "S"
silverTally = silverTally + 1
else medal = "B"
bronzeTally = bronzeTally + 1
response.write(myArray(town) "has:" goldTally "gold medals" &"<br>"
silverTally "silver medals" &"<br>"
bronzeTally "bronze medals" &"<br>"
next
next
Any help you can give would be greatly appreciated thanks heaps.
The VBScript tool for counting/grouping/classifying is the Dictionary. Some use cases: Set ops, word list, split file.
Simple Arrays can be sorted via using an ArrayList. [Array vs Arraylist], fancy sorting7.
For tabular data, use a disconnected recordset.
Inline demo:
Option Explicit
' simple sample data
Dim a : a = Split("b c a b b c a a b")
' use a dictionary for counting/grouping
Dim d : Set d = CreateObject("Scripting.Dictionary")
Dim e
For Each e In a
d(e) = d(e) + 1
Next
WScript.Echo Join(d.Keys)
WScript.Echo Join(d.Items)
' use an ArrayList for sorting simple arrays
Dim l : Set l = CreateObject("System.Collections.ArrayList")
For Each e in a
l.Add e
Next
l.Sort
WScript.Echo Join(l.ToArray())
' use a disconnected recordset for tabular data
Const adVarChar = 200
Const adInteger = 2
Const adClipString = 2
Dim r : Set r = CreateObject("ADODB.Recordset")
r.Fields.Append "k", adVarChar, 50
r.Fields.Append "n", adInteger
r.Open
For Each e In d.Keys
r.AddNew
r.Fields("k").value = e
r.Fields("n").value = d(e)
r.Update
Next
r.MoveFirst
Do Until r.EOF
WScript.Echo r.Fields("k").value, r.Fields("n").value
r.MoveNext
Loop
r.Sort = "k DESC"
WScript.Echo r.GetString(adClipString, , ", ", "; ", "null")
output:
cscript 39305170.vbs
b c a
4 2 3
a a a b b b b c c
a 3
c, 2; b, 4; a, 3;
BTW: Even in a pseudo code language,
for myArray(town) 'For each town
and
response.write(myArray(town) "has:" goldTally "gold medals" ...
can't work at the same time.
I have the following tables
R:
rid, wid, sid, attend
1 1 3 1
2 1 2 0
3 2 3 1
4 3 1 0
5 2 1 1
6 4 1 1
E:
eid, wid,sid
1 1 3
2 2 1
W:
wid, title
1 title1
2 title2
3 title3
4 title4
I want to retrieve the title of W where the wid is in R but not in E. Naturally, I will use LEFT OUTER JOIN. I wrote the following query
SELECT DISTINCT w.title
FROM E LEFT OUTER JOIN R
ON R.sid = E.sid AND R.wid = E.wid
JOIN W
ON R.wid = W.wid
WHERE R.sid = 1 AND R.attend = 1
this will return the titles of wid that exists in both tables R and E: title2 and title3. However, I want to retrieve the titles of wid that exists in R but not in E i.e: title4. Therefore, when I LEFT OUTER JOIN R with E, the columns of E that does not have matching values in R will be filled with NULL values -as far as I know-. Though, when I use the clause WHERE E.sid = NULL or ON E.sid = NULL the query does not retrieve anything what so ever. I tried to retrieve from the table with simple query like
SELECT * FROM E where sid = NULL but it would not retrieve anything although I added a row with sid = null just to test.
so, maybe there is a problem with SQLite supporting null values or maybe it is just something in my query.
I have been searching for a week now. I hope I can find some help here as I usually do.
the first link that #AFract provided helped me. I had two problems.
I was putting table E on the left hand side of the LEFT OUTER JOIN and table R on the right, which does not give proper output. I had to switch their positions
apparently the syntax E.sid = NULL does not work for SQLite although it is written in their documentation on the official site. the correct syntax that worked for me is E.sid IS NULL
so I modified my query as following
SELECT DISTINCT W.title
FROM R LEFT OUTER JOIN E
ON R.sid = E.sid AND R.wid = E.wid JOIN W ON R.wid = W.wid
WHERE R.sid = 1 AND E.sid IS NULL AND R.attend = 1
After searching the forum, I did not find a good solution for this question. If I missed it, please tell me.
I need to count the unique values in one column in EXCEL 2010.
The worksheet has 1 million rows and 10 columns. All cell values are string or numbers.
I used the solution at Count unique values in a column in Excel
=SUMPRODUCT((A2:A1000000<>"")/COUNTIF(A2:A100000,A2:A1000000&""))
But, it runs so long time that the EXCEL is almost frozen. And, it generates 25 processes in Win 7.
Are there more efficient ways to do it?
Also, in the column, all values have for format of
AX_Y
here, A is a character, X is an integer, Y is an integer from 1 to 10.
For example, A5389579_10
I need to cut off the part after (including) undersocre. for the example,
A5389579
This is what I need to count as unique values in all cells in one column.
For example, A5389579_10
A1543848_6
A5389579_8
Here, the unique value has 2 after removing the part after underscore.
How to do it in EXCEL VBA and R (if no efficient solution for EXCEL)?
If you want to do this by VBA, you can take advantage of the Collection object. Since collections can only contain unique values, trying to add all of your input data to a collection will result in an array of unique values. The code below takes all the variables in a selected range and then outputs an array with distinct values to an other sheet (in this case a sheet named Output).
Sub ReturnDistinct()
Dim Cell As Range
Dim i As Integer
Dim DistCol As New Collection
Dim DistArr()
Dim OutSht As Worksheet
Dim LookupVal As String
Set OutSht = ActiveWorkbook.Sheets("Output") '<~~ Define sheet to putput array
If TypeName(Selection) <> "Range" Then Exit Sub
'Add all distinct values to collection
For Each Cell In Selection
If InStr(Cell.Value, "_") > 0 Then
LookupVal = Mid(Cell.Value, 1, InStr(Cell.Value, "_") - 1)
Else
LookupVal = Cell.Value
End If
On Error Resume Next
DistCol.Add LookupVal, CStr(LookupVal)
On Error GoTo 0
Next Cell
'Write collection to array
ReDim DistArr(1 To DistCol.Count, 1 To 1)
For i = 1 To DistCol.Count Step 1
DistArr(i, 1) = DistCol.Item(i)
Next i
'Outputs distinct values
OutSht.Range("A1:A" & UBound(DistArr)).Value = DistArr
End Sub
Note that since this code writes all the distinct values to a single column in the OutSht-sheet, this will return an error if there are more than 1,048,576 distinct values in your dataset. In that case you would have to split the data to be filled into multiple output columns.
For your specific request to count, use the below in a formula like =COUNTA(GetUniques(LEFT("A1:A100000",FIND("_","A1:A100000")-1)) entered as an array formula with Ctrl+Shift+Enter.
It also accepts multiple ranges / values (e.g. GetUniques("A1:A10","B2:E4"))
Function GetUniques(ParamArray args())
Dim arg, ele, arr, i As Long
Dim c As Collection
Set c = New Collection
For Each arg In args
If TypeOf arg Is Range Then
If arg.Count = 1 Then
arr = array(arg.value)
Else
arr = arg.Value
End If
ElseIf VarType(arg) > vbArray Then
arr = arg
Else
arr = Array(arg)
End If
For Each ele In arr
On Error Resume Next
c.Add ele, VarType(ele) & "|" & CStr(ele)
On Error GoTo 0
Next ele
Next arg
If c.Count > 0 Then
ReDim arr(0 To c.Count - 1)
For i = 0 To UBound(arr)
arr(i) = c(i + 1)
Next i
Set c = Nothing
GetUniques = arr
End If
End Function
edit: added a performance optimisation for ranges (loads them at once into an array - much faster than enumerating through a range)
In R:
# sample data
df <- data.frame(x=1:1000000,
y=sample(1e6:(1e7-1),1e6,replace=T))
df$y <- paste0("A",df$y,"_",sample(1:10,1e6,replace=T))
# this does the work...
length(unique(sub("_[0-9]+","",df$y)))
# [1] 946442
# and it's fast...
system.time(length(unique(sub("_[0-9]+","",df$y))))
# user system elapsed
# 2.01 0.00 2.02
In excel 2010... in the next column add (if original data was in A:A add in B1)
= 1/COUNTIF(A:A,A1) and copy down col B to the bottom of your data. Depending on your PC it may chug away calculating for a long time, but it will work. Then copy col B & paste values over itself.
Then SUM col B
What I'm trying to do is create a 2d stacked chart where the position of my series means something like where they are in a queue (position 1 - being the upermost section of the stacked column is last to get served and position 2- is the bottom section of the stacked column will be first up).
I've formatted my data to looks like this (but this can be easily changed if the solution needs it to be):
Task 1 Task 2 Task 3 <- x-axis
A 100 B 400 B 510 <- This row is position 1
B 200 A 200 A 300 <- This row is position 2
^-Legend
The issue I'm having is that I want all tasks on the same chart and excel isn't recognizing at every x the position of A and B. It simply is assuming from Column 1 that Row 2 is A and Row 3 is B and is not adjusting in each subsequent column based on the A/B keys. I'm wondering if there's a way to do this.
As a recap, is it possible to get a 2d stacked chart with multiple x-values that recognizes the position of your legend keys (whether it should be at the top or bottom of the column) at each unique x-value. Any solution either VBA or in-sheet formula I haven't had any luck with.Thanks in advance.
'Run this macro from the sheet containing your data, after highlightling the data.
Sub Macro3()
'The below code assumes that you have already selected
'the columns containing your data and that the first column,
'and every 2nd column after that contains your legend keys.
Dim rng As Range
Set rng = Selection
Dim colNum As Integer
Dim rowNum As Integer
Dim strLegend As String
Dim rowStart As Integer
Dim colStart As Integer
Dim strSeries As String
Dim i As Integer
Dim seriesNum As Integer
Dim shtName As String
rowStart = rng.Row
colStart = rng.Column
shtName = ActiveSheet.Name & "!"
'Creates an empty chart...
ActiveSheet.Shapes.AddChart.Select
'...of type StackedColumn.
ActiveChart.ChartType = xlColumnStacked
seriesNum = 0
'Select all the cells that match the legend in the first column.
For rowNum = 0 To rng.Rows.Count - 1
strLegend = Cells(rowStart + rowNum, colStart).Value
strSeries = "=" & shtName & Cells(rowStart + rowNum, colStart + 1).Address
For colNum = 2 To rng.Columns.Count - 1 Step 2
For i = 0 To rng.Rows.Count - 1
If Cells(rowStart + i, colStart + colNum).Value = strLegend Then
strSeries = strSeries & "," & shtName & Cells(rowStart + i, colStart + colNum + 1).Address
Exit For
End If
Next
Next
'Create a new series.
ActiveChart.SeriesCollection.NewSeries
seriesNum = seriesNum + 1
'Set the legend.
ActiveChart.SeriesCollection(seriesNum).Name = strLegend
'Set the X axis labels to nothing, so the default is used.
ActiveChart.SeriesCollection(seriesNum).XValues = ""
'Set the series data.
ActiveChart.SeriesCollection(seriesNum).Values = strSeries
Next
'An extra series gets added automatically???
'This code removes it.
If ActiveChart.SeriesCollection.Count > rng.Rows.Count Then
ActiveChart.SeriesCollection(rng.Rows.Count + 1).Delete
End If
End Sub
This code requires that your legend values and number values each be in separate columns like shown below. The labels 'Task 1', etc. are not used in this example.
A | 100 | B | 400 | B | 510
B | 200 | A | 200 | A | 300
I have DataTable with two Column as "ID", "Value" with data as:
ID Value
A 100
A 200
A 300
A 400
A 500
B -100
B -99
B -98
B -97
C 1
C 2
C 3
C 4
I want to display this in GridView as:
A B C
100-100 1
200 -99 2
300 -98 3
400 -97 4
Which is the best way to Transpose this in DataTable. It would be really helpful if any one can provide an example.
Regards
I'm fairly familiar with OSI PI data and I've done the same after pulling PI tag data into an SQL Server database.
The trick is that there needs to be another column with the Start Time or End Time so the correct rows for A, B, and C can be matched up.
Then it's just a matter of using PIVOT (SQL Server 2005+ only) to group them:
SELECT *
FROM (SELECT ts_start, ID, Value FROM DataTable) v
PIVOT( SUM(Value) FOR ID IN ([A],[B],[C]) ) AS pvt
You can use just about any aggregate you want (MAX, MIN, SUM, etc.) above, it doesn't matter as long as there's only one value for each distinct combination of tag and timestamp. Aggregation is required by PIVOT, as are the aliases v and pvt (you can name them whatever you like).
Try this function (something i've recently had to do myself). The params are:
dtTableToTranspose = the table you want to transpose (obviously)
index = the column index that has the row key (in your case it will be 0)
private static DataTable TransposeADONETDataTable(DataTable dtTableToTranspose, Int32 index)
{
DataTable dtTransposedTable = new DataTable("TransposedTable");
String colName = dtTableToTranspose.Columns[index].ColumnName.ToString();
dtTransposedTable.Columns.Add(colName);
foreach (DataRow row in dtTableToTranspose.Rows)
{
dtTransposedTable.Columns.Add(row[index].ToString());
}
Int32 colIndex = 0;
foreach (DataColumn dc in dtTableToTranspose.Columns)
{
if (colIndex != index)
{
DataRow newRow = dtTransposedTable.NewRow();
newRow[0] = dc.ColumnName;
for (Int32 destColIndex = 1; destColIndex < dtTransposedTable.Columns.Count; destColIndex++)
{
newRow[destColIndex] = dtTableToTranspose.Rows[destColIndex - 1][colIndex];
}
dtTransposedTable.Rows.Add(newRow);
}
colIndex++;
}
return dtTransposedTable;
}