ODBC Data Reader HasRows=True but No Data - powershell

I'm connecting to an Access database through ODBC using Powershell, reading data from Access to convert it to another database. I have one query that is causing me problems because although HasRows returns True, when I attempt to loop through the reader, it acts as if it is at the end of the reader. Here is the code I'm using
$FMconn = new-object System.Data.Odbc.OdbcConnection
$FMconn.ConnectionString = "DSN=AccessFileMaker"
$FMconn.Open()
$FMCmd = $FMconn.CreateCommand()
$FMCmd.CommandTimeout = 0
$sql = "
SELECT
fd__folder.id as folderid
,fd__folder.folderletter
,wl__wallet.id as walletid
,wl__wallet.walletnumber
FROM
fd__folder
INNER JOIN wl__wallet
ON fd__folder.id_wallet = wl__wallet.id
WHERE
fd__folder.folderLetter > ''
"
$FMCmd.CommandText = $sql
$Reader = $FMCmd.ExecuteReader()
if ($Reader.HasRows) {
while ($Reader.Read())
{
$folderID = $Reader["folderid"].ToString()
$folderletter = $Reader["folderletter"].ToString().TrimEnd()
$walletID = $Reader["walletid"].ToString()
$walletNum = "Wallet " + $Reader["walletnumber"].ToString().TrimEnd()
(other code here to insert data into the other DB but irrelevant to the problem)
}
$Reader.Close()
}
As I step through the code I get to the while($Reader.Read()) and it immediately steps to $Reader.Close()
The query runs find in Access as is and returns 56115 records. I've used this same process to extract other records from Access (although none of the queries involved a join). So why can't I loop through the records of this query if the Reader has rows? Any help debugging this would be greatly appreciated.

Related

Powershell - ODBC MSAccess Commit transaction refresh data for Select Query after Insert

I'm connecting with ODBC in powershell to an .accdb Access Database. After inserting new data into a table (insert into via ExecuteNonQuery), I'm unable to pull the data with a select command for futher processing (create a PDF table). The resulting object of the query is empty (0 rows), though "Select ##IDENTITY" returns the most recent index identifier. The Workflow is something like this:
Data entered into a forms window -> new record is created -> data is pulled off and processed into a report -> report is sent by mail -> record is flagged as sent
I tried to use the SQL transaction mechanism, but even after the commit is done, the data is not immediately retrievable with a select-query. After inserting another record, the previously inserted one can be pulled with a select query, but not the new most recent one.
I have not found any working solution to this behavior. I've heard about this, when using Access forms, where the data will be available when the form has been moved to the next record. Any ideas how I can solve this?
Below are my getter and setter functions. In general they work as intended but using Set-Data with an insert first and firing Get-Data with a select afterwards does not provide any records.
Function Get-Data($SQLCommand){
try{
$Connection = New-Object System.Data.Odbc.OdbcConnection($DSN)
$Connection.Open()
$AccdbCommand = New-Object System.Data.Odbc.OdbcCommand($SQLCommand, $Connection)
$AccdbAdapter = New-Object System.Data.Odbc.OdbcDataAdapter($AccdbCommand)
$AccdbDataSet = New-Object System.Data.DataSet
$AccdbAdapter.Fill($AccdbDataSet)
$Connection.Close()
return $AccdbDataSet
}
catch
{
[System.Windows.Forms.MessageBox]::Show($_.Exception.Message + "`r`n" + $_.Exception.InnerException, "Fehler",'OK','Error')
}
}
Function Set-Data($SQLCommand){
try
{
$Connection = New-Object System.Data.Odbc.OdbcConnection($DSN)
$Connection.Open()
$Transaction = $Connection.BeginTransaction()
$AccdbCommand = New-Object System.Data.Odbc.OdbcCommand($SQLCommand, $Connection, $Transaction)
$AccdbCommand.ExecuteNonQuery()
$transaction.Commit()
$AccdbCommand = New-Object System.Data.Odbc.OdbcCommand("Select ##IDENTITY", $Connection)
$result = $AccdbCommand.ExecuteScalar()
$Connection.Close()
}
catch
{
[System.Windows.Forms.MessageBox]::Show($_.Exception.Message + "`r`n" + $_.Exception.InnerException, "Fehler", 'OK', 'Error')
}
}
I've resolved this Problem. The commit itself is working as intended. The missing data record in the output process was a result of an error in looping the rows in the dataset with a for Statement.

Powershell Multiple variables in foreach loop getting AWS-EC2 instance info

