{"id":18929642,"url":"https://github.com/thecodingmachine/database.dbstats","last_synced_at":"2026-03-16T15:30:18.238Z","repository":{"id":6036158,"uuid":"7260456","full_name":"thecodingmachine/database.dbstats","owner":"thecodingmachine","description":"This package provides a set of classes that can be used to create \"aggregation\" table containing high-level statistics about your database. The DB_Stats can be used to initalize the aggregation tables and automatically create triggers that will update data in real time.","archived":false,"fork":false,"pushed_at":"2015-05-18T15:27:38.000Z","size":192,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":8,"default_branch":"3.0","last_synced_at":"2025-02-16T12:30:26.033Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"theforeman/hammer-cli-foreman-tasks","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thecodingmachine.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-12-20T16:11:57.000Z","updated_at":"2015-05-18T15:27:39.000Z","dependencies_parsed_at":"2022-08-22T20:31:20.164Z","dependency_job_id":null,"html_url":"https://github.com/thecodingmachine/database.dbstats","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thecodingmachine%2Fdatabase.dbstats","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thecodingmachine%2Fdatabase.dbstats/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thecodingmachine%2Fdatabase.dbstats/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thecodingmachine%2Fdatabase.dbstats/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thecodingmachine","download_url":"https://codeload.github.com/thecodingmachine/database.dbstats/tar.gz/refs/heads/3.0","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239927825,"owners_count":19719835,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T11:34:07.520Z","updated_at":"2026-03-16T15:30:18.171Z","avatar_url":"https://github.com/thecodingmachine.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"#DB_Stats\n\n##Introduction\n\n`DB_Stats` is a PHP library designed to compute statistics on MySQL tables. It enables multi-dimensional analyses of a table (just like in OLAP although less powerfull).\nWhen you want to analyse data in a table, you plug `DB_Stats` on that table. The table containing the data to analyse is called the \"source table\".\n`DB_Stats` will generate a roll-up table (also called \"destination table\" or \"stats table\"), containing aggregated stats from the initial table. `DB_Stats` will also generate triggers\non the source table. Whenever data is inserted, updated or deleted from the source table, the triggers will automatically update statistics in the roll-up table.\n\nThen, you can query the data in this table using the \u003ca href=\"DB_Stats_Query.html\"\u003e`DB_Stats_Query`\u003c/a\u003e class, that provides query capabilities on DB_Stats tables.\n\n##Understanding DB_Stats\n\nIn order to use `DB_Stats`, it is important to understand the way `DB_Stats` works.\nHere is a sample source table. The table below contains persons from a medical record.\n\n\u003ctable border=\"1\"\u003e\n\t\u003ctr\u003e\n\t\t\u003cth\u003eId\u003c/th\u003e\n\t\t\u003cth\u003eName\u003c/th\u003e\n\t\t\u003cth\u003eJob\u003c/th\u003e\n\t\t\u003cth\u003eCountry\u003c/th\u003e\n\t\t\u003cth\u003eCity\u003c/th\u003e\n\t\t\u003cth\u003eCreationDate\u003c/th\u003e\n\t\t\u003cth\u003eAge\u003c/th\u003e\n\t\t\u003cth\u003eWeight\u003c/th\u003e\n\t\t\u003cth\u003eSize\u003c/th\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e1\u003c/td\u003e\n\t\t\u003ctd\u003eAlice\u003c/td\u003e\n\t\t\u003ctd\u003eTeacher\u003c/td\u003e\n\t\t\u003ctd\u003eFrance\u003c/td\u003e\n\t\t\u003ctd\u003eParis\u003c/td\u003e\n\t\t\u003ctd\u003e2009-06-22 12:15:00\u003c/td\u003e\n\t\t\u003ctd\u003e25\u003c/td\u003e\n\t\t\u003ctd\u003e50\u003c/td\u003e\n\t\t\u003ctd\u003e170\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e2\u003c/td\u003e\n\t\t\u003ctd\u003eBob\u003c/td\u003e\n\t\t\u003ctd\u003eLawyer\u003c/td\u003e\n\t\t\u003ctd\u003eFrance\u003c/td\u003e\n\t\t\u003ctd\u003eMarseille\u003c/td\u003e\n\t\t\u003ctd\u003e2009-07-01 05:05:05\u003c/td\u003e\n\t\t\u003ctd\u003e35\u003c/td\u003e\n\t\t\u003ctd\u003e75\u003c/td\u003e\n\t\t\u003ctd\u003e175\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e3\u003c/td\u003e\n\t\t\u003ctd\u003eCharlie\u003c/td\u003e\n\t\t\u003ctd\u003eTeacher\u003c/td\u003e\n\t\t\u003ctd\u003eUSA\u003c/td\u003e\n\t\t\u003ctd\u003eNew-York\u003c/td\u003e\n\t\t\u003ctd\u003e2009-07-05 13:15:00\u003c/td\u003e\n\t\t\u003ctd\u003e55\u003c/td\u003e\n\t\t\u003ctd\u003e70\u003c/td\u003e\n\t\t\u003ctd\u003e180\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e4\u003c/td\u003e\n\t\t\u003ctd\u003eDebbie\u003c/td\u003e\n\t\t\u003ctd\u003eIT Consultant\u003c/td\u003e\n\t\t\u003ctd\u003eUSA\u003c/td\u003e\n\t\t\u003ctd\u003eSan Francisco\u003c/td\u003e\n\t\t\u003ctd\u003e2009-08-02 18:00:00\u003c/td\u003e\n\t\t\u003ctd\u003e65\u003c/td\u003e\n\t\t\u003ctd\u003e65\u003c/td\u003e\n\t\t\u003ctd\u003e175\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e5\u003c/td\u003e\n\t\t\u003ctd\u003eEve\u003c/td\u003e\n\t\t\u003ctd\u003eIT Consultant\u003c/td\u003e\n\t\t\u003ctd\u003eUSA\u003c/td\u003e\n\t\t\u003ctd\u003eSan Francisco\u003c/td\u003e\n\t\t\u003ctd\u003e2009-08-02 19:00:00\u003c/td\u003e\n\t\t\u003ctd\u003e30\u003c/td\u003e\n\t\t\u003ctd\u003e55\u003c/td\u003e\n\t\t\u003ctd\u003e185\u003c/td\u003e\n\t\u003c/tr\u003e\n\n\u003c/table\u003e\n\nThere are a few columns to describe these patients:\n\n- The name\n- The job\n- The location (country/city)\n- The date the user was added to the database\n- A set of data about the person (age / weight (in kg) / size (in cm))\n\nWe will split those columns in 2 sets: \u003cem\u003edimensions\u003c/em\u003e and \u003cem\u003evalues\u003c/em\u003e. Dimensions are the \"things\" we will filter upon. Values are the \"things\" we will sum up to make stats.\nIn this sample, we will choose those dimensions:\n\n- Job\n- Location (Country / City)\n- Creation date (Year / Month / Day)\n\t\nAs you noticed, a \u003cem\u003edimension\u003c/em\u003e can contain several columns (in this sample, the location is made of 2 columns and the creation date is made of 3 columns).\nThe values will be:\n\n- Sum of Age\n- Sum of Weight\n- Sum of Size\n- Number of patients\n\nComputing the average:\nValues are numbers that are summed from the original dataset. In this sample, we might want the average value for the age of the patients in the database. However, `DB_Stats`\ndoes only provide us with the sum of the age. Hopefully, we can also compute the number of patients (by adding 1 to a stats row each time a row is inserted). Therefore,\nwe can compute the average by dividing the sum of the ages by the number of patients.\n\nWith those dimensions and those values, the roll-up table will certainly look like this:\n\n\u003ctable border=\"1\"\u003e\n\t\u003ctr\u003e\n\t\t\u003cth\u003eId\u003c/th\u003e\n\t\t\u003cth\u003eJob\u003c/th\u003e\n\t\t\u003cth\u003eCountry\u003c/th\u003e\n\t\t\u003cth\u003eCity\u003c/th\u003e\n\t\t\u003cth\u003eYear\u003c/th\u003e\n\t\t\u003cth\u003eMonth\u003c/th\u003e\n\t\t\u003cth\u003eDay\u003c/th\u003e\n\t\t\u003cth\u003eSumAge\u003c/th\u003e\n\t\t\u003cth\u003eSumWeight\u003c/th\u003e\n\t\t\u003cth\u003eSumSize\u003c/th\u003e\n\t\t\u003cth\u003eCnt\u003c/th\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e1\u003c/td\u003e\n\t\t\u003ctd\u003eTeacher\u003c/td\u003e\n\t\t\u003ctd\u003eFrance\u003c/td\u003e\n\t\t\u003ctd\u003eParis\u003c/td\u003e\n\t\t\u003ctd\u003e2009\u003c/td\u003e\n\t\t\u003ctd\u003e06\u003c/td\u003e\n\t\t\u003ctd\u003e22\u003c/td\u003e\n\t\t\u003ctd\u003e25\u003c/td\u003e\n\t\t\u003ctd\u003e50\u003c/td\u003e\n\t\t\u003ctd\u003e170\u003c/td\u003e\n\t\t\u003ctd\u003e1\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e2\u003c/td\u003e\n\t\t\u003ctd\u003eLawyer\u003c/td\u003e\n\t\t\u003ctd\u003eFrance\u003c/td\u003e\n\t\t\u003ctd\u003eMarseille\u003c/td\u003e\n\t\t\u003ctd\u003e2009\u003c/td\u003e\n\t\t\u003ctd\u003e07\u003c/td\u003e\n\t\t\u003ctd\u003e01\u003c/td\u003e\n\t\t\u003ctd\u003e35\u003c/td\u003e\n\t\t\u003ctd\u003e75\u003c/td\u003e\n\t\t\u003ctd\u003e175\u003c/td\u003e\n\t\t\u003ctd\u003e1\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e3\u003c/td\u003e\n\t\t\u003ctd\u003eTeacher\u003c/td\u003e\n\t\t\u003ctd\u003eUSA\u003c/td\u003e\n\t\t\u003ctd\u003eNew-York\u003c/td\u003e\n\t\t\u003ctd\u003e2009\u003c/td\u003e\n\t\t\u003ctd\u003e07\u003c/td\u003e\n\t\t\u003ctd\u003e05\u003c/td\u003e\n\t\t\u003ctd\u003e55\u003c/td\u003e\n\t\t\u003ctd\u003e70\u003c/td\u003e\n\t\t\u003ctd\u003e180\u003c/td\u003e\n\t\t\u003ctd\u003e1\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e4\u003c/td\u003e\n\t\t\u003ctd\u003eIT Consultant\u003c/td\u003e\n\t\t\u003ctd\u003eUSA\u003c/td\u003e\n\t\t\u003ctd\u003eSan Francisco\u003c/td\u003e\n\t\t\u003ctd\u003e2009\u003c/td\u003e\n\t\t\u003ctd\u003e08\u003c/td\u003e\n\t\t\u003ctd\u003e02\u003c/td\u003e\n\t\t\u003ctd\u003e95\u003c/td\u003e\n\t\t\u003ctd\u003e120\u003c/td\u003e\n\t\t\u003ctd\u003e360\u003c/td\u003e\n\t\t\u003ctd\u003e2\u003c/td\u003e\n\t\u003c/tr\u003e\n\u003c/table\u003e\n\nIn this sample, the data has been grouped by all the columns. Since there are 2 patients that are both IT Consultant, live in the USA at San Francisco and where created in 2009-08-02, their data is summed.\nOf course, this can seem pretty useless, since a simple \"GROUP BY\" request does exactly the same think. But keep in mind that:\n\n- this data is updated in real time, so the source table can contain millions of records and you can still get instant resuls\n- `DB_Stats` provide much more, as we will see below\n\nIndeed, `DB_Stats` does not only provide stats on one level of \"GROUP BY\", it will also perform all the possible GROUP BYs according to any relevant combination of\ncolumns. So the roll-up table will also contain this:\n\n\u003ctable border=\"1\"\u003e\n\t\u003ctr\u003e\n\t\t\u003cth\u003eId\u003c/th\u003e\n\t\t\u003cth\u003eJob\u003c/th\u003e\n\t\t\u003cth\u003eCountry\u003c/th\u003e\n\t\t\u003cth\u003eCity\u003c/th\u003e\n\t\t\u003cth\u003eYear\u003c/th\u003e\n\t\t\u003cth\u003eMonth\u003c/th\u003e\n\t\t\u003cth\u003eDay\u003c/th\u003e\n\t\t\u003cth\u003eSumAge\u003c/th\u003e\n\t\t\u003cth\u003eSumWeight\u003c/th\u003e\n\t\t\u003cth\u003eSumSize\u003c/th\u003e\n\t\t\u003cth\u003eCnt\u003c/th\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e5\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003e210\u003c/td\u003e\n\t\t\u003ctd\u003e365\u003c/td\u003e\n\t\t\u003ctd\u003e885\u003c/td\u003e\n\t\t\u003ctd\u003e5\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e6\u003c/td\u003e\n\t\t\u003ctd\u003eTeacher\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003e80\u003c/td\u003e\n\t\t\u003ctd\u003e120\u003c/td\u003e\n\t\t\u003ctd\u003e370\u003c/td\u003e\n\t\t\u003ctd\u003e2\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e7\u003c/td\u003e\n\t\t\u003ctd\u003eTeacher\u003c/td\u003e\n\t\t\u003ctd\u003eFrance\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003eNULL\u003c/td\u003e\n\t\t\u003ctd\u003e25\u003c/td\u003e\n\t\t\u003ctd\u003e500\u003c/td\u003e\n\t\t\u003ctd\u003e170\u003c/td\u003e\n\t\t\u003ctd\u003e1\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e...\u003c/td\u003e\n\t\t\u003ctd\u003e...\u003c/td\u003e\n\t\t\u003ctd\u003e...\u003c/td\u003e\n\t\t\u003ctd\u003e...\u003c/td\u003e\n\t\t\u003ctd\u003e...\u003c/td\u003e\n\t\t\u003ctd\u003e...\u003c/td\u003e\n\t\t\u003ctd\u003e...\u003c/td\u003e\n\t\t\u003ctd\u003e...\u003c/td\u003e\n\t\t\u003ctd\u003e...\u003c/td\u003e\n\t\t\u003ctd\u003e...\u003c/td\u003e\n\t\t\u003ctd\u003e...\u003c/td\u003e\n\t\u003c/tr\u003e\n\u003c/table\u003e\n\nIn order to read this, you must understand that when a column containes \"NULL\", it means the values contain are sumed for any possible values of the column.\nSo for instance, the row with ID \"5\" has NULL in all the columns related to the dimensions. Therefore, it will contain the sum of all the patients. So we can see instantly that we have 5 patients in database\nand that the sum of there age is 210. Therefore, the average age is 42.\nRow with ID \"7\" contains all the patients who are Teacher and who live in France, etc...\n\n\u003cem\u003eImportant!\u003c/em\u003e\u003cbr/\u003e\nAll the combinations of \"NULL\" columns are available according to there dimensions. \u003cb\u003eA dimension is made of an ordered list of columns.\u003c/b\u003e This means that for the dimension YEAR/MONTH/DAY, we can \nsearch for stats regarding patients created in 2009, we can search for stats regarding patients created in June 2009, but we CANNOT search for stats regarding patients created in June whatever the year.\n\n\n\n\n##Using the library\n\nNow that we understand the theory, let's jump into the coding.\n\nFirst, `DB_Stats` is compatible with the Mouf framework, so any object created below by code can also be created using the Mouf graphical interface.\n\n###Creating the DB_Stats object\nIn this part, we will focus on creating the objects programmatically.\nIn order to create a roll-up table, we need to define a `DB_Stats` object.\n\n\n```\n+--------------------------------------------------------+\n| DB_Stats                                               |\n+--------------------------------------------------------+\n| + setDbConnection(DB_Connection connection)            |\n| + setSourceTable(string tableName)                     |\n| + setStatsTable(string tableName)                      |\n| + setDimensions(array\u0026lt;DB_Dimension\u0026gt; dimensions)        |\n| + addDimension(DB_Dimension dimension)                 |\n| + setValues(array\u0026lt;DB_Stat_Column\u0026gt; values)              |\n| + addValue(DB_Stat_Column value)                       |\n| + createStatsTable()                                   |\n| + fillTable()                                          |\n| + createTrigger()                                      |\n+--------------------------------------------------------+\n```\n\nThe first step is to get a connection to the database. This is done via the `DB_Connection object`:\n\n```php\n$conn = new DB_MySqlConnection();\n$conn-\u0026gt;setHost(\"localhost\");\n$conn-\u0026gt;setDbName(\"myDb\");\n$conn-\u0026gt;setUser(\"root\");\n$conn-\u0026gt;connect();\n\n$dbStats = new DB_Stats($conn, \"patients\", \"patientsrollup\");\n```\n\nWith this piece of code, we create a connection to MySql, we create a Db_Stats object and we connect it to the connection.\nThen, we set the source table and the rollup table.\n\n\u003ch3\u003eCreating the dimensions\u003c/h3\u003e\nNow, we need to set the dimensions. For this, we will use the `DB_Stats-\u0026gt;addDimension` method. This method takes a DB_Dimension object in argument.\n\n```\n+--------------------------------------------------------+\n| DB_Dimension                                           |\n+--------------------------------------------------------+\n| + setColumns(array\u0026lt;DB_StatColumn\u0026gt; columns)             |\n| + addColumn(DB_StatColumn column)                      |\n+--------------------------------------------------------+\n```\n\nAnd a dimension is made of a set of columns.\n\n```\n+--------------------------------------------------------+\n| DB_StatColumn                                          |\n+--------------------------------------------------------+\n| + setColumnName(string name)                           |\n| + setDataOrigin(string dataOrigin)                     |\n| + setType(string type)                                 |\n+--------------------------------------------------------+\n```\n\nHere is a sample of declaration for the \"Job\" dimension:\n\n```php\n$jobColumn = new DB_StatColumn();\n$jobColumn-\u0026gt;setColumnName(\"job\");\n$jobColumn-\u0026gt;setDataOrigin(\"[statcol].job\");\n$jobColumn-\u0026gt;setType(\"VARCHAR(255)\");\n\n$jobDimension = new DB_Dimension();\n$jobDimension-\u0026gt;addColumn($jobColumn);\n\n$dbStats-\u0026gt;addDimension($jobDimension);\n```\n\nIt is important to understand that each \"column\" declared in a dimension will result in a column created in the rollup table.\nThe type of the column is set using the `DB_StatColumn-\u0026gt;setType` method.\nSo by creating the \"job\" dimension, we add the \"job\" column to the rollup table. The \u003cem\u003edataOrigin\u003c/em\u003e refers to the \nplace the data comes from. It will come from the \"job\" column of the source table. We refer to this column as \"[statcol].job\".\n\n**Important!**\nWhen refering to a column from the source table, ALWAYS prefix the name of the column by \"[statcol].\". \n\n###Creating the dimensions - advanced\n\nWe created a easy dimension, with only one column, but many dimensions are not that easy. Let's focus on the date dimension.\nIn the \"date\" dimension, a single field in the source table provides data for many columns. Here is the dimension:\n\n```php\n$year = new DB_StatColumn();\n$year-\u0026gt;setColumnName(\"year\");\n$year-\u0026gt;setDataOrigin(\"YEAR([statcol].CreationDate)\");\n$year-\u0026gt;setType(\"INT\");\n\n$month = new DB_StatColumn();\n$month-\u0026gt;setColumnName(\"month\");\n$month-\u0026gt;setDataOrigin(\"MONTH([statcol].CreationDate)\");\n$month-\u0026gt;setType(\"INT\");\n\n$day = new DB_StatColumn();\n$day-\u0026gt;setColumnName(\"day\");\n$day-\u0026gt;setDataOrigin(\"DAY([statcol].CreationDate)\");\n$day-\u0026gt;setType(\"INT\");\n\n$dateDimension = new DB_Dimension();\n// Remember the order is important. We add the year first, then the month and finally the day\n$dateDimension-\u0026gt;addColumn($year);\n$dateDimension-\u0026gt;addColumn($month);\n$dateDimension-\u0026gt;addColumn($day);\n\n$dbStats-\u0026gt;addDimension($dateDimension);\n```\n\nIn this sample, have a look at the dataOrigin. It is dynamically computed using MySql functions. For instance, `YEAR([statcol].CreationDate)` will\nreturn the year that is stored in the `CreationDate` column.\n\n##Creating the values\n\nWe created the dimension columns, now, we need to create the values.\nThe values are simply a set of `DB_StatColumn` objects bound to the DB_Stats object.\n\nHere is an example:\n```php\n$totalAge = new DB_StatColumn();\n$totalAge-\u0026gt;setColumnName(\"sumage\");\n$totalAge-\u0026gt;setDataOrigin(\"[statcol].age\");\n$totalAge-\u0026gt;setType(\"BIGINT\");\n\n$dbStats-\u0026gt;addValue($totalAge);\n```\n\nThis will create a \"sumage\" column in the stats table that will contain the sum of the ages of the patients. The dataOrigin is similar to the one we saw with the dimensions.\nYou MUST prefix any column from the source table with \"[statcol].\".\n\nYou can use any MySql function in the dataOrigin field to perform transformations. You can also use\nserveral columns from the source table, etc...\nFor instance, we could compute the sum of the body mass indexes, using a dataOrigin computed this way:\n```php\n$bodyMassIndex-\u0026gt;setDataOrigin(\"[statcol].weight/([statcol].height*[statcol].height)\");\n```\n\nSpecial case:\nThe \"cnt\" column is a special case. Indeed, the column does not refer to any field, it is just incremented by one when a new row is added. In this case, you can just provide\n\"1\" as a value for dataOrigin. Therefore, 1 will be added to the \"cnt\" column each time a new row matches the stats.\n\n```php\n$cnt = new DB_StatColumn();\n$cnt-\u0026gt;setColumnName(\"cnt\");\n$cnt-\u0026gt;setDataOrigin(\"1\");\n$cnt-\u0026gt;setType(\"BIGINT\");\n\n$dbStats-\u0026gt;addValue($cnt);\n```\n\n###Creating the tables and triggers\n\nOur `DB_Stats` object is now fully configured. We just have to execute a few methods to set the system up.\n\n```php\n// Creates the stats table\n$dbStats-\u0026gt;createStatsTable();\n\n// Fills the table with stats\n$dbStats-\u0026gt;fillTable();\n\n// Creates the triggers\n$dbStats-\u0026gt;createTrigger();\n```\n\nThe `DB_Stats-\u0026gt;createStatsTable` will create the table in the database.\nThe `DB_Stats-\u0026gt;fillTable` will purge the stats table and fill it with freshly computed stats from the source table. Beware, if the source table is big, this operation might take some time!\nThe `DB_Stats-\u0026gt;createTrigger` will create the triggers on the source table that will automatically update the stats table.\n\nThat's it! Now, we have a perfectly functional rollup table that we can query to retrieve stats from the source table.\nThe rollup table is already indexed and will deliver results at the speed of light!\n\nYou can perform queries directly on that table, or you can use the \u003ca href=\"DB_Stats_Query.html\"\u003e`DB_Stats_Query`\u003c/a\u003e class that is designed for performing queries on stats tables.\n\n##Known limitations\n\nDue to the way DB_Stats works, you should be careful when developing with DB_Stats about those issues:\n\n- DB_Stats does not support performing stats on several tables. You cannot JOIN several tables and compute stats on those JOINed tables (so it is impossible to draw a snowflake or star schema like in OLAP)\n- Since DB_Stats writes in the stats table in real time, the writing process in the source table might be severely slowed, especially if you have a big number of dimensions. Try to avoid to many dimensions, or be sure to use those on a table that is not modified to often.\n- Values can only be added. You can compute the average by dividing the sum of the value by the sum of the number of lines, but you cannot compute the \"max\" or the \"min\" of a column.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthecodingmachine%2Fdatabase.dbstats","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthecodingmachine%2Fdatabase.dbstats","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthecodingmachine%2Fdatabase.dbstats/lists"}