I understand there are MANY ways to do all of this, but trying to do it the best way.
I have created the db parameters, dns, dbh, sth, sql and generally quite happy with the result up to ... well ... the result part.
<?php
// db parameters
$dbhost = "localhost";
$dbname = "x";
$dbuser = "y";
$dbpass = "z";
// driver invocation (dsn is short for data source name)
$dsn = "mysql:host=$dbhost;dbname=$dbname";
// create db object (dbh is short for database handle)
$dbh = new PDO($dsn, $dbuser, $dbpass);
// execution of database query (sth is short for statement handle)
$sql = "SELECT * FROM a_aif_remaining";
$sth = $dbh->prepare($sql);
$sth->execute();
NOT SURE WHAT TO PUT BELOW.... (A) or (B)
I just want to present a simple array of the data. One row from the table per line.
Option A
echo $_POST['fieldname1'];
echo $_POST['fieldname2'];
echo $_POST['fieldname3'];
Option B
while ($rows = $sth->fetch(PDO::FETCH_ASSOC)) {
echo $row[fieldname1],'<br>';
}
AND I AM CONFIDENT WITH THE ENDING
$dbh = NULL;
?>
Any advise would be GREATLY appreciated.
UPDATED CODE: (Produces nothing on the page)
<?php
// db parameters
$dbhost = "localhost";
$dbname = "theaudit_db1";
$dbuser = "theaudit_user";
$dbpass = "audit1999";
$dsn = "mysql:host=$dbhost;dbname=$dbname"; // driver invocation (dsn is short for Data Source Name)
try {
$dbh = new PDO($dsn, $dbuser, $dbpass); // connect to new db object (dbh is short for Database Handle)
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // set the PDO error mode to enable exceptions
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // set the PDO emulate prepares to false
// execute query to database (sth is short for Statement Handle)
$sql = "SELECT * FROM a_aif_remaining";
$sth = $dbh->prepare($sql);
$sth->execute();
$data = $sth->fetchAll(PDO::FETCH_ASSOC);
$dbh = NULL;
}
catch(PDOException $e)
{
echo $e->getMessage();
}
?>
Though I can't get what's the connection between A anb B, I can answer the
I just want to present a simple array of the data. One row from the table per line.
question.
$sql = "SELECT * FROM a_aif_remaining";
$sth = $dbh->prepare($sql);
$sth->execute();
$data = $sth->fetchAll(PDO::FETCH_ASSOC);
where $data is a sought-for array.
The problem with your updated code is simple - you arent echo'ing your data out. You need to add something like..
foreach($data as $arKey=>$dataRow){
foreach($dataRow as $arKey=>$rowField){
echo $rowField.','; //concat with a ',' to give csv like output
}
echo '<br>'; //to get to next line for each row (may want to trim the last ','
}
I am also confused by the reference to $_POST. It is true both are associate arrays but that does not mean that the $_POST option is viable - the data would only be available in the $_POST if you put it there (eg $_POST = $data) which would be pointless. Or if you had posted the data from somewhere else. Neither seem to fit what you are asking so I would forget about the $_POST and just figure out how you access your multi dimensional $data array. There is endless tut's on this subject. Try using
var_dump($data)
to see whats inside that should help you visualise what is going on.
NOTE: in option B you are not correctly concatenating or referencing your array it should be:
while ($rows = $sth->fetch(PDO::FETCH_ASSOC)) {
echo $rows[fieldname1].'<br>'; //$row doesnt exist its $rows and you use . to concat not ,
}
Ah yes and probably better to use unset rather than setting $dbh to equal null
unset($dbh);
Related
I need to query a group of SAP sybase databases for some information and print that as a comma spearated list. So I figure I write a perl script that connects to any of those databases via DBI module. Here is what I came up with.
my $user = "someuser";
my $passwd = "somepassword";
my #sids=(filled with DB identifiers);
my $output="";
my $size;
my $version;
my $id;
my $dsn;
my $dbh;
my $sid;
my #row;
my $sth1;
my $sth2;
foreach $sid (#sids) {
print $sid."\n";
$dsn = "dbi:Sybase:server=$sid;charset=iso_1;tdsLevel=CS_TDS_50";
print $dsn."\n";
$dbh = DBI->connect($dsn, $user, $passwd,{ PrintError => 0,RaiseError => 0, AutoCommit => 1, syb_enable_utf8 => 1});
print "DBI OK\n" if defined ($dbh);
$sth1 = $dbh->prepare('select SUM(size) from master..sysusages WHERE dbid = 4 AND segmap = 3');
$sth2 = $dbh->prepare('select ##version');
$sth1->execute;
while (#row = $sth1->fetchrow) {
$size = $row[0];
}
$size = $size * 16 / 1024;
$sth1->finish;
$sth2->execute;
while (#row = $sth2->fetchrow) {
$version = $row[0];
}
$sth2->finish;
$output = $sid.",".$size.",".$version;
$dbh->disconnect;
print $output."\n";
}
When I execute this, it crashes after 4th iteration, because the connection handle is not set. So the connection of the fifth DB does not work anymore.
Can't call method "prepare" on an undefined value at ./check_sybasedbs.pl line 36.
Line 36 is the preparation of statement 1.
I tried putting sleep commands at various positions. I also tried to explicitly clean up the variables that are reused via undef. Now I am out of ideas and would really appreciate your input.
Your code could be written as sample below (please see if ... else ... block for $dbh)
use strict;
use warnings;
use feature 'say';
use DBI;
my($user, $passwd) = qw/someuser somepassword/;
my #sids = qw/server1 server2 ... server#/;
foreach my $sid (#sids) {
my $dsn = "dbi:Sybase:server=$sid;charset=iso_1;tdsLevel=CS_TDS_50";
say "DSN: $dsn";
my $dbh = DBI->connect($dsn, $user, $passwd, { PrintError => 1,
RaiseError => 1,
AutoCommit => 1,
syb_enable_utf8 => 1
}
);
if( not defined ($dbh) ) {
say "WARNING: Could not connect to $dsn";
} else {
say "INFO: DB connection established";
my($size,$version);
my $query = 'SELECT
SUM(size)
FROM
master..sysusages
WHERE
dbid = 4
AND
segmap = 3
';
my $sth = $dbh->prepare($query);
$sth->execute;
while (#row = $sth->fetchrow) {
$size = $row[0];
}
$sth->finish;
$query = 'select ##version';
$sth = $dbh->prepare($query);
$sth->execute;
while (#row = $sth->fetchrow) {
$version = $row[0];
}
$sth->finish;
$dbh->disconnect;
$size = $size * 16 / 1024;
say "SID: $sid, SIZE: $size, VERSION: $version";
}
}
NOTE: use strict; use warnings; helps to avoid many pitfalls, use diagnostics; helps to identify a problem in difficult cases
NOTE: $sth->fetchrow_hashref allows address hash element by name, no need to count index of array as in case $sth->fetch_rowarray
in my naiv thinking I hid some lines of code that I was convinced could not be the reason for this misbehaviour. As it turns out, it was. So the reason for my problem was a simple logical error, that caused the password, that was used after a connect to a certain DB to be wrong.
I have a function that exports the results of a SQL query to a json file:
# Connect to SQL Server
$SqlCommand.CommandText = $Query;
$SqlCommand.Connection = $SqlConnection;
# Execute query and get the result back
$QueryResult = $SqlCommand.ExecuteReader()
# Hold query result in data table
$QueryTable = New-Object "System.Data.DataTable"
$QueryTable.Load($QueryResult)
# Export query results to json
$QueryTable | Select-Object $QueryTable.Columns.ColumnName | ConvertTo-Json | Out-File "$OutputDirectory\$SqlInstance-$QueryName.json"
And I have multiple queries that I want to execute and have created variables for each one:
$q1 = "SELECT blah"
$q2 = "SELECT more blah"
$q3 = "SELECT even more blah"
I call the function by:
ExportQueryResultsToJson -Query $q1 -QueryName "q1"
I have around 80 queries that I want to execute so instead of having 80 lines of ExportQueryResultsToJson ... I want to use ForEach. I've created an array of variables:
$SqlServer2012QueryArray = #(
$q1,
$q2,
$q3
)
I've tried many variations of the following:
foreach ($Query in $SqlServer2012QueryArray) {
$Expression = "ExportQueryResultsToJson -Query '$Query' -QueryName $Query"
Invoke-Expression $Expresion
}
And I've tried using a splat but I can't figure out how to pass all queries in correctly.
What am I doing wrong?
You can approach this in a number of ways. Three possible ways, which are all very algorithmically similar, are below:
Using Your Array:
The solution depends on your array $sqlserver2012QueryArray having a list of sequentially numbered variables in the format q<number>. The first variable name must be q1.
for ($i = 0; $i -lt $sqlserver2012QueryArray.Count; $i++) {
ExportQueryResultsToJson -Query $sqlserver2012QueryArray[$i] -QueryName $((Get-Variable "q$($i+1)").Name)
}
Querying Already Created Variables:
This solution relies on your variables being named in the format q<number>. They do not have to be sequentially named. It could capture unwanted variables if they are named like q<number>abc.
foreach ($var in (Get-Variable -Name q[0-9]*)) {
ExportQueryResultsToJson -Query $var.Value -QueryName $var.Name
}
Using a Hash Table:
You can create a hash table with each key name being your variable name and the associated value being the query string. You can bypass creating the query variables all together with this solution by just inputting the query strings as the values.
$queryhash = #{'q1' = $q1; 'q2' = $q2; 'q3' = $q3; 'q14' = $q14}
foreach ($var in $queryhash.GetEnumerator()) {
ExportQueryResultsToJson -Query $var.Value -QueryName $var.Key
}
Note: In all cases, you should try to avoid Invoke-Expression. It is not generally a safe command to use because it welcomes code injection. I also don't see why it is necessary at all in this case either.
I have few lines in my array #lines in which * shows me the start time of a command (like sync/fetch) and the line with same processID pid and the command without * shows me the end time. They may not be continuous always. I would like to get the startdate and enddate of a particular processID and cmd. Like for usera the cmd sync with processID 11859 started at 2015/01/13 13:53:01.491-05:00 and ended at 2015/01/13 13:55:01.492-05:00
Below is my approach in which I took a hash of array and used processID as key and did split the lines. This works fine only when the start and end lines of a command are continuous , but how can I make it work even when they are not continuous.
my %users;
foreach my $line (#lines) {
if ($line =~ m{(\*)+}) {
($stdate, $sttime, $pid, $user, $cmd) = split ' ', $line;
$startdate ="$stdate $sttime";
}
else {
($eddate, $edtime, $pid, $user, $cmd) = split ' ', $line;
$enddate = "$eddate $edtime";
}
$users{$pid} = [ $startdate, $enddate, $user, $cmd ];
}
Content in #lines:
2015/01/13 13:53:01.491-05:00 11859 usera *sync_cmd 7f1f9bfff700 10.101.17.111
2015/01/13 13:57:02.079-05:00 11863 userb *fetch_cmd 7f1f9bfff700 10.101.17.111
2015/01/13 13:59:02.079-05:00 11863 userb fetch_cmd 7f1f9bfff700 10.101.17.111
2015/01/13 13:55:01.492-05:00 11859 usera sync_cmd 7f1f9bfff700 10.101.17.111
I'm looking at your code and wondering why you're using a hash of arrays.
As far as I'm concerned, the purpose of array is a set of similar but ordered values.
Could you not instead do:
my %processes;
foreach (#lines) {
my ( $date, $time, $pid, $user, $cmd, #everything_else ) = split;
if ( $cmd =~ m/^\*/ ) {
#if command starts with a * - it started.
if ( defined $processes{$pid} ) {
print "WARNING: $pid reused\n";
}
$processes{$pid}{'start_date'} = $date;
$processes{$pid}{'time'} = $time;
$processes{$pid}{'user'} = $user;
$processes{$pid}{'cmd'} = $cmd;
}
else {
#cmd does not start with '*'.
if ( $processes{$pid}{'cmd'} =~ m/$cmd/ ) {
#this works, because 'some_command' is a substring of '*some_command'.
$processes{$pid}{'end_date'} = $date;
$processes{$pid}{'end_time'} = $time;
}
else {
print
"WARNING: $pid has a command of $cmd, where it started with $processes{$pid}{'cmd'}\n";
}
}
}
You might want some additional validation tests in case you've got e.g. a long enough log that pids get reused, or e.g. you've got a log that doesn't include both start and finish of a particular process.
When you assign to %users{$pid} you are presuming that the most recent $startdate and $enddate are both relevant. This problem is exacerbated by the fact that your variables that hold your field values have a scope larger than the foreach loop, allowing these values to bleed between records.
In the if block, you should assign the values of $startdate, $user, $cmd to the array. Individually or as a slice if you like. In the else block you should assign $enddate to it's element in the array.
Regex extra credit: You don't seem to really care if there is more that one * in a record, making the + in the regex superfluous. As an added bonus, without it the capturing group is also of no value. m{\*} should do quite nicely.
Very new to Perl. I am having issues trying to get DBI to communicate to a SQL server 2008 DB.
I get the following error when I try and connect to SQL Servereveb when I try to use ODBC or directly.
I am new to Perl, can someone please assist...thanks
install_driver(MSSQL) failed: Can't locate object method "set_sql" via package "Class::DBI::MSSQL" at C:/Perl/lib/DBD/MSSQL.pm line 79. Compilation failed in require at (eval 19)C:/Perl/site/lib/DBI.pm:744 line 3.
use strict;
use warnings;
use diagnostics;
use Class::DBI::Loader;
use DBI;
use File::Glob ':glob';
my $DBUserName = "*******";
my $DBPassword = "*******";
my $DBName = "dbi:MSSQL:uat-dbserver1";
my $dbh = "";
my $sqlStatement = "";
my $sqlCmd = "";
my #EasySetTableNames = ();
$dbh = DBI->connect( $DBName, $DBUserName, $DBPassword,
{ PrintError => 0, AutoCommit => 0})
|| die "Database connection creation failed: $DBI::errstr\n";
$sqlStatement = "SELECT * from tableA ";
$sqlCmd = $dbh->prepare($sqlStatement);
$sqlCmd->execute();
#EasySetTableNames = #{$dbh->selectcol_arrayref($sqlStatement)};
print "hi";
and via ODBC
#!/usr/bin/perl -w
use strict;
use DBI;
# Replace datasource_name with the name of your data source.
# Replace database_username and database_password
# with the SQL Server database username and password.
my $data_source = "dbi:MSSQL:test";
my $user = "test";
my $password = "test";
# Connect to the data source and get a handle for that connection.
my $dbh = DBI->connect($data_source, $user, $password)
or die "Can't connect to $data_source: $DBI::errstr";
# This query generates a result set with one record in it.
my $sql = "SELECT 1 AS test_col";
# Prepare the statement.
my $sth = $dbh->prepare($sql)
or die "Can't prepare statement: $DBI::errstr";
# Execute the statement.
$sth->execute();
# Print the column name.
print "$sth->{NAME}->[0]\n";
# Fetch and display the result set value.
while ( my #row = $sth->fetchrow_array ) {
print "#row\n";
}
# Disconnect the database from the database handle.
$dbh->disconnect;
Any help you can provide would be so appreciated.
I usually use the ODBC driver from within the dbi and this is how I would usually hit sql server (2008 r2)
#!/export/appl/pkgs/perl/5.8.4-fiq/bin/perl
#!/usr/bin/perl
#!/bin/sh
use strict;
use DBI;
use Time::localtime;
use Data::Dumper;
my $dsn = 'DBI:ODBC:Driver={SQL Server}';
my $host = 'xxx\yyy';
my $database = 'testing';
my $user = 'user';
my $auth = 'password';
my $dbh = DBI->connect("$dsn;Server=$host;Database=$database", $user, $auth) or die "Database connection not made: $DBI::errstr";
my $sql = "EXECUTE database.schema.sproc";
my $stmt = $dbh->prepare($sql);
$stmt->execute();
$stmt->finish();
$dbh->disconnect;
I was able to connect to SQL Server using OLE32, here is an example of the code..."Cursor type changed" error on Perl OLE32 MSSQL dateadd function results
I'm trying to make a query to a database in Joomla 2.5. I have a db named 'example', and I'm trying to get certain value named 'value' (very original) for a user whose id is 949:
$db =& JFactory::getDBO();
$query = $db->getQuery(true);
$user = 949;
$db->setQuery( 'SELECT value FROM example WHERE user_id = ' . $user );
$result = $db->loadObjectList();
echo $result;
However, I'm just getting 'Array' as result (the expected value is a decimal, e.g. 4.5).
Could someone please tell me what am I doing wrong?
$db =& JFactory::getDBO();
$query = $db->getQuery(true);
$user = 949;
$db->setQuery( "SELECT value FROM example WHERE user_id = '" . $user."'" );
$result = $db->loadObjectList();
echo $result;
try this one
$db->loadObjectList() returns an array of objects, which echo can't display. If you want to just return one value from one row, user $db->loadResult() instead.