473,769 Members | 6,120 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Median Function in mySQL

Hello to all:

I have been searching the web for examples on how to determine a median
value in a mySQL table. I have reviewed the article at
http://mysql.progen.com.tr/doc/en/Gr...functions.html. I am an
experienced VB programmer that has recently moved to PHP/mySQL. My employer
has a text file outputted from a vendor specific software with data.
However it cannot be manipulated because it is text. I created a web that
reads the text file on client, converts it to usable data, inputs to mySQL
table and then reflects HTML pages with desired report. One report
subtracts two times and then my employer wishes a median grouped by another
field. I used the AVG function, but of course this is mean, not Median. My
query is:

$mSql = "SELECT AdmitDoc,
Count(AdmitDoc) as Number_Admits,
sec_to_time(AVG (unix_timestamp (Outdt) -
unix_timestamp( Decdt))) as AVG_Doc_To_Admi t,
sec_to_time(AVG (unix_timestamp (Outdt) -
unix_timestamp( Indt))) as AVG_Total_Stay
from tadmits GROUP BY AdmitDoc";

This query subtracts several wait times in an emergency department and
groups by admitting physician. I would like to have median rather than
mean. AdmitDoc is text field, Outdt, Decdt, Indt are all date/time fields.

Any thoughts?

Thanks,
Ross
Jul 20 '05 #1
4 9715
Ross Contino wrote:
Hello to all:

I have been searching the web for examples on how to determine a median value in a mySQL table. I have reviewed the article at
http://mysql.progen.com.tr/doc/en/Gr...functions.html. I am an
experienced VB programmer that has recently moved to PHP/mySQL. My employer has a text file outputted from a vendor specific software with data.
However it cannot be manipulated because it is text. I created a web that reads the text file on client, converts it to usable data, inputs to mySQL table and then reflects HTML pages with desired report. One report
subtracts two times and then my employer wishes a median grouped by another field. I used the AVG function, but of course this is mean, not Median. My query is:

$mSql = "SELECT AdmitDoc,
Count(AdmitDoc) as Number_Admits,
sec_to_time(AVG (unix_timestamp (Outdt) -
unix_timestamp( Decdt))) as AVG_Doc_To_Admi t,
sec_to_time(AVG (unix_timestamp (Outdt) -
unix_timestamp( Indt))) as AVG_Total_Stay
from tadmits GROUP BY AdmitDoc";

This query subtracts several wait times in an emergency department and groups by admitting physician. I would like to have median rather than mean. AdmitDoc is text field, Outdt, Decdt, Indt are all date/time fields.
Any thoughts?

Thanks,
Ross


There is no MEDIAN() operator in MySQL, so you will have to perform
this operation in several steps...

(1) Count the number of rows in each group
(2) For each group, if the count is odd, the median is the middle row
(when the set is ordered); when the count is even, the median is the
mean of the middle two rows.

In skeletal form...

// get counts for each set of interest...

SELECT AdmitDoc, COUNT(*) AS "Number_Adm its"
FROM tadmits
GROUP BY AdmitDoc

// for each AdmitDoc, work out LIMIT parameters (nb first row =
0)...

$doc = $datRow[ 'AdmitDoc' ];
$count = $datRow[ Number_Admits];

if $count is odd,
$limit1 = intval( $count / 2 );
$limit2 = 1;
else
$limit1 = intval( $count / 2 ) - 1;
$limit2 = 2;

// select middle row(s) from ORDERed set...

SELECT AdmitDoc,
SEC_TO_TIME(UNI X_TIMESTAMP(Out dt)-UNIX_TIMESTAMP( Decdt)) AS
"Doc_To_Adm it"
FROM tadmits
WHERE AdmitDoc = $doc
ORDER BY UNIX_TIMESTAMP( Outdt) - UNIX_TIMESTAMP( Decdt)
LIMIT $limit1, $limit2
if $count is odd,
// only one row...
$datRow = mysql_fetch_arr ay( $datRows, MYSQL_ASSOC );
$median_doc_to_ admit = $datRow[ 'Doc_To_Admit' ];
else
// two rows
$datRow = mysql_fetch_arr ay( $datRows, MYSQL_ASSOC );
$val1 = $datRow[ 'Doc_To_Admit' ];
$datRow = mysql_fetch_arr ay( $datRows, MYSQL_ASSOC );
$val2 = $datRow[ 'Doc_To_Admit' ];
$median_doc_to_ admit = ( $val1 + $val2 ) / 2;