I need to get instanceId and PrivateIpAddress from all my EC2 instances in my environment and insert into table. I have this but doesn't seem to work. I seem to get everything not just the IP and ID.
$instancestate = (get-ec2instance).RunningInstance
foreach ($instances in $instancestate)
{
$query = "INSERT INTO prodinstances (Idinstance, IPAddress)
VALUES ('$instances.InstanceId','$instances.PrivateIpAddress')"
$Rows = Execute-MySQLNonQuery $conn $query
}
If I change the code
$instancestate = (get-ec2instance).RunningInstance.InstanceId
I get the ID and can insert it in the database. I can also change it to
$instancestate = (get-ec2instance).RunningInstance.PrivateIpAddress
and get the IPAddress and insert that into the database, but when i combine them I get all the info for the EC2 instances which does have .instanceId and .PrivateIpAddress in the list when I hover over the variable $instances. Any Idea how to get both those parameters. My code seems correct but alas it is not...
"VALUES ('$instances.InstanceId'"
is the same as
"VALUES ('" + $instances + ".InstanceId'"
Now it doesn't seem correct. You need $() around it, inside the string:
"VALUES ('$($instances.InstanceId)'"
Fixed works like a charm...
$instancestate = (get-ec2instance).RunningInstance
foreach ($instances in $instancestate)
{
$query = "insert into prodinstances (idinstance,IPAddress) VALUES ('$($instances.InstanceId)', '$($instances.PrivateIpAddress)')
ON duplicate key update idinstance='$($instances.InstanceId)',IPAddress='$($instances.PrivateIpAddr ess)'"
$Rows = Execute-MySQLNonQuery $conn $query
}

iDB2Commands in Visual Studio 2010

These are the basic things I know about iDB2Commands to be used in Visual Studio 2010. Could you please help me how could I extract data from DB2? I know INSERT, DELETE and Record Count. But SELECT or Extract Data and UPDATE I don't know.
Imports IBM.Data.DB2
Imports IBM.Data.DB2.iSeries
Public conn As New iDB2Connection
Public str As String = "Datasource=10.0.1.11;UserID=edith;password=edith;DefaultCollection=impexplib"
Dim cmdUpdate As New iDB2Command
Dim sqlUpdate As String
conn = New iDB2Connection(str)
conn.Open()
'*****Delete Records and working fine
sqlUpdate = "DELETE FROM expusers WHERE username<>#username"
cmdUpdate.Parameters.Add("username", iDB2DbType.iDB2Date)
cmdUpdate.Parameters("username").Value = ""
'*****Insert Records and working fine
sqlUpdate = "INSERT INTO expusers (username, password, fullname) VALUES (#username, #password, #fullname)"
cmdUpdate.Parameters.Add("username", iDB2DbType.iDB2VarChar)
cmdUpdate.Parameters.Add("password", iDB2DbType.iDB2VarChar)
cmdUpdate.Parameters.Add("fullname", iDB2DbType.iDB2VarChar)
cmdUpdate.Parameters("username").Value = txtUsername.Text
cmdUpdate.Parameters("password").Value = txtPassword.Text
cmdUpdate.Parameters("fullname").Value = "Editha D. Gacusana"
'*****Count Total Records and working fine
Dim sqlCount As String
Dim cmd As New iDB2Command
sqlCount = "SELECT COUNT(*) AS count FROM import"
cmd = New iDB2Command(Sql, conn)
Dim count As Integer
count = Convert.ToInt32(cmd.ExecuteScalar)
'*****Update Records and IT IS NOT WORKING AT ALL
sqlUpdate = "UPDATE expusers SET password = #password WHERE RECNO = #recno"
cmdUpdate.Parameters.Add("recno", iDB2DbType.iDB2Integer)
cmdUpdate.Parameters.Add("password", iDB2DbType.iDB2VarChar)
cmdUpdate.Parameters("recno").Value = 61
cmdUpdate.Parameters("password").Value = txtPassword.Text
cmdUpdate.Connection = conn
cmdUpdate.CommandText = sqlUpdate
cmdUpdate.ExecuteNonQuery()
conn.Close()
Please help me how to code the SELECT query wherein I could extract/fetch data from DB2 Database. Also, how could i update the records in the database.
Thanks!
Instead of ExecuteNonQuery(), look at ExecuteReader(). I don't have VS2010 installed, but try something like this:
iDB2Command cmdSelect = new iDB2Command("SELECT username, password, fullname FROM expusers", conn);
cmdSelect.CommandTimeout = 0;
iDB2DataAdapter da = new iDB2DataAdapter(cmdSelect);
DataSet ds = new DataSet();
da.Fill(ds, "item_master");
GridView1.DataSource = ds.Tables["expusers"];
GridView1.DataBind();
Session["TaskTable"] = ds.Tables["expusers"];
da.Dispose();
cmdSelect.Dispose();
cn.Close();
See: http://gugiaji.wordpress.com/2011/12/29/connect-asp-net-to-db2-udb-for-iseries/
If you aren't trying to bind to a grid, look at iDB2Command.ExecuteReader() and iDB2DataReader()
The DELETE is working fine? The code has the parameter type for "username" set to iDB2Date. The INSERT has "username" set to iDB2VarChar. How is the column defined in the table? Char, Varchar or Date?
On the UPDATE, you reference RECNO, but that does not seem to be a column in the table. Updating a relational database table by row number is a bad idea - the row numbers are not guaranteed to stay constant. If you are just testing, as I think you are, don't use RECNO, use RRN(). The DB2 for i syntax is WHERE rrn(expusers) = #recno
To help your testing, do a SELECT without a WHERE clause and list out all the rows. Make sure the name stored in the username column matches the name you are trying to update. Pay particular attention to the case of the data. If the name in expusers looks like "EDITHA D. GACUSANA", and #username is "Editha D. Gacusana" then it will not match on the WHERE clause.

