SUM values of specific column from all tables LIKE table_% - php

I need help to create an SQL query in order to SUM the values of specific column from all tables LIKE table_% as the tables will grow over time and this must cater for new table names based on the format below
Scheme Name: database_01
Table Names: tb_data_'YEAR'_'MONTH'
YEAR and MONTH are both values which range from all 12 months and years from 2011 to 2018.
Each Table contains a column called TOTAL_VALUE. I have a php script that triggers an SQL query to pull data from the database.
I would like to SUM the total of each tables TOTAL_VALUE column and save the value for my script below to push the array.
$sql = "SELECT TOTAL_VALUES FROM tb_data_2017_october";
$result = mysqli_query($conn, $sql);
$data = array(); while($enr = mysqli_fetch_assoc($result)){
$a = array($enr['TOTAL_VALUES']);
foreach ($a as $as){
echo "'".$as."', ";}
array_push($data, $as); }
I have been trying to alter the SQL with options such as:
SELECT id FROM table1
UNION
SELECT id FROM table2
UNION
SELECT id FROM table3
UNION
SELECT id FROM table4
However i need to cater for the ability to check all tables that are like tb_data_%

See this question for information about getting the list of tables: Get table names using SELECT statement in MySQL
You can get the list of tables in one query result, and then query each table. I'll rework your code slightly to give an example:
// Get the tables
$tables_sql = "SELECT table_name
FROM information_schema.tables
WHERE table_schema='<your DB>'
AND table_name LIKE 'tb_data%'";
$tables = mysqli_query($conn, $sql);
// Iterate over the tables
while($table = mysqli_fetch_assoc($tables)){
{
/*
* Your code
*/
// This query assumes that you can trust your table names not to to an SQL injection
$sql = "SELECT TOTAL_VALUES FROM " . $table['table_name'];
$result = mysqli_query($conn, $sql);
$data = array(); while($enr = mysqli_fetch_assoc($result)){
$a = array($enr['TOTAL_VALUES']);
foreach ($a as $as){
echo "'".$as."', ";
array_push($data, $as); }
}
You can do whatever you need once your have your list of tables. You can build one big union query (which would be more efficient than querying each table individually), or feed the tables to the MERGE engine, as in barmar's answer

Use the MERGE storage engine to create a virtual table that combines all the monthly tables.
CREATE TABLE tb_all_data (
...
) ENGINE=MERGE UNION=(tb_data_2017_october, tb_data_2017_november, ...);
List all the tables in the UNION= list, and update it whenever you create a new table.
Then you can just query from tb_all_data.

Try this- it will loop through all the tables with the pattern you want and create sums for you:
declare #table table (rowid int identity, name varchar(max))
insert #table
select name from sys.tables where name like '%yourname%'
declare #holding table (name varchar(max), sumvalue int)
declare #iterator int = 1
declare #tablename varchar(max)
while #iterator<=(select max(rowid) from #table)
begin
select #tablename=name from #table where rowid=#iterator
insert #holding
exec('select '+#tablename+' sum(TOTAL_VALUE)TOTAL_VALUE from '+#tablename+' group by +'+#tablename+'')
set #iterator=#iterator+1
end
select * from #holding

Related

Select Data From Multiple MySQL Tables

Im searching for a function in MySQL in order to Select rows from multiple tables that have a similar name. For example: Proyect_1, Proyect_2, Proyect_3
All of the tables have the same column names, the only difference between the tables is the table name. It starts with the prefix 'proyect'. The issue is that the program doesn´t know how many 'proyect' tables there are, so i can´t make a list of them and select data like always
I need something like this:
SELECT mydata FROM TABLES LIKE 'Proyect_%';
Any ideas? Thanks!
To get all tables with a common prefix
SHOW TABLES LIKE 'Proyect_%';
This will return rows of tables that matched the prefix. Example:
Proyect_1
Proyect_2
Proyect_3
In PHP you can create a UNION query that will pick up the tables returned by the above query,
$sql = "SHOW TABLES LIKE 'Proyect_%'";
$result = $conn->query($sql);
$dataQuery = array();
$query = "";
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_array(MYSQLI_NUM)) {
$dataQuery[] = "SELECT * FROM {$row[0]}";
}
$query = implode(' UNION ', $dataQuery);
}
echo $query;
if you want to search for all tables with name like Proyect then you can get from MySQL information schema.
SELECT * FROM information_schema.tables
From here you can find table by table name

SQL query to find the table name

I have 5 different tables in my dB with the structure Name|Price|Id..
I have a unique price and Id entry combination.
Using these 2, what could be the possible SQL query to fetch the name of the table in which this entry is present?
I need to fetch the name of this table in order to update the value of Price.
You really should normalise your database properly and use a single table, but if you really need a kludge then:
SELECT name, brand, id, 'Tea' as tablename
FROM TableTea
WHERE brand = 'abc'
AND id = 100
UNION
SELECT name, brand, id, 'Coffee' as tablename
FROM TableCoffee
WHERE brand = 'abc'
AND id = 100
UNION
SELECT name, brand, id, 'Chocolate' as tablename
FROM TableChocolate
WHERE brand = 'abc'
AND id = 100
And you'll have to change it if you ever add new products
if your DBMS is MySQL you can use this Query:
SELECT Result.TABLE_NAME FROM (
SELECT TABLE_NAME,COLUMN_NAME,COUNT(*) AS QTA FROM INFORMATION_SCHEMA.COLUMNS
where TABLE_SCHEMA = 'NAME_DB'
and COLUMN_NAME IN ('Name','Price','Id')
GROUP BY TABLE_NAME
) as Result
WHERE Result.QTA = 3
i have already tried to do without php
Replace NAME_DB with your Database.
You would first need to know the tables in which it's possible to have the entry. Use a loop to iterate over those tables and run the query, each time returning a result set and testing if records exist in the result set. This will tell you what tables have the entry.
General Approach:
$array = array("table1", "table2", "table3", "table4", "table5");
foreach($array as $table) {
//build your query using the table name
$query = "SELECT something FROM " . $table;
//exec your query against your db and return results
//test if records exist in result set. If true, you know the table name based on the loop iteration ($table).
}

Add MySQL Count Column to PHP/HTML Table

I'm developing a website using HTML, PHP and MySQL to access a database. On one page I present a table with data from that database. This is some of the code I'm using:
$sql1 = "SELECT * FROM MyTable ORDER BY ID ASC";
$rs1 = mysqli_query($link,$sql1);
(...)
while($row1 = mysqli_fetch_assoc($rs1)) {
echo "<tr><td>".$row1['ID']."</td><td>".$row1['Field1']."</td><td></td><td>".$row1['Field2']."</td><td>".$row1['Field3']."</td></tr>\n" ;
}
Notice the empty <td></td>? That's because I want to have there the number of time a given ID appears on two other tables (there are foreign keys involved, obviously). I have sorted out the code I need for that:
$sql2 = "SELECT (SELECT COUNT(*) FROM MyTable2 WHERE ID2=$row1['ID'])+(SELECT COUNT(*) FROM MyTable3 WHERE ID2=$row1['ID']) AS total";
However, I'm struggling with figuring out a way to add this result to the other table. Any help?
try with this.. it inserts the total to an table after selecting the count.
"INSERT INTO total_table (total)
SELECT (SELECT COUNT(*) FROM MyTable2 WHERE ID2=$row1['ID'])+(SELECT COUNT(*) FROM MyTable3 WHERE ID2=$row1['ID']) AS total
WHERE cid = 2"

mySQL, PHP, HTML table with sortable columns - but issue with some column values

I have a mySQL database table with columns like:
Item
item_id
name
size (e.g., in bytes)
description
date
And another table, that has a 1:* relationship to the first table, which contains "keywords" that describe items represented by fields in the first table:
Item_Keyword
item_id
keyword
I use PHP to "select *" from the Item table, and then iterate over the returned rows (using a while loop with fetch_assoc()) to build a HTML table containing all of the data.
On each iteration of the while loop, I execute another query for all of the keyword(s) from the Item_Keyword table which match the id of the current tuple from the Item table, and then add these to a column in the table, concatenated together:
$res = getItems();
if ($res)
{
while ($row = $res->fetch_assoc())
{
...
$itemID = $row['item_id];
$res2 = getKeywords($itemID);
if ($res2)
{
$keywords = "";
while ($row2 = $res2->fetch_assoc())
{
if (strlen($keywords) > 0)
$keywords .= ", ";
$keywords .= $row2['keyword'];
}
$text .= "<td> " . $keywords . " </td>";
}
}
}
So I end up with a table that looks something like:
ID Name Size Description Date Keywords
0 Widget 1024 Widget one 010101 widget,one,item
I'm trying to make the HTML table columns sortable. I can envisage how that would work with an ORDER BY in my query on the Item table. The trouble is, since the Keywords are stored in a separate table and retrieved with an independent query, I can only ORDER BY one set of query results or the other, but not both - more pithily, I can't see any way of sorting by values in the Keyword column.
Is there some kind of esoteric query that I could construct that would allow me to SELECT the keyword(s) for an item, and include these in the "FROM" parameters for the query on the Item table? Something like:
SELECT item_id, name, size, description, date (SELECT keyword FROM Item_Keyword WHERE item_id = 0)
FROM Item
WHERE item_id = 0
First off, you should probably be grabbing all of your data with a single query like this:
SELECT
i.item_id AS `item_id`,
i.name AS `name`,
i.size AS `size`,
i.description AS `description`,
i.date AS `date`,
GROUP_CONCAT(ik.keyword) AS `keywords`
FROM item AS i
LEFT JOIN item_keyword AS ik
ON item.item_id = item_keyword.item_id
GROUP BY i.item_id
ORDER BY i.item_id ASC, ik.keyword ASC /* OR whatever sort you desire */
Note here that I use GROUP_CONCAT() and a GROUP BY clause in order to collapse all keyword entries into a single row associated with each item_id.
This gets you everything you need in a single database call eliminating all those unnecessary extra queries. You can do this without a group by as well, you would just have more rows (i.e. an item with 3 keywords would result in 3 rows). With this approach, you could read your data into a multi-dimensional array before rendering the table.

Summing a field from all tables in a database

I have a MySQL database called "bookfeather." It contains 56 tables. Each table has the following structure:
id site votes_up votes_down
The value for "site" is a book title. The value for "votes_up" is an integer. Sometimes a unique value for "site" appears in more than one table.
For each unique value "site" in the entire database, I would like to sum "votes_up" from all 56 tables. Then I would like to print the top 25 values for "site" ranked by total "votes_up".
How can I do this in PHP?
Thanks in advance,
John
You can do something like this (warning: Extremely poor SQL ahead)
select site, sum(votes_up) votes_up
from (
select site, votes_up from table_1
UNION
select site, votes_up from table_2
UNION
...
UNION
select site, votes_up from table_56
) group by site order by sum(votes_up) desc limit 25
But, as Dav asked, does your data have to be like this? There are much more efficient ways of storing this kind of data.
Edit: You just mentioned in a comment that you expect there to be more than 56 tables in the future -- I would look into MySQL limits on how many tables you can UNION before going forward with this kind of SQL.
Here's a PHP code snip that should get it done.
I have not tested it so it might have some typos and stuff, make sure you replace DB_NAME
$result = mysql_query("SHOW TABLES");
$tables = array();
while ($row = mysql_fetch_assoc($result)) {
$tables[] = '`'.$row["Tables_in_DB_NAME"].'`';
}
$subQuery = "SELECT site, votes_up FROM ".implode(" UNION ALL SELECT site, votes_up FROM ",$tables);
// Create one query that gets the data you need
$sqlStr = "SELECT site, sum(votes_up) sumVotesUp
FROM (
".$subQuery." ) subQuery
GROUP BY site ORDER BY sum(votes_up) DESC LIMIT 25";
$result = mysql_query($sqlStr);
$arr = array();
while ($row = mysql_fetch_assoc($result)) {
$arr[] = $row["site"]." - ".$row["sumVotesUp"];
}
print_r($arr)
The UNION part of Ian Clelland answer can be generated using a statement like the following. The table INFORMATION_SCHEMA.COLUMNS has a column TABLE_NAME to get all tables.
select * from information_schema.columns
where table_schema not like 'informat%'
and column_name like 'VOTES_UP'
Join all inner SELECT with UNION ALL instead of UNION. UNION is doing an implicit DISTINCT (on oracle).
The basic idea would be to iterate over all your tables (using a SQL SHOW TABLES statement or similar) in PHP, then for every table, iterate over the rows (SELECT site,votes_up FROM $table). Then, for every row, check the site against an array that you're building with sites as keys and votes up as values. If the site is already in the array, increment its votes appropriately; otherwise, add it.
Vaguely PHP-like pseudocode:
// Build an empty array for use later
$votes_array = empty_array();
// Get all the tables and iterate over them
$tables = query("SHOW TABLES");
for($table in $tables) {
$rows = query("SELECT site,votes_up FROM $table");
// Iterate over the rows in each table
for($row in $rows) {
$site = $row['site'];
$votes = $row['votes_up'];
// If the site is already in the array, increment votes; otherwise, add it
if(exists_in_array($site, $votes_array)) {
$votes_array[$site] += $votes;
} else {
insert_into_array($site => $votes);
}
}
}
// Get the sites and votes as lists, and print out the top 25
$sorted_sites = array_keys($votes_array);
$sorted_votes = array_values($votes_array);
for($i = 0; $i < 25; $i++) {
print "Site " . $sorted_sites[$i] . " has " . $sorted_votes[$i] . " votes";
}
"I allow users to add tables to the database." - I hope all your users are benevolent and trustworthy and capable. Do you worry about people dropping or truncating tables, creating incorrect new tables that break your code, or other things like that? What kind of security do you have when users can log right into your database and change the schema?
Here's a tutorial on relational database normalization. Maybe it'll help.
Just in case someone else that comes after you wants to find what this could have looked like, here's a single table that could do what you want:
create database bookfeather;
create user bookfeather identified by 'bookfeather';
grant all on bookfeather.* to 'bookfeather'#'%';
use bookfeather;
create table if not exists book
(
id int not null auto_increment,
title varchar(255) not null default '',
upvotes integer not null default 0,
downvotes integer not null default 0,
primary key(id),
unique(title)
);
You'd vote a title up or down with an UPDATE:
update book set upvotes = upvotes + 1 where id = ?
Adding a new book is as easy as adding another row:
insert into book(title) values('grails in action')
I'd strongly urge that you reconsider.

Categories