How can I change SQL data order from rows to columns? - sql

I have a snippet of code that writes the data alphabetically from a database ACROSS 3 columns on a web page.
Example:
a result b result c result
d result e result f result
g result h result i result
I need instead to display it alphabetically DOWN the columns, like this:
a result d result g result
b result e result h result
c result f result i result
Keeping in mind I have about 100 data results, it would display the first 1/3 in column one descending, then start a new column and continue, breaking it into 3 equal parts.
The code I have now that sorts across the rows is:
<%
GL="<table width="+Z+"100%"+Z+"border=0 cellpadding=3 celspacing=3>"
sql="select * from guideDef order by guideDesc;"
rs.open sql,adoCon
colCount=0
do while not rs.eof
colCount=(colCount+1) mod 3
if colCount=1 then GL=GL+"<tr>"
GL=GL+"<td valign=middle id=menu1 width="+Z+"33%"+Z+">"+E
GL=GL+"<a href="+Z+"shop.asp?guide="+rs("guide")+"&city=Plantation"+Z+">"+E
GL=GL+rs("guideDesc")+"</a></td>"
if colCount=0 then GL=GL+"</tr>"
GL=GL+E
rs.moveNext
loop
rs.close
if colCount=1 then GL=GL+"<td> </td><td> </td></tr>"+E
if colCount=2 then GL=GL+"<td> </td></tr>"+E
GL=GL+"</table>"
response.write GL
%>
Thanks in advance for any help. I don't write code, so I have tried for hours to change this without success.

Maybe a better solution is to leave the SQL as is and handle this in the application code rather than as a result of the query.

