Showing posts with label Php and mysql. Show all posts

SQL Server JSON to Table and Table to JSON

One of the surprises that I got from writing for Simple-Talk was the popularity of my article Consuming JSON Strings in SQL Server.  I hadn’t really expected it to be so appreciated; in fact I was nervous about posting it at all. It came from a real requirement I had at the time, but I got interested in it in order to show how one could analyse hierarchical data documents iteratively in TSQL. Also, an anonymous troll on StackOverflow had told me it was impossible.
There were a few questions that I’d left unanswered. The first was how to read a JSON string as a table, and the other was how to produce a JSON document from a table. I ran out of space in the article and thought it was really the sort of thing that readers of the article would want to experiment with.
In this blog, I’ll take the whole process around the circle.  You’ll notice that much of this is a bit cumbersome, but I only use short JSON Strings and haven’t noticed a performance problem in doing this.
We start with a table.
Select *  from adventureworks.production.location

And by a quick use of …
  Select ‘("’+Convert(varchar(3),LocationID)+‘", "’+ Name+‘", "’+Convert(varchar(10),CostRate)
   
+‘", "’+Convert(varchar(10),Availability)+‘", "’+Convert(varchar(10),ModifiedDate,126)+‘"),’

  from
adventureworks.production.location
We can convert it to a PowerShell array that we can use as if it were a table
@(("1", "Tool Crib", "0.00", "0.00", "2002-06-01"),
("2", "Sheet Metal Racks", "0.00", "0.00", "2002-06-01"),
("3", "Paint Shop", "0.00", "0.00", "2002-06-01"),
("4", "Paint Storage", "0.00", "0.00", "2002-06-01"),
("5", "Metal Storage", "0.00", "0.00", "2002-06-01"),
("6", "Miscellaneous Storage", "0.00", "0.00", "2002-06-01"),
("7", "Finished Goods Storage", "0.00", "0.00", "2002-06-01"),
("10", "Frame Forming", "22.50", "96.00", "2002-06-01"),
("20", "Frame Welding", "25.00", "108.00", "2002-06-01"),
("30", "Debur and Polish", "14.50", "120.00", "2002-06-01"),
("40", "Paint", "15.75", "120.00", "2002-06-01"),
("45", "Specialized Paint", "18.00", "80.00", "2002-06-01"),
("50", "Subassembly", "12.25", "120.00", "2002-06-01"),
("60", "Final Assembly", "12.25", "120.00", "2002-06-01")
)|
   Select @{name="LocationID"; Expression = {$_[0]}},
                     @{name="Name"; Expression = {$_[1]}},
                     @{name="CostRate"; Expression = {$_[2]}},
                     @{name="Availability"; Expression = {$_[3]}},
                     @{name="ModifiedDate"; Expression = {(Get-Date $_[4]).DateTime}} |
     convertTo-json
… and this we can use to get the JSON version of the SQL Table, and from there to JSON…
[
    {
        "CostRate":  "0.0000",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Tool Crib",
        "Availability":  "0.00",
        "LocationID":  "1"
    },
    {
        "CostRate":  "0.0000",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Sheet Metal Racks",
        "Availability":  "0.00",
        "LocationID":  "2"
    },
    {
        "CostRate":  "0.0000",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Paint Shop",
        "Availability":  "0.00",
        "LocationID":  "3"
    },
    {
        "CostRate":  "0.0000",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Paint Storage",
        "Availability":  "0.00",
        "LocationID":  "4"
    },
    {
        "CostRate":  "0.0000",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Metal Storage",
        "Availability":  "0.00",
        "LocationID":  "5"
    },
    {
        "CostRate":  "0.0000",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Miscellaneous Storage",
        "Availability":  "0.00",
        "LocationID":  "6"
    },
    {
        "CostRate":  "0.0000",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Finished Goods Storage",
        "Availability":  "0.00",
        "LocationID":  "7"
    },
    {
        "CostRate":  "22.5000",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Frame Forming",
        "Availability":  "96.00",
        "LocationID":  "10"
    },
    {
        "CostRate":  "25.0000",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Frame Welding",
        "Availability":  "108.00",
        "LocationID":  "20"
    },
    {
        "CostRate":  "14.5000",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Debur and Polish",
        "Availability":  "120.00",
        "LocationID":  "30"
    },
    {
        "CostRate":  "15.7500",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Paint",
        "Availability":  "120.00",
        "LocationID":  "40"
    },
    {
        "CostRate":  "18.0000",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Specialized Paint",
        "Availability":  "80.00",
        "LocationID":  "45"
    },
    {
        "CostRate":  "12.2500",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Subassembly",
        "Availability":  "120.00",
        "LocationID":  "50"
    },
    {
        "CostRate":  "12.2500",
        "ModifiedDate":  "06/01/1998 00:00:00",
        "Name":  "Final Assembly",
        "Availability":  "120.00",
        "LocationID":  "60"
    }
]
We could, of course, have got the table as a Datatable by ADO.NET and converted that to JSON
$SourceTable=‘production.location’
$Sourceinstance=‘MyInstanceName’
$Sourcedatabase=‘Adventureworks’

$SourceConnectionString = "Data Source=$Sourceinstance;Initial Catalog=$Sourcedatabase;Integrated Security=True"
$sql = "select * FROM $SourceTable"
$result=@()
try
{
       $sourceConnection  = New-Object System.Data.SqlClient.SQLConnection($SourceConnectionString)
       $sourceConnection.open()
       $commandSourceData  = New-Object system.Data.SqlClient.SqlCommand($sql,$sourceConnection)
       $reader = $commandSourceData.ExecuteReader()
       $Counter = $Reader.FieldCount
   while ($Reader.Read()) {
              $tuple=@{}
              for ($i = 0; $i -lt $Counter; $i++) {
#$Reader.GetFieldType($i).Name
                      $tuple."$($Reader.GetName($i))"="$(if ($Reader.GetFieldType($i).Name -eq ‘DateTime’)
                                                  {$Reader.GetDateTime($i)}
                                             else {$Reader.GetValue($i)})";
                 }
              $Result+=$tuple
      }
  $result |convertTo-JSON
}
catch
{
    $ex = $_.Exception
    Write-Error "whilst opening source $Sourceinstance . $Sourcedatabase . $SourceTable : $ex.Message"
}
finally
{
    $reader.close()
}
Which produces the same JSON String
To produce this directly from the table takes more effort. First you would need to install the library from my JSON article. You can convert the table to a hierarchy table.
create TABLE #hierarchy
  (
   element_id INT IDENTITY(1, 1) NOT NULL, /* internal surrogate primary key gives the order of parsing and the list order */
   parent_ID INT,/* if the element has a parent then it is in this column. The document is the ultimate parent, so you can get the structure from recursing from the document */
   Object_ID INT,/* each list or object has an object id. This ties all elements to a parent. Lists are treated as objects here */
   NAME NVARCHAR(2000),/* the name of the object */
   StringValue NVARCHAR(MAX) NOT NULL,/*the string representation of the value of the element. */
   ValueType VARCHAR(10) NOT null /* the declared type of the value represented as a string in StringValue*/
  )