You'll have to do this separately for your two required measures
because they each need a different sort order.

---
Steve

Jul 20 '05 #2

Ross Contino wrote:
Hello to all:

I have been searching the web for examples on how to determine a median value in a mySQL table. I have reviewed the article at
http://mysql.progen.com.tr/doc/en/Gr...functions.html. I am an
experienced VB programmer that has recently moved to PHP/mySQL. My employer has a text file outputted from a vendor specific software with data.
However it cannot be manipulated because it is text. I created a web that reads the text file on client, converts it to usable data, inputs to mySQL table and then reflects HTML pages with desired report. One report
subtracts two times and then my employer wishes a median grouped by another field. I used the AVG function, but of course this is mean, not Median. My query is:

$mSql = "SELECT AdmitDoc,
Count(AdmitDoc) as Number_Admits,
sec_to_time(AVG (unix_timestamp (Outdt) -
unix_timestamp( Decdt))) as AVG_Doc_To_Admi t,
sec_to_time(AVG (unix_timestamp (Outdt) -
unix_timestamp( Indt))) as AVG_Total_Stay
from tadmits GROUP BY AdmitDoc";

This query subtracts several wait times in an emergency department and groups by admitting physician. I would like to have median rather than mean. AdmitDoc is text field, Outdt, Decdt, Indt are all date/time fields.
Any thoughts?

Thanks,
Ross


There is no MEDIAN() operator in MySQL, so you will have to perform
this operation in several steps...

(1) Count the number of rows in each group
(2) For each group, if the count is odd, the median is the middle row
(when the set is ordered); when the count is even, the median is the
mean of the middle two rows.

In skeletal form...

// get counts for each set of interest...

SELECT AdmitDoc, COUNT(*) AS "Number_Adm its"
FROM tadmits
GROUP BY AdmitDoc

// for each AdmitDoc, work out LIMIT parameters (nb first row =
0)...

$doc = $datRow[ 'AdmitDoc' ];
$count = $datRow[ Number_Admits];

if $count is odd,
$limit1 = intval( $count / 2 );
$limit2 = 1;
else
$limit1 = intval( $count / 2 ) - 1;
$limit2 = 2;

// select middle row(s) from ORDERed set...

SELECT AdmitDoc,
SEC_TO_TIME(UNI X_TIMESTAMP(Out dt)-UNIX_TIMESTAMP( Decdt)) AS
"Doc_To_Adm it"
FROM tadmits
WHERE AdmitDoc = $doc
ORDER BY UNIX_TIMESTAMP( Outdt) - UNIX_TIMESTAMP( Decdt)
LIMIT $limit1, $limit2
if $count is odd,
// only one row...
$datRow = mysql_fetch_arr ay( $datRows, MYSQL_ASSOC );
$median_doc_to_ admit = $datRow[ 'Doc_To_Admit' ];
else
// two rows
$datRow = mysql_fetch_arr ay( $datRows, MYSQL_ASSOC );
$val1 = $datRow[ 'Doc_To_Admit' ];
$datRow = mysql_fetch_arr ay( $datRows, MYSQL_ASSOC );
$val2 = $datRow[ 'Doc_To_Admit' ];
$median_doc_to_ admit = ( $val1 + $val2 ) / 2;

You'll have to do this separately for your two required measures
because they each need a different sort order.

---
Steve

Jul 20 '05 #3
Hi Steve:

I ended up writing a php function to select the medians from both values,
but it entailed looping the data frequently and creating a new table to
store it (see below). I could not quite get your method working. Would
your method have only worked via SQL and preclude the constant looping and
need for a table to store the medians?

Median functions:

