Tuesday, July 9, 2013

In SQL Query, Only Return Every n-th Record

A little SQL trick that helps in some cases. In my case, I wanted to select some data that is logged into the table every several seconds, and then quickly plot it in Excel, but over a date range of a few months. So, I run a query

SELECT "timestamp", valueiwant
FROM mytable
order by timestamp

And that potentially leaves me with thousands or hundreds of thousands of rows. However, to visualise a trend over time, I don't need to plot each and every value on the graph. I'll be happy with 1/10 or even 1/100 of records. Here is how I can use ROW_NUMBER to achieve that.

SELECT * FROM
(
 SELECT "timestamp", instrumenttimestamp, ROW_NUMBER() OVER (order by timestamp) AS rownum
    FROM mytable
 order by timestamp
) AS t
WHERE t.rownum % 25 = 0

Row number returns the sequential number of a row in the result set. The WHERE clause then checks if the number is a multiple of 25, therefore only rows 25, 50, 75, 100 etc. will be returned by the outer query.

References

ROW_NUMBER (Transact-SQL)
Return row of every n'th record
by . Also posted on my website

Saturday, June 29, 2013

Final Hurdles While Installing Windows Updates

There are three different PC models here, all configured in the same way, all have to have Windows Updates installed on them automatically. However, while two of the models were happily updated, the third decided it does not like some of the updates and presented me with the screen similar to the following:

Turns out these two error codes are quite known problems.

The first one is solved, among some other options, by downloading and installing a specific update: , which is over 300MB in size. So in my case I had to do a check for the PC model by reading it via PowerShell

$strModel = (Get-WmiObject Win32_ComputerSystem).Model.Trim()

and if the model was the "weird" one, install this update.

The second one is solved by repairing the .NET Framework 4 installation. Fortunately, this can be done either silently or with unattended option. All in all, the fix for my two problems was applied as the following addition to the script and, fortunately, no additional restarts were required and after running this bit I could proceed to install updates as per my previous post.

if($strModel -Like "*WeirdModel*")
{
 Write-Host "Verifying .NET Framework 4 ..."
 Start-Process "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\SetupCache\Client\setup.exe" "/repair /x86 /x64 /ia64 /parameterfolder Client /passive /norestart" -Wait
 Write-Host "Done."
 Write-Host "Installing System Update Readiness Tool ..."
 $readinessTool = Join-Path $win7Folder "Windows6.1-KB947821-v27-x64.msu"
 $toolCommand = $readinessTool + " /quiet /norestart"
 Write-Host $toolCommand
 Start-Process "wusa.exe" $toolCommand -Wait
 Write-Host "Done."
}

References:

Error Code 0x80073712 occurs in Windows Update or Microsoft Update
System Update Readiness Tool for Windows 7 (KB947821) [May 2013]
Error codes “0x80070643” or “0x643” occur when you install the .NET Framework updates
Silent install, repair and uninstall command lines for each version of the .NET Framework
by . Also posted on my website

Tuesday, June 25, 2013

Optimising Windows Updates Installation

It's a good thing that I wrote about Installing Windows Updates via Shell Script some time ago because today I needed to reuse that bit of a script and could not find it anywhere on my PC or our corporate network.