;With loc (Roworder,locationID, Name, CostRate, Availability, ModifiedDate)
as
(
Select  ROW_NUMBER() OVER ( ORDER BY locationID) as RowOrder,
       LocationID, Name, CostRate, Availability, ModifiedDate
from Adventureworks.production.location
)
 
INSERT INTO #Hierarchy (parent_ID,Object_ID,NAME,StringValue,ValueType)
          Select Roworder,null,‘LocationID’, convert(varchar(5),LocationID),‘int’  from loc
union all Select Roworder,null,‘Name’, Name ,‘string’  from  loc
union all Select Roworder,null,‘CostRate’, convert(varchar(10),CostRate) ,‘real’  from  loc
union all Select Roworder,null,‘Availability’, convert(varchar(10),Availability) ,‘real’  from  loc
union all Select Roworder,null,‘ModifiedDate’, Convert(varchar(10),ModifiedDate,126) ,‘string’  from  loc
union all Select (Select count(*) from loc)+1, ROW_NUMBER() OVER ( ORDER BY locationID ), NULL,’1′,‘object’ from  loc
union all Select null, (Select count(*) from loc)+1,‘-’,”,‘array’
from that point, it is easy to create the JSON string
 
DECLARE @MyHierarchy JSONHierarchy
INSERT INTO @myHierarchy
       SELECT * from #hierarchy
 