/***********func tion block********** ***************/
function GetMedian_Dec($ myDoc, $No_Admits)
{
$MyMedian = "";
$LimitSql = "SELECT
SEC_TO_TIME(UNI X_TIMESTAMP(Out dt)-UNIX_TIMESTAMP( Decdt))AS Doc_To_Admit
FROM tadmits WHERE AdmitDoc = '" . $myDoc . "'" . "
ORDER BY Doc_To_Admit";
$result2 = mysql_query($Li mitSql);
$i=1;
$FirstTime = "";
$SecondTime = "";
If (($No_Admits % 2)==1){ //odd number of admissions
$MyCounter = intval(($No_Adm its / 2) + 1);
while($row3=mys ql_fetch_assoc( $result2)){
if ($i ==$MyCounter){
$UpSql = "UPDATE tersummary SET Median_MD_To_Ad mit = '"
.. $row3['Doc_To_Admit'] . "' WHERE AdmitDoc = '" . $myDoc . "'";
mysql_query($Up Sql);
}//end if
$i++;
}//end while
}
else { //even number of admissions
$MyCounter = intval($No_Admi ts / 2);
while($row3=mys ql_fetch_assoc( $result2)){
if ($i==$MyCounter ){
$FirstTime = $row3['Doc_To_Admit'];
}//end if
if ($i==$MyCounter + 1){
$SecondTime = $row3['Doc_To_Admit'];
}//end if
$i++;
}//end while
$AvgVal = (strtotime($Fir stTime) + strtotime($Seco ndTime)) /
2;
$UpSql = "UPDATE tersummary SET Median_MD_To_Ad mit = '" .
date("H:i:s",$A vgVal) . "' WHERE AdmitDoc = '" . $myDoc . "'";
mysql_query($Up Sql);
}
}
function GetMedian_Stay( $myDoc, $No_Admits)
{ $MyMedian = "";
$LimitSql = "SELECT
SEC_TO_TIME(UNI X_TIMESTAMP(Out dt)-UNIX_TIMESTAMP( Indt))AS Total_Stay
FROM tadmits WHERE AdmitDoc = '" . $myDoc . "'" . "
ORDER BY Total_Stay";
$result2 = mysql_query($Li mitSql);
$i=1;
$FirstTime = "";
$SecondTime = "";
If (($No_Admits % 2)==1){ //odd number of admissions
$MyCounter = intval(($No_Adm its / 2) + 1);
while($row3=mys ql_fetch_assoc( $result2)){
if ($i ==$MyCounter){
$UpSql = "UPDATE tersummary SET Median_Total_St ay = '"
.. $row3['Total_Stay'] . "' WHERE AdmitDoc = '" . $myDoc . "'";
mysql_query($Up Sql);
}//end if
$i++;
}//end while
}
else { //even number of admissions
$MyCounter = intval($No_Admi ts / 2);
while($row3=mys ql_fetch_assoc( $result2)){
if ($i==$MyCounter ){
$FirstTime = $row3['Total_Stay'];
}//end if
if ($i==$MyCounter + 1){
$SecondTime = $row3['Total_Stay'];
}//end if
$i++;
}//end while
$AvgVal = (strtotime($Fir stTime) + strtotime($Seco ndTime)) /
2;
$UpSql = "UPDATE tersummary SET Median_Total_St ay = '" .
date("H:i:s",$A vgVal) . "' WHERE AdmitDoc = '" . $myDoc . "'";
mysql_query($Up Sql);
}//end if/else
}
/*************en d block********** *************** ***/
Thanks,
Ross

There is no MEDIAN() operator in MySQL, so you will have to perform
this operation in several steps...

(1) Count the number of rows in each group
(2) For each group, if the count is odd, the median is the middle row
(when the set is ordered); when the count is even, the median is the
mean of the middle two rows.

In skeletal form...

// get counts for each set of interest...

SELECT AdmitDoc, COUNT(*) AS "Number_Adm its"
FROM tadmits
GROUP BY AdmitDoc

// for each AdmitDoc, work out LIMIT parameters (nb first row =
0)...

$doc = $datRow[ 'AdmitDoc' ];
$count = $datRow[ Number_Admits];

if $count is odd,
$limit1 = intval( $count / 2 );
$limit2 = 1;
else
$limit1 = intval( $count / 2 ) - 1;
$limit2 = 2;

// select middle row(s) from ORDERed set...

SELECT AdmitDoc,
SEC_TO_TIME(UNI X_TIMESTAMP(Out dt)-UNIX_TIMESTAMP( Decdt)) AS
"Doc_To_Adm it"
FROM tadmits
WHERE AdmitDoc = $doc
ORDER BY UNIX_TIMESTAMP( Outdt) - UNIX_TIMESTAMP( Decdt)
LIMIT $limit1, $limit2
if $count is odd,
// only one row...
$datRow = mysql_fetch_arr ay( $datRows, MYSQL_ASSOC );
$median_doc_to_ admit = $datRow[ 'Doc_To_Admit' ];
else
// two rows
$datRow = mysql_fetch_arr ay( $datRows, MYSQL_ASSOC );
$val1 = $datRow[ 'Doc_To_Admit' ];
$datRow = mysql_fetch_arr ay( $datRows, MYSQL_ASSOC );
$val2 = $datRow[ 'Doc_To_Admit' ];
$median_doc_to_ admit = ( $val1 + $val2 ) / 2;

