Assuming I have the table as you showed but called "fm".
use DBI;
use strict;
use warnings;
use Data::Dumper;
use JSON::XS;
my $h = DBI->connect('dbi:ODBC:xxx', 'xxx', 'xxx');
my $r = $h->selectall_arrayref(q/select company, col1, col2, col3 from fm/);
print Dumper($r);
my @to_encode;
foreach my $row (@$r) {
my $hash;
$hash->{name} = shift @$row;
$hash->{data} = $row;
push @to_encode, $hash;
}
my $js = encode_json(\@to_encode);
print Dumper($js);
outputs:
$VAR1 = [
[
'comp1',
'1',
'2',
'3'
],
[
'comp2',
'4',
'5',
'6'
],
[
'comp3',
'7',
'8',
'9'
]
];
$VAR1 = '[{"name":"comp1","data":["1","2","3"]},{"name":"comp2","data":["4","5","6"]},{"name":"comp3","data":["7","8","9"]}]';
EDIT: re-read your example and I think this is really what you want:
use DBI;
use strict;
use warnings;
use Data::Dumper;
use JSON::XS;
my $h = DBI->connect('dbi:ODBC:baugi', 'sa', 'easysoft');
my $s = $h->prepare(q/select col1, col2, col3 from fm/);
$s->execute;
my $cols = $s->{NAME};
my @data;
for (my $n = 0; $n < scalar(@$cols); $n++) {
push @data, {name => $cols->[$n], data => []};
}
while (my @row = $s->fetchrow) {
for (my $n = 0; $n < scalar(@$cols); $n++) {
push @{$data[$n]->{data}}, shift @row;
}
}
my $js = encode_json(\@data);
print Dumper($js);
$VAR1 = '[{"name":"col1","data":["1","4","7"]},{"name":"col2","data":["2","5","8"]},{"name":"col3","data":["3","6","9"]}]';
There are probably much more elegant ways of doing it and simplifying the Perl work with better SQL but it is early and I've not had my first coffee yet.
As you point out the numbers look like strings in the encoded JSON. That is because your JSON module (well JSON::XS anyway) uses something like sv_POK on the scalars to try and guess whether they are numbers or strings and most DBD modules bind all columns as strings and set the returned scalar with sv_setpv. It is annoying but you will need to add 0 to each number before calling encode_json OR:
By sheer chance I just happen to be changing DBD::ODBC so it will bind integers as integers - see Major changes to column binding in Perl DBD::ODBC
With DBD::Oracle you can bind the columns as SQL_INTEGER add the DiscardString attribute e.g.,
$s->prepare(q/select company,col1,col2,col3 from mytable);
$s->execute;
$s->bind_col(2, undef, {TYPE => SQL_INTEGER, DiscardString => 1});
# repeat for col2 and col3
$r = $s->fetchall_arrayref
I believe some other DBDs already bind integers as integers - may be DBD::Pg.