memcached - how to use it for multiple records returned from single SELECT operation?

memchached is useful for caching and looking up of single independent records. For the multiple records returned from doing a SELECT operation, how could I make good use of the memcached for caching and looking up later?
I didn't get you. If you use php or .net (Enyim client) you can store your result in to an object and set it in to the memcached. (Client will serialize the object and store it in the memcached.)
Following example will store one or more records (results) returned by the db query.
//Init Memcache, Try avoid multiple init if possible because this is a costly operation
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");
mysql_pconnect("localhost","root","");
mysql_select_db("YOURDB");
$query = "SELECT * FROM table where `firstname`='dasun';";
$key = md5($query);
$get_result = $memcache->get($key);
if ($get_result) {
print_r($get_result);
echo "It's a hit! :)";
}
else {
$result = mysql_query($query);
$row = mysql_fetch_array($result);
print_r($row);
// Store the result for 5 minutes
$memcache->set($key, $row, TRUE, 300);
echo "Not a hit. :(";
}

Can I tell if an ado.net DbCommand is a query or not (before executing it)

I am trying to write a Powershell script to run a general SQL command against a database. The idea is that Run-SQL "select ..." will run the SQL text against the currently open database. If the SQL statement is a query, it should return a DataTable. If it is a non-query (DDL or DML) it should return nothing ($null).
In order to do this, I need to know which method (ExecuteReader or ExecuteNonQuery) to execute against the command. Is there a way to determine this? (I'm happy to prepare the command if that helps).
As an alternative, I can add a -query argument to be supplied by the user, which distinguishes the two cases, but as a potential user, I'd find this annoying (as, in my view, I have already said whether it's a query by the SQL I used, why say again?)
My key use is for Oracle databases, so an Oracle-specific answer is OK with me, although I'd prefer something generic.
I think you could just use ExecuteReader whether it's a query or not. It may be overkill but in some quick experiments with doing an UPDATE ($reader returns nothing) and a COUNT ($reader[0] outputs scalar result) - it just seems to work.
$connstr = "server=.\SQLEXPRESS;Database=AdventureWorks;" +
"Integrated Security=true;Persist Security Info=False"
$conn = new-object System.Data.SqlClient.SqlConnection $connstr
#$query = "UPDATE Production.Product SET Name = 'ACME' WHERE Name = 'Blade'"
$query = "SELECT Count(*) FROM Production.Product"
$cmd = new-object System.Data.SqlClient.SqlCommand $query,$conn
$conn.Open()
try
{
$reader = $cmd.ExecuteReader()
while ($reader.Read())
{
$reader[0]
}
}
finally
{
$conn.Dispose()
}
As an alternative to what Keith said you could try
$sql = 'Select count(1) From SomeTable;'
$sql = $sql.TrimStart(' ')
if ($sql -match "^select") { Write-Host 'ExecuteReader' }
else { Write-Host 'ExecuteNonQuery'}
The trim is there in case the SQL command has a leading space since $sql = ' select ' won't match "^select"