You'll have to do this separately for your two required measures
because they each need a different sort order.

---
Steve

Jul 20 '05 #4

Ross:

The outline I suggested uses PHP to control the loop through each
AdmitDoc, and to create the text of the query to find the median
value(s), so it is not a SQL-only solution. The main advantage it has
over your code is that using a LIMIT clause fetches only 1 or 2 rows
regardless of how many are in the table, which could be a sigificant
optimisation if you have thousands of rows.

Which bit wasn't working for you?

Here's a self-contained worked example...
<?php

$t_strServer = 'localhost';
$t_strUser = 'root';
$t_strPassword = '';
$t_objSQLConnec tion = mysql_connect( $t_strServer, $t_strUser,
$t_strPassword );
mysql_select_db ( 'TEST', $t_objSQLConnec tion );
mysql_query( 'DROP TABLE IF EXISTS tadmits', $t_objSQLConnec tion );
mysql_query( 'CREATE TABLE tadmits ( id INT, AdmitDoc VARCHAR(2), outdt
DATETIME, decdt DATETIME )', $t_objSQLConnec tion );
mysql_query( 'INSERT INTO tadmits VALUES ( 1, "aa", "20041203000000 ",
"20041201000000 " )', $t_objSQLConnec tion );
mysql_query( 'INSERT INTO tadmits VALUES ( 2, "aa", "20041204000000 ",
"20041202000000 " )', $t_objSQLConnec tion );
mysql_query( 'INSERT INTO tadmits VALUES ( 3, "aa", "20041206000000 ",
"20041202000000 " )', $t_objSQLConnec tion );
mysql_query( 'INSERT INTO tadmits VALUES ( 4, "bb", "20041208000000 ",
"20041203000000 " )', $t_objSQLConnec tion );
mysql_query( 'INSERT INTO tadmits VALUES ( 5, "bb", "20041211000000 ",
"20041204000000 " )', $t_objSQLConnec tion );
mysql_query( 'INSERT INTO tadmits VALUES ( 6, "cc", "20041210000000 ",
"20041206000000 " )', $t_objSQLConnec tion );
mysql_query( 'INSERT INTO tadmits VALUES ( 7, "cc", "20041213000000 ",
"20041203000000 " )', $t_objSQLConnec tion );
mysql_query( 'INSERT INTO tadmits VALUES ( 8, "cc", "20041216000000 ",
"20041205000000 " )', $t_objSQLConnec tion );
mysql_query( 'INSERT INTO tadmits VALUES ( 9, "cc", "20041223000000 ",
"20041201000000 " )', $t_objSQLConnec tion );
mysql_query( 'INSERT INTO tadmits VALUES (10, "cc", "20041222000000 ",
"20041207000000 " )', $t_objSQLConnec tion );
mysql_query( 'INSERT INTO tadmits VALUES (11, "dd", "20041226000000 ",
"20041202000000 " )', $t_objSQLConnec tion );
mysql_query( 'INSERT INTO tadmits VALUES (12, "ee", "20041214000000 ",
"20041203000000 " )', $t_objSQLConnec tion );

print "Doctor:\tMedia n days\n\n";