SELECT dbo.ToJSON(@MyHierarchy)
And it won’t surprise you that the string is more or less identical to the one we got in PowerShell.
Of course, reading a JSON string as a table is rather easier.
Create view TableOfJSONString as
 
Select parent_ID,
       max(case when name=‘LocationID’ then convert(int,StringValue) else 0 end) as LocationID,
       max(case when name=‘Name’ then convert(Varchar(50),StringValue) else ” end) as Name,
       max(case when name=‘CostRate’ then convert(SmallMoney,StringValue) else 0 end) as CostRate,
       max(case when name=‘Availability’ then convert(Decimal(8,2),StringValue) else 0  end) as Availability,
       max(case when name=‘ModifiedDate’ then convert(DateTime,StringValue) else 0 end) as ModifiedDate
from dbo.parseJSON( ‘[
    {
        "LocationID":  "1",
        "Name":  "Tool Crib",
        "CostRate":  "0.00",
        "Availability":  "0.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    },
    {
        "LocationID":  "2",
        "Name":  "Sheet Metal Racks",
        "CostRate":  "0.00",
        "Availability":  "0.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    },
    {
        "LocationID":  "3",
        "Name":  "Paint Shop",
        "CostRate":  "0.00",
        "Availability":  "0.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    },
    {
        "LocationID":  "4",
        "Name":  "Paint Storage",
        "CostRate":  "0.00",
        "Availability":  "0.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    },
    {
        "LocationID":  "5",
        "Name":  "Metal Storage",
        "CostRate":  "0.00",
        "Availability":  "0.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    },
    {
        "LocationID":  "6",
        "Name":  "Miscellaneous Storage",
        "CostRate":  "0.00",
        "Availability":  "0.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    },
    {
        "LocationID":  "7",
        "Name":  "Finished Goods Storage",
        "CostRate":  "0.00",
        "Availability":  "0.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    },
    {
        "LocationID":  "10",
        "Name":  "Frame Forming",
        "CostRate":  "22.50",
        "Availability":  "96.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    },
    {
        "LocationID":  "20",
        "Name":  "Frame Welding",
        "CostRate":  "25.00",
        "Availability":  "108.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    },
    {
        "LocationID":  "30",
        "Name":  "Debur and Polish",
        "CostRate":  "14.50",
        "Availability":  "120.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    },
    {
        "LocationID":  "40",
        "Name":  "Paint",
        "CostRate":  "15.75",
        "Availability":  "120.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    },
    {
        "LocationID":  "45",
        "Name":  "Specialized Paint",
        "CostRate":  "18.00",
        "Availability":  "80.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    },
    {
        "LocationID":  "50",
        "Name":  "Subassembly",
        "CostRate":  "12.25",
        "Availability":  "120.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    },
    {
        "LocationID":  "60",
        "Name":  "Final Assembly",
        "CostRate":  "12.25",
        "Availability":  "120.00",
        "ModifiedDate":  "01 June 2002 00:00:00"
    }
]
‘
  )
where ValueType = ‘string’
group by parent_ID
And we can just then use it in any SQL Expression like this
Select * from TableOfJSONString

You’ll notice that I’ve given you a ‘parent_ID’ to give you the intrinsic order of the rows, since these things can be significant in a JSON document.
Of course, you can do some dynamic SQL to deal with any JSON String, but I don’t like to do this since there is no guarantee that a JSON string represents table data. Also, when you are getting json strings from an application repeatedly, they tend to  carry the same metadata.

Display line and area charts in PHP and MySQL



Most data in any web application is usually sourced from a database. Usually some data transformation is required before we can visualize the required data. Most programmers however wanting to display visualizations or charts shy away from the task as there are a number of intermediate steps required to display the visualization. Morris charts however makes the task easier. We only need to directly pass the MySQL queried rows to the Morris charts javascript and we are done. Morris Charts is one of my favorite tools to display dashboard visualization on the web.
Let us see with a simple example. But first go ahead and download the library.

Example

Our first example will show how to display a line chart. Line charts are usually used to display temporal data over time. The following is a sample CRON log MySQL table used to illustrate the examples. The table is used in one of my web applications to record CRON execution times. Every hours some images are processed by the CRON job which is then recorded in the database table.
CREATE TABLE IF NOT EXISTS `cron` (
  `id` int(11) NOT NULL auto_increment,
  `cron_time` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `images_processed` int(11) default '0',
   KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
First include the stylesheets and script files in the header. Adjust the paths according to your directory structure or directly link to a CDN as shown below. Morris depends on the Raphael library to render graphics. However, if you use the CDN path as given below you do not need to download anything.
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js"></script>
In the following code example I will display the last 24 CRON execution timings as a line chart. First we will get the data from MySQL.
$rows = '';
$query = "SELECT * FROM cron ORDER BY cron_time DESC LIMIT 0, 24";
$result = mysqli_query($con,$query);
$total_rows =  $result->num_rows;
if($result) 
{
    $rows = mysqli_fetch_all($result, MYSQLI_ASSOC);
}
The $rows variable now contains the data array which will be used to display the line chart. The array will be like the following:
Array
(
    [0] => Array
        (
            [id] => 606
            [cron_time] => 2015-02-04 23:05:34
            [images_processed] => 65
        )
 
    [1] => Array
        (
            [id] => 605
            [cron_time] => 2015-02-04 23:00:02
            [images_processed] => 12
        )
.
.
The data is used below to display the chart. Note we need to encode the data to json before we pass it to Morris charts. Morris charts expects the data as a JSON array.
.
.
data: [
    { year: '2008', value: 20 },
    { year: '2009', value: 10 },
    { year: '2010', value: 5 },
    { year: '2011', value: 5 },
    { year: '2012', value: 20 }
  ],
Next we define a div where we want to display the chart.
<div id="morris-line-chart"></div>
<script>
 
Morris.Line({
    // ID of the element in which to draw the chart.
    element: 'morris-line-chart',
 
    // Chart data records -- each entry in this array corresponds to a point
    // on the chart.
    data: <?php echo json_encode($rows);?>,
 
    // The name of the data record attribute that contains x-values.
    xkey: 'cron_time',
 
    // A list of names of data record attributes that contain y-values.
    ykeys: ['images_processed'],
 
    // Labels for the ykeys -- will be displayed when you hover over the
    // chart.
    labels: ['Images Processed'],
 
    lineColors: ['#0b62a4'],
    xLabels: 'hour',
 
    // Disables line smoothing
    smooth: true,
    resize: true
});
</script>
This will display the line chart as below.
morris-chart1
If you need to plot another variable then you can add the same to the javascript data option. Say we need to add a column from the db table like ‘images_failed’ to the graph, we can do the it as below.
<script>
 
Morris.Line({
    // ID of the element in which to draw the chart.
    element: 'morris-line-chart',
 
    // Chart data records -- each entry in this array corresponds to a point
    // on the chart.
    data: <?php echo json_encode($rows);?>,
 
    // The name of the data record attribute that contains x-values.
    xkey: 'cron_time',
 
    // A list of names of data record attributes that contain y-values.
    ykeys: ['images_processed', 'images_failed'],
 
    // Labels for the ykeys -- will be displayed when you hover over the
    // chart.
    labels: ['Images Processed', 'Images Failed'],
 
    // Add different line colors to each variable
    lineColors: ['#0b62a4' '#D58665'],
    xLabels: 'hour',
 
    // Disables line smoothing
    smooth: true,
    resize: true
});
</script>
This will display the 2 variable line chart.
morris-chart2
We can also display the above as a area chart by changing the javascript function name from ‘Morris.Line’ to ‘Morris.Area’. This will display the following without changing any other option.
morris-chart3
There are a variety of options to customize the charts.