This time I'm reusing most of the functionality, but additionally do the following:

  • Make sure that the Windows Update service is started
  • Run a PowerShell script that passes a folder where the Windows update files are stored to the VbScript file
  • Execute VbScript to install all updates in a folder
  • Repeat. (I want to keep my "required" and "optional" updates separate

I was caught for a while trying to use PowerShell Set-Service and Start-Service commands and getting permission errors. I did not quite solve it, but found a simple workaround by utilising a command line:

@ECHO OFF

sc config wuauserv start= auto
net start wuauserv

Next, the PowerShell script is used to pass parameters to VbScript:

cscript .\Common\InstallUpdates.vbs $updatesFolder

Finally, the VbScript is almost the same as in the previous version, but note how the argument passed by PowerShell is parsed. The argument is the name of the folder where I placed the updates downloaded from Microsoft Update Catalog

Set args = WScript.Arguments
sfolder = args.Item(0)

Dim objfso, objShell
Dim iSuccess, iFail
Dim files, folderidx, Iretval, return
Dim fullFileName

Set objfso = CreateObject("Scripting.FileSystemObject")
Set folder = objfso.GetFolder(sfolder)
Set objShell = CreateObject("Wscript.Shell")

With (objfso)
 If .FileExists("C:\log.txt") Then
  Set logFile = objfso.OpenTextFile("C:\log.txt", 8, TRUE)
 Else
  Set logFile = objfso.CreateTextFile("C:\log.txt", TRUE)
 End If
End With

Set files = folder.Files
iSuccess = 0
iFail = 0

For each folderIdx In files

fullFileName = sfolder & "\" & folderidx.name

 If Ucase(Right(folderIdx.name,3)) = "MSU" then
  logFile.WriteLine("Installing " & folderidx.name & "...")
  iretval=objShell.Run ("wusa.exe " & fullFileName & " /quiet /norestart", 1, True)
  If (iRetVal = 0) or (iRetVal = 3010) then
   logFile.WriteLine("Success.")
   iSuccess = iSuccess + 1
  Else
   logFile.WriteLine("Failed.")
   iFail = iFail + 1
  End If
 ElseIf Ucase(Right(folderIdx.name,3)) = "EXE" Then
  logFile.WriteLine("Installing " & folderidx.name & "...")
  iretval = objShell.Run(fullFileName & " /q /norestart", 1, True)
  If (iRetVal = 0) or (iRetVal = 3010) then
   logFile.WriteLine("Success.")
   iSuccess = iSuccess + 1
  Else
   logFile.WriteLine("Failed.")
   iFail = iFail + 1
  End If
 End If
Next
 
wscript.echo iSuccess & " update(s) installed successfully and " & iFail & " update(s) failed. See C:\log.txt for details."

Disable the Windows Update service again if necessary

net stop wuauserv
sc config wuauserv start= disabled

References:

Managing Windows Services from the command line
Working with Command-Line Arguments
How do you pass a variable to VBS script in a powershell command?
Enable/Disable a Service via PowerShell
PowerShell queryService – Wait for a Dependency Starting Service
by . Also posted on my website

Tuesday, May 14, 2013

Customising Windows Installation

In some cases - for example, where the only purpose of the PC is to run a specific software package - certain Windows features are customised with the provider's brand. Such features may include logon screen background, individual desktop backgrounds for each user and user account logon pictures (tile images). Therefore it may be useful to know where those are stored and how to update them. The following description is for Windows 7 and Windows Server 2008.

1. Windows logon screen background.

This is the easiest one. It should be copied to the following location: C:\Windows\system32\oobe\info\backgrounds\backgroundDefault.jpg. A registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\Background\OEMBackground should exist with a dword value of 00000001.

2. Desktop backgrounds (wallpaper) for each user

Check the following registry key: HKEY_CURRENT_USER\Control Panel\Desktop\Wallpaper. What I found was the following: C:\Users\Account_Name\AppData\Roaming\Microsoft\Windows\Themes\TranscodedWallpaper.jpg

Therefore, for each Account_Name the image has to be replaced with the desired one.

3. User Account logon pictures

This turned out to be trickier. There is a description on MSDN on how to do it manually [1]. Automating the task is not so obvious. Turns out, there is a function in the shell32.dll that sets a user login picture. It can be called easily from C# code by P/Invoke. In fact, the following is the full code of a console application that will update the user login picture.

using System;
using System.Runtime.InteropServices;

namespace UserPictureUpdater
{
    class Program
    {
        [DllImport("shell32.dll", EntryPoint = "#262", CharSet = CharSet.Unicode, PreserveSig = false)]
        public static extern void SetUserTile(string username, int notneeded, string picturefilename);
        [STAThread]
        static void Main(string[] args)
        {
            if (args.Length == 2)
            {
                SetUserTile(args[0], 0, args[1]);
            }
        }
    }
}

The application can run from command line

UserPictureUpdater Administrator adminnew.png

Or, in my case, I'm running it from PowerShell script the following way

Start-Process $command $params

Where $command is the full path, i.e. "C:\Folder\UserPictureUpdater.exe", and $params is the command line parameters, i.e. "Administrator adminnew.png".

Also, turns out someone figured out the way to do the whole thing in PowerShell [2]. But I was done with my approach by the time I found out.

References

About User Profiles
Setting the user tile image in Windows 7 and Server 2008 R2
by . Also posted on my website

Saturday, April 6, 2013

Google as my automated testing tool

It is probably a well-known fact, but Google webmaster tools record errors when they crawl the website. Of course, first of all the website has to be submittet to Google. After that, the crawl errors can be accessed by selecting the website of interest and clicking Health. On the left side, Crawl Errors will be available.

I did not even know that this was available until I received an email from Google which informed me that there was an increase in server errors and provided me a link to review those errors.

Google Webmaster Tools

Looks like the website was generating about ~70 errors when crawled, and I did not know. When the number of errors increased to ~90, I got an email. The errors are listed and can be marked as fixed as I deal with the root cause.

Website Crawl Errors

Most errors were caused by my refactoring where I replaced direct access to the database with using the repository pattern, and did it carelessly.

Another reason was that I used a tool I found on the web to generate my website map and did not review it before uploading on the website. The map contained some links that were not supposed to be accessed directly. It is probably a good idea to review those links to verify they are really needed or can be replaced and if they are needed, remove them from the site map. I'll be tracking the errors from now on.

References

Webmaster tools
Crawl errors
Sitemap Generator
by . Also posted on my website

Friday, April 5, 2013

Project ROSALIND: Rabbits and Recurrence Relations

I came across the project ROSALIND which is described as learning bioinformatics through problem solving. It is intriguing and well-designed, so I started with solving some introductory ones.

The first interesting problem was modified Fibonacchi sequence. Actually, I did not know that the background of the Fibonacci sequence was modelling of rabbit reproduction. It assumed that rabbits reach reproductive age after one month, and that every mature pair of rabbits produced a pair of newborn rabbits each month. A modified problem, however, suggested that every mature pair of rabbits produced k pairs of newborn rabbits each month. The task is to calculate a total number of rabbit pairs after n months, assuming we have one pair of newborn rabbits at the start.

While the problem could be solved by recursion, the cost of calculation would be high. Every successive month the program would re-calculate the full solution for each previous month. A better approach is dynamic programming (which, in essence, is just remembering and reusing the already calculated values). Here is the modified solution in C#.

/// <summary>
/// Modified Fibonacchi problem: each rabbit pair matures in 1 month and produces "pairs" of newborn rabbit pairs each month
/// </summary>
/// <param name="pairs">Number of newborn rabbit pairs produced by a mature pair each month</param>
/// <param name="to">Number of months</param>
/// <returns>Total number of rabbit pairs after "to" months</returns>
static Int64 Fibonacci(int pairs, int to)
{
 if (to == 0)
 {
  return 0;
 }

 Int64 mature = 0;
 Int64 young = 1;

 Int64 next_mature;
 Int64 next_young;
 Int64 result = 0;
 for (int i = 0; i < to; i++)
 {
  result = mature + young;

  next_mature = mature + young;
  next_young = mature * pairs;

  mature = next_mature;
  young = next_young;
 }
 return result;
}

Note: the result grows fast! When trying to use the default Int32 (32 bit, or up to ~2 billion) and calculate the result for 4 pairs and 32 months, the value overflowed at around month 23.

The next problem was another variation on the rabbit simulation. In this case, the rabbits are mortal and die after k months. My solution was to have a counter for rabbits of each age at each step. I keep the counters in the dictionary, where the key is the age of a rabbit pair and the value is the number of rabbit pairs of that age on that step.

/// <summary>
/// Mortal Rabbits Fibonacci sequence variation
/// </summary>
/// <param name="months">How many months does the simulation run for</param>
/// <param name="lifespan">Rabbit lifespan</param>
/// <returns>A count of rabbit pairs alive at the end</returns>
static UInt64 MortalRabbits(int months, int lifespan)
{
 Dictionary<int, UInt64> dRabbits = GetEmptyDictionary(lifespan);
 dRabbits[0]++;

 for (int i = 0; i < months - 1; i++)
 {
  Dictionary<int, UInt64> newRabbits = GetEmptyDictionary(lifespan);
  foreach (KeyValuePair<int, UInt64> pair in dRabbits)
  {
   int age = pair.Key;

   if (age == 0)
   {
    newRabbits[1] = newRabbits[1] + dRabbits[age];
   }
   else if (age > 0 && age < lifespan - 1)
   {
    newRabbits[age + 1] = newRabbits[age + 1] + dRabbits[age];
    newRabbits[0] = newRabbits[0] + dRabbits[age];
   }
   else if (age == lifespan - 1)
   {
    newRabbits[0] = newRabbits[0] + dRabbits[age];
   }
  }
  dRabbits = newRabbits;
 }

 UInt64 count = 0;
 foreach (KeyValuePair<int, UInt64> pair in dRabbits)
 {
  count = count + pair.Value;
 }

 return count;
}

/// <summary>
/// Creates an dictionary where keys are integers from 0 to lifespan - 1, and all values are zeros
/// </summary>
/// <param name="lifespan"></param>
/// <returns>An empty dictionary</returns>
static Dictionary<int, UInt64> GetEmptyDictionary(int lifespan)
{
 Dictionary<int, UInt64> dRabbits = new Dictionary<int, UInt64>();

 for (int i = 0; i < lifespan; i++)
 {
  dRabbits.Add(i, 0);
 }
 return dRabbits;
}

References

Project ROSALIND
Modified Fibonacci Problem
Mortal Fibonacci Rabbits
Fibonacci Series
by . Also posted on my website

Wednesday, March 27, 2013

Improving a PostgreSQL report performance: Part 2 - Temporary Table

The report I was working on still did not live up to expectations. There was something else going on. I had to dig a little deeper.

The report was generated by XTraReports and I have no authority to edit it. The ReportDataSource contains functions for retrieving datasets for main report and subreport.

public class ReportDataSource : BaseDataSource
{
 public DataSet GetPrimaryReportData(DateTime fromDate, DateTime toDate)
 {
  string commandText = "select * from myreportfunction;";
  var reportDataSet = ExecuteQuery("ReportDataSet", commandText, new[] { "MainDataSet" });
  return reportDataSet;
 }

 public DataSet GetSubReportData(DateTime fromDate, DateTime toDate)
 {
  string commandText = String.Format("select * from myreportsubfunction");
  return ExecuteQuery("SubReportDataSet", commandText, new[] { "SubDataSet" });
 }
}

And here's how the PostgreSQL functions looked like.

The myreportsubfunction is the one I worked on already so now it looked like the following

CREATE OR REPLACE FUNCTION myreportsubfunction(IN from timestamp without time zone, IN to timestamp without time zone)
  RETURNS TABLE(Name1 character varying, Name2 character varying) AS
$BODY$
BEGIN
RETURN QUERY EXECUTE
'select Column1 as Name1, Column2 as Name2
from sometable tbl
inner join ...
where ...
and ...
and $1 <= somedate
and $2 >= somedate
group by ...
order by ...;' USING $1, $2;
END
$BODY$
  LANGUAGE plpgsql VOLATILE

And there was the myreportfunction

CREATE FUNCTION myreportfunction ( FROMdate timestamp without time zone, todate timestamp without time zone )
 RETURNS TABLE ( name character varying, somevalue1 integer, somevalue2 real ) AS $body$
 SELECT
    something,
    sum(somevalue1)::int as somevalue1,
    sum(somevalue2)::real as somevalue2
 FROM myreportsubfunction($1, $2)      group by something;
  $body$ LANGUAGE sql;

What's going on here? Well, looks like first the myreportfunction is called, it calls the myreportsubfunction and returns aggregated results. But then the myreportsubfunction is called separately and essentially executes the same huge query again! No wonder the performance is nowhere near acceptable. Anyway, to satisfy the report requirements, I need to have the aggregated data first, which means that I need to save the results of the huge complex query, aggregate the results and return them for the main report, and then return the saved results of the query as subreport, or "detailed" data. My approach is to use the temporary table.

Here is what the functions will do:

myreportfunction

  • if a temptable exists, drop it
  • create a temptable
  • run a complex query and save results in the temptable
  • run a query that returns the aggregated data for the report

myreportsubfunction

  • if the temptable exists, return everything from the table, then drop the table

And the resulting PostgreSQL code

myreportfunction

CREATE OR REPLACE FUNCTION myreportfunction(IN fromdate timestamp without time zone, IN todate timestamp without time zone)
  RETURNS TABLE("name" character varying, somevalue1 character varying, somevalue2 character varying) AS
$BODY$
BEGIN
DROP TABLE IF EXISTS temptable;
CREATE TEMPORARY TABLE temptable("name" character varying, somevalue1 character varying, somevalue2 character varying);
DELETE FROM temptable;

EXECUTE '
insert into temptable(name, somevalue1, somevalue2)  
select Column1 as Name1, Column2 as Name2
from sometable tbl
inner join ...
where ...
and ...
and $1 <= somedate
and $2 >= somedate
group by ...
order by ...;' USING $1, $2;

RETURN QUERY EXECUTE 'SELECT name, somevalue1, somevalue2 FROM temptable group by name;';
END
$BODY$
  LANGUAGE plpgsql VOLATILE

myreportsubfunction

CREATE OR REPLACE FUNCTION myreportsubfunction(IN timestamp without time zone, IN timestamp without time zone)
  RETURNS TABLE(name character varying, somevalue1 integer, somevalue2 real) AS
$BODY$
BEGIN
IF EXISTS (SELECT 1 FROM temptable) THEN 
 RETURN QUERY EXECUTE'select * from temptable';
 DELETE FROM temptable;
 DROP TABLE IF EXISTS temptable;
END IF;
END
$BODY$
  LANGUAGE plpgsql VOLATILE

Now hoping for the performance improvement by at least 50% ...

References

CREATE TABLE
Improving a PostgreSQL report performance: Part 1 - RETURN QUERY EXECUTE
by . Also posted on my website