$t_datRows = mysql_query( 'SELECT AdmitDoc, COUNT(*) as "Number_Adm its"
FROM tadmits GROUP BY AdmitDoc', $t_objSQLConnec tion );
while( $t_datRow = mysql_fetch_arr ay( $t_datRows, MYSQL_ASSOC ) )
{
$t_strAdmitDoc = $t_datRow[ 'AdmitDoc' ];
$t_lngNumber_Ad mits = $t_datRow[ 'Number_Admits' ];
if( $t_lngNumber_Ad mits % 2 == 0 )
{
// even...
$t_lngLimit1 = intval( $t_lngNumber_Ad mits / 2 ) - 1;
$t_lngLimit2 = 2;
}
else
{
// odd...
$t_lngLimit1 = intval( $t_lngNumber_Ad mits / 2 );
$t_lngLimit2 = 1;
}

$t_datRows2 = mysql_query( 'SELECT AdmitDoc, UNIX_TIMESTAMP( outdt) -
UNIX_TIMESTAMP( decdt) AS "Doc_To_Adm it" FROM tadmits WHERE AdmitDoc =
"' . $t_strAdmitDoc . '" ORDER BY UNIX_TIMESTAMP( outdt) -
UNIX_TIMESTAMP( decdt) LIMIT ' . $t_lngLimit1 . ',' . $t_lngLimit2,
$t_objSQLConnec tion );

if( $t_lngNumber_Ad mits % 2 == 0 )
{
// even...
$t_datRow2 = mysql_fetch_arr ay( $t_datRows2, MYSQL_ASSOC );
$t_dblValue1 = $t_datRow2[ 'Doc_To_Admit' ];
$t_datRow2 = mysql_fetch_arr ay( $t_datRows2, MYSQL_ASSOC );
$t_dblValue2 = $t_datRow2[ 'Doc_To_Admit' ];
$t_lngMedianTim e = ( $t_dblValue1 + $t_dblValue2 ) / 2;
}
else
{
// odd...
$t_datRow2 = mysql_fetch_arr ay( $t_datRows2, MYSQL_ASSOC );
$t_lngMedianTim e = $t_datRow2[ 'Doc_To_Admit' ];
}

mysql_free_resu lt( $t_datRows2 );

// seconds to decimal days...
$t_lngMedianTim e = $t_lngMedianTim e / ( 3600 * 24 );

print "$t_strAdmitDoc :\t$t_lngMedian Time days\n\n";

}

mysql_free_resu lt( $t_datRows );

?>
I get this:

Doctor: Median days

aa: 2 days

bb: 6 days

cc: 11 days

dd: 24 days

ee: 11 days

---
Steve

Jul 20 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
20179
by: michael way | last post by:
I read the follow query about calculating median posted by Daivd Porta on 10/8/03. CREATE TABLE SomeValues (keyx CHAR(1) PRIMARY KEY, valuex INTEGER NOT NULL) INSERT INTO SomeValues VALUES ('A',1) INSERT INTO SomeValues VALUES ('B',2) INSERT INTO SomeValues VALUES ('C',3) INSERT INTO SomeValues VALUES ('D',4)
2
2526
by: Bob | last post by:
I have been looking at the code for MedianFind(pDte As String) from the following thread from UtterAccess.com: "Finding Median average grouped by field" I have been able to get it to run using Northwind no problem. I am having some trouble though converting it to my specific purpose which may be less complicated than the solution Bob (raskew) provided in the thread. Here are my specifics:
8
14113
by: nick.vitone | last post by:
Hi, I'm somewhat of a novice at Access, and I have no experience programming whatsoever. I'm attempting to calculate the statistical median in a query. I need to "Group by" one column and find the median of the another, though I'm not sure how. I've been able to add the "Median" function (from the Microsoft Access Help Archive), but I can't figure out how to incorporate that into the Totals. Do I need to use the "expression" and...
4
8180
by: uspensky | last post by:
I have a table (cars) with 3 fields: VIN, Class, sell_price 101, sports, 10000 102, sports, 11000 103, luxury, 9000 104, sports, 11000 105, sports, 11000 106, luxury, 5000 107, sports, 11000
5
9436
by: jonm4102 | last post by:
I'm trying to calculate the median of some numerical data. The data can only be found in a query (henceforth query 1) field I previously made, and I would prefer to calculate the median in a new query it without making a table out of query 1. I can't find a median function in the "Total" field, so is there so way to make an expression to calculate the median of the orignial data from query 1 in my new query? Also, what does name by...
1
6504
by: Jaime Leivers | last post by:
Here's a median function in access that you can call in any query. You could change this to any excel function you wanted. Most people can find the windows help file that says how to call an excel function but don't know how to pass an array of the recordset they made into that function. This uses GetRows that nicely creates an array that can be passed into excel. I have this data table for testing. The table name is TestData ...
3
4672
by: Scott | last post by:
I need to take the median from a field of records in a report. Can someone shed the light how to do it. Thanks, Scott
3
5161
by: mehwishobaid | last post by:
i dont know wat is wrong with my code. when i compile. i get the error saying line 29: error: expression must have pointer-to-object type #include <iostream> using namespace std; #include <vector> double* median(double a, int a_size) // Function Median
6
4098
by: rrstudio2 | last post by:
I am using the following vba code to calculate the median of a table in MS Access: Public Function MedianOfRst(RstName As String, fldName As String) As Double 'This function will calculate the median of a recordset. The field must be a number value. Dim MedianTemp As Double Dim RstOrig As Recordset Set RstOrig = CurrentDb.OpenRecordset(RstName, dbOpenDynaset)
0
9590
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9424
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10223
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10051
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10000
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9866
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
6675
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
1
3968
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
2815
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.