I believe this code will solve your problem:
<%
Set rs = Server.CreateObject("ADODB.RecordSet")
Set adoCon = Server.CreateObject("ADODB.Connection")
adoCon.Open "your connection string here"
Const COLUMN_COUNT = 3
Const adOpenStatic = 3
sql = "SELECT guide, guideDesc FROM guideDef ORDER BY guideDesc;"
rs.Open sql, adoCon, adOpenStatic
CellsRemain = rs.RecordCount Mod COLUMN_COUNT
RowCount = (rs.RecordCount - CellsRemain) / COLUMN_COUNT
Response.Write "<div>Rendering " & rs.RecordCount & " records to a " & _
COLUMN_COUNT & " x " & RowCount & " table with " & _
CellsRemain & " stand-alone cells.</div>"
Response.Write "<table width=""100%"" border=""0"" cellpadding=""3"" celspacing=""3"">" & vbCrLf
done = 0
cell = 0
While done < rs.RecordCount
Response.Write "<tr>" & vbCrLf
While cell < COLUMN_COUNT And done < rs.RecordCount
cell = cell + 1
done = done + 1
guide = "" & rs("guide")
guideDesc = "" & rs("guideDesc")
url = "shop.asp?guide=" + Server.UrlEncode(guide) + "&city=Plantation"
Response.Write "<td>"
Response.Write "<a href=""" & Server.HtmlEncode(url) & """>"
Response.Write Server.HtmlEncode(guideDesc)
Response.Write "</td>" & vbCrLf
If cell < COLUMN_COUNT Then rs.Move RowCount
Wend
If done < rs.RecordCount Then
rs.Move -1 * ((COLUMN_COUNT - 1) * RowCount - 1)
cell = 0
Else
While cell < COLUMN_COUNT
Response.Write "<td> </td>" & vbCrLf
cell = cell + 1
Wend
End If
Response.Write "</tr>" & vbCrLf
Wend
Response.Write "</table>" & vbCrLf
%>
This renders your table the way you want it:
A E H
B F I
C G J
D
You can use the COLUMN_COUNT constant to control how many columns will be made. The algorithm flexibly adapts to that number.
What the code does is basically this:
open a static RecordSet object so we can jump around in it freely
calculate how many rows and columns we need to show all records
<tr>
jump down the RecordSet in RowCount steps, painting <td>s until <tr> is full
jump back to the record that's after the one we started with in step 4
</tr>
if there are still records left, go to step 3
render as many empty cells as we need to make the table well-formed
done.

Look at using the PIVOT AND UNPIVOT commands.

Ignore all the answers about using crosstab, they aren't reading your question.
What I would do is get your results as a giant table and divide them into three different collections, then go though each row inserting item one from collection one, then collection two, then collection three, ect, until you have exhausted all three collections.
The other option would be to write code that would go down one column until one third of the results were used, then move on to the next column, but given the way HTML is ordered, that would be a little more difficult to write.

You could divide the results up into 3 parts (if you know the row count). Print them as 3 separate tables within separate div elements. You could then float the div elements next to each other using CSS.
if this sounds like what you want to do, (since you say you don't write code) let me know if you need help with this.

This is also referred to as crosstab queries. You need to use a case statement with some aggregate function see here
http://www.paragoncorporation.com/ArticleDetail.aspx?ArticleID=25

something like this would be what I would do (in c#):
const int columns = 3;
string[] cells = GetCells(); // load your sql into this
string ret = "<table>";
int numRows = (cells.Length + columns - 1) / columns; // round up
for (int y = 0; y < numRows; y++)
{
ret += "<tr>";
for (int x = 0; x < columns; x++)
{
int elem = x*numRows + y;
if (elem < cells.Length)
ret += "<td>" + cells[elem] + "</td>";
else
ret += "<td> </td>";
}
ret += "</tr>";
}
ret += "</table>";
and GetCells() would look something like:
string[] GetCells()
{
string sql = "SELECT guide, guideDesc FROM guideDef ORDER BY guideDesc";
rs.Open(sql, adoCon, adOpenStatic);
string[] ret = new string[rs.RecordCount]
for (int i=0; i<rs.RecordCount; i++)
{
ret[i] = "<a href=...></a>";
}
return ret;
}

Related

Array out of bounds error Visual basic forms

Hi im new to this but my code keeps giving me the same error after ive entered three countries and their details. Once i click Ok on my third data entry i get an out of bounds error message.
here is my code if anyone can help
Dim countries(2) As employee
Dim row As Integer
For row = 0 To 2
countries(row).CountryName = InputBox("row" & row & " Enter name of country")
countries(row).population = InputBox("row" & row & " Enter population")
countries(row).Capital = InputBox("row" & row & " enter capital city")
countries(row).GDP = InputBox("row" & row & " Enter GDP value ")
countries(row).worldRanking = InputBox("row" & row & " GDP world rank")
countries(row).Democracy = InputBox("row" & row & " Democracy based? (1 = yes 2 = no")
Next row
For row = 0 To 4
If countries(row).worldRanking < 100 Then
ListBox1.Items.Add(countries(row).CountryName)
End If
Next row
You've defined a 3-element array here:
Dim countries(2) As employee
(2) = 0 to 2 = three elements.
So countries(row) where row > 2 isn't defined.
Arrays aren't always the best choice for collections. Have a look at IEnumerable, List, etc which have more flexibility (IMHO).
You could use GetUpperBound() in your loops, instead of hard-coding a number:
For row = 0 To countries.GetUpperBound(0)

How to tell what row a db table is reading from

Is there a way to determine the row a set of data has been collected from in a DataTable?
I currently have this code
expression = "date = '" & numericYear & "-" & doubleMonth & "-20'"
foundRows = dbTable.Select(expression)
For count = 0 To foundRows.Length - 1
tableRow =
MessageBox.Show(dbTable.Rows(count).Item(5).ToString())
Next count
The issue is the messagebox shows row 0 then 1 then 2 etc. How can i get it to show the row being read from the Data Table? For example if the event being read is on row 52 of the data table how would i tell that?
you can use the indexof method:
foundRows = dbTable.Select(expression)
For count = 0 To foundRows.Length - 1
rowIndex = dbTable.Rows.IndexOf(foundRows(count))
MessageBox.Show("Row " & cstr(rowIndex) & " " & foundRows(count).Item(5).ToString())
Next count

Double For Loop in VB.NET

Dim ssi(11) As String
For i = 0 To 10
If ssi(i) = "" Then ssi(i) = "0"
For j = 0 To Val(ssi(11)) + i
ssi(i) = xuh(Val(ssi(i)))
Next
Next
If ssi(11) = "2" Then
L_zz.Caption = Val(Left(ssi(0) & ssi(1) & ssi(2) & ssi(3) & ssi(4) & ssi(5) & ssi(6) & ssi(7), ssi(10)))
ElseIf ssi(11) = "3" Then
L_zz.Caption = Val(Left(ssi(0) & ssi(1) & ssi(2) & ssi(3) & ssi(4) & ssi(5) & ssi(6) & ssi(7), ssi(10))) * (-1)
End If
I am new here and new to VB as well.
I am trying to understand this double loop in vb code.
ssi(i) is defined as a String variable. and each element is assigned to a specific number in a String. Hope I told it clearly.
My problem with this loop is below.
Since i ranges from 0 to 10, what does this j mean? Does j mean the new ssi(1-10) or another whatever number?
I think the best way to answer your question about understanding a double loop is to try looking at something simpler.
The first program I always write in each new version of BASIC that comes along is a 12 times table.
I've modified it a bit below to be a 12 x 10 table for the purpose of illustrating for you how a double loop works ... hope it helps:
For x As Integer = 1 To 12
For y As Integer = 1 To 10
Console.Write(x * y)
Console.Write(vbTab)
Next
Console.WriteLine()
Next

ASP Looping through an array inside SQL Statement

I have a form that will have a varying amount of 'Answer" fields. So I have tried building my array as such:
match = "found"
form_counter = 1
i=0
DIM pollanswer()
do while match = "found"
pollanswer(i) = lr_request_collection_dict("poll_answer" & form_counter)
if pollanswer(i) = "" then
match ="notfound"
end if
form_counter=form_counter+1
i=i+1
loop
Later in my code, I am taking those values and wanting to insert them into my database but this is where I am stuck because I do need to insert the first value by itself the then loop through the rest.
thisQuery = "insert into survey_2_surveyquestionanswers (surveyquestionanswer_surveyquestionid, "&_
"surveyquestionanswer_answer, surveyquestionanswer_answerlabel, surveyquestionanswer_order) "&_
"select ##identity, "& SQLQuote(pollanswer(0)) &", "& SQLQuote(pollanswer(0)) &", 1 "&_
icount = 1
ecount = 2
for each arrValue in pollanswer
"union select ##identity, "& SQLQuote(pollanswer) &", "& SQLQuote(pollanswer) &", "& SQLInt(ecount)
ecount=ecount+1
next
";"
set thisRS = dbAccessObj.DirectQuery("live", thisQuery)
Any help would be greatly appreciated.
Well it seems you are inserting the first entry twice with the "for each" method.
You could use the indexed form:
for a_index = 1 to Ubound(pollanswer)
arrValue = pollanswer(a_index)
...
next
This just omits the first array element.

Extract 2 words from a string

im working with a receipt layout and trying to divide up a products descriptiontext into 2 lines if its longer then 24 characters.
my first solution was something like this:
If Row.Description.Length >= 24 Then
TextToPrint &= Row.Description.Substring(0, 24) & " $100"
TextToPrint &= Row.Description.Substring(24) & vbNewLine
else
TextToPrint &= Row.Description & filloutFunction(Row.Description.length) &" $100" & vbNewLine
end if
but that gives this result.
A product with a long na $100
me that doesn't fit
I cant figure out how to make a function to divide the description to look like we normaly see it.
A product with a long $100
name that doesn't fit
hope i made myself clear /:
If its greater than 24 then look for a space character from point 23 decrementally. Once you find it, split the string on that position. That 'column' system you have looks pretty nasty though - where is this output going, screen?
My first shot,
private static List<string> SplitSentence(string sentence, int count)
{
if(sentence.Length <= count)
{
return new List<string>()
{
sentence
};
}
string extract = sentence.Substring(0, sentence.Substring(0, count).LastIndexOfAny(new[]
{
' '
}));
List<string> list = SplitSentence(sentence.Remove(0, extract.Length), count);
list.Insert(0, extract.Trim());
return list;
}
and so :
string sentence = "A product with a long name that doesn't fit";
List<string> sentences = SplitSentence(sentence, 24);
sentences[0] = sentences[0] + " $100";
I think it's possible to optimize.
Something like this should work:
Dim yourString = "This is a pretty ugly test which should be long enough"
Dim inserted As Boolean = False
For pos As Integer = 24 To 0 Step -1
If Not inserted AndAlso yourString(pos) = " "c Then
yourString = yourString.Substring(0, pos + 1) & Environment.NewLine & yourString.Substring(pos + 1)
inserted = True
End If
Next