What is the correct way of retrieving maximum values of all columns in a table with a single query? Thanks.
Clarification: the same query should work on any table, i.e. the column names are not to be hard-coded into it.
SELECT max(col1) as max_col1, max(col2) as max_col2 FROM `table`;
I think (but would be happy to be shown wrong) that you have to know at least the number of columns in the table, but then you can do:
select max(c1),max(c2),max(c3),max(c4),max(c5)
from (
select 1 c1, 1 c2, 1 c3, 1 c4, 1 c5 from dual where 0
union all
select * from arbitrary5columntable
) foo;
Obviously you lose any benefits of indexing.
You're going to have to do it in two steps - one to retrieve the structure of the table, followed by a second step to retrieve the max values for each
In php:
$table = "aTableName";
$columnsResult = mysql_query("SHOW COLUMNS FROM $table");
$maxValsSelect = "";
while ($aColumn = mysql_fetch_assoc($columnsResult)) {
if (strlen($maxValsSelect) > 0) {
//Seperator
$maxValsSelect .= ", ";
}
$maxValsSelect .= "MAX(" . $aColumn['Field'] . ") AS '" . $aColumn['Field'] . "'";
}
//Complete the query
$maxValsQuery = "SELECT $maxValsSelect FROM $table";
$maxValsResult = mysql_query($maxValsQuery);
//process the results....
Related
Here is the query to get all columns of a single row
$STH = $DBH->db->prepare("SELECT * FROM Settings");
$STH->execute();
$STH->setFetchMode(PDO::FETCH_ASSOC);
$str = '';
while ($row = $STH->fetch())
{
foreach($row as $key => $value)
{
$str .= '<div>'.$key.' => '.$value.'</div>';
}
}
and this one is to get extended information of the column (including comment)
$STH = $DBH->db->prepare("SHOW FULL COLUMNS FROM Settings");
$STH->execute();
$STH->setFetchMode(PDO::FETCH_ASSOC);
\* the same php code *\
can I combine these two SQL queries to get the following data simultaniously
`FieldName`, `FieldValue`, `CommentValueOfColumn`
'
'
'
example of Settings table
Columns -> | PrintImage | SettMinus | HasChat . . .
--------------------------------------------
Values -> 0 1 1 . . .
and there is additional data Comment of the column.
So I want to select data:
PrintImage, 0 , Comment of PrintImage;
SettMinus, 1 , Comment of SettMinus;
HasChat, 1 , Comment of HasChat;
.....................................
and so on.
This will give you the column name, values of the columns and the comments. However, you can use php to get the values which is
VALUEARRAY[ORDINAL_POSITION]
You also need to copy/paste the rest of the column names after concat_ws.
Again, I cannot do everything in mysql so it needs help from PHPcodes to get the exact value from the array.
SELECT s.COLUMN_NAME,
s.ORDINAL_POSITION,
t.valuearray,
s.COLUMN_COMMENT
from INFORMATION_SCHEMA.columns s
cross join (select concat_ws(",", PrintImage,
SettMinus,HasChat) as valuearray from settings) t
where s.TABLE_NAME='Settings';
sample result :
COLUMN_NAME ORDINAL_POSITION valuearray COLUMN_COMMENT
PrintImage 1 0,1,1 commenttest
SettMinus 2 0,1,1 comments too
HasChat 3 0,1,1 3rd comment
I have 2 tables
Table1
ID . Name . Position
= = = = = = = = = = = =
10 . Mike . Analyst
20 . Anna . HR
30 . Mark . Accountant
Table2
Deal ID . Status
= = = = = = = = = = = =
10 . . . . . Active
19 . . . . . New
20 . . . . . New
I want to add a new Calculated Column in Table1 with this logic :
If ID found in Table2 then return Position, ELSE return "NONE"
so the output table should be like this
Outout
ID . Name . Position . . . . **NewCol**
= = = = = = = = = = = = = = = = =
10 . Mike . Analyst . . . . . **Analyst**
20 . Anna . HR . . . . . . . . **HR**
30 . Mark . Accountant. . **NONE**
There are two ways to accomplish that.
Query Based Result
If you just want to display the information every time you need it, the simplest, cleanest and efficient way is just to perform a SELECT within the tables. In addition, the data will allways be updated, because the query runs over the actual table state.
So, the query would look like this:
SELECT T1.*, IF(T2.ID IS NULL, 'NONE', T1.Position) As NewPos
FROM Table1 T1 LEFT OUTER JOIN Table2 T2
ON (T1.ID = T2.ID)
This query will show the position if found on Table2 and, if not, it will display NULL value, so it may be useful for your needs.
Database Modification and Data Inserting
The other way, is to alter the Table1 structure to add the column Position. The existence of the column is referred to the table architecture, it is not value dependant, so you can't alter a Table and adding the column based on row values.
So, the first step to do is to alter the table adding the column, something like this:
ALTER TABLE table1 ADD COLUMN Position VARCHAR(50);
The second step is to fill the data. For this, you will have to perform an UPDATE to fill the data you have just created, something like this.
UPDATE Table1 T1 LEFT OUTER JOIN Table2 T2
ON (T1.ID = T2.ID)
SET T1.Position = IF(T2.ID IS NULL, 'NONE', T1.Position);
This query will update the rows which also exists in Table2 referenced by ID and will put its position.
The problem of this way it's that if you perform this and after, you add rows to Table1 and Table2, the information will not be updated and you'll have to do the UPDATE query every certain time, which is database and time cost.
So, if the application is not too big, in this case is better to use just the SELECT query, which involves less cost, performance and database changes.
How to select rows from a table where its condition can match any value from an array.
something like this:
Select * from Table Where Name = Array_of_Names;
Array_of_Names is a java array.
You can pass it using IN keyword in query with multiple items separated by comma in brackets like :
String query = "Select * from Table Where Name IN (";
for(int i =0 ;i<arrayName.length();i++){
query = query + "'" +arrayName(i) + "'" + ",";
}
query = query.substring(0, query.length()-1);
query = query + ")";
// execute your query here
This ll pass your query like :
Select * from Table Where Name IN ('arrayvalue1','arrayvalue2','arrayvalue3');
as per length of array.
You'll need to craft the SQL statement and use WHERE ... IN ...
SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1,value2,...);
here you are:
Select * from Table Where Name in ("Tom", "Dick", "Harry");
I have a MySQL script like this: SELECT id, name FROM users WHERE id IN (6,4,34)
The sequence in the IN(...) array is very important. Is it possible to get them in the given sequence?
You can use the MySQL FIELD function to keep it compact;
SELECT id, name
FROM users
WHERE id IN (6, 4, 34)
ORDER BY FIELD(id, 6, 4, 34);
Try
SELECT id, name FROM users WHERE id IN (6,4,34) order by FIELD(id,6,4,34)
You can use any expression in the ORDER BY clause, including a 'CASE':
ORDER BY CASE id
WHEN 6 THEN 1
WHEN 4 THEN 2
WHEN 34 THEN 3
END ASC
If your list comes from the application programming layer, you might build this with the following (PHP here):
$sortVal = 1;
foreach($ids as $id_val) {
$cases[] = sprintf('WHEN %i THEN %i', $id_val, $sortVal++);
}
$order_by = 'ORDER BY CASE id ' . implode($cases) . ' END ASC';
However, I'll mention that Joachim's answer is quite elegant :-)
A complete example based on Chris Trahey answer.
$ids = array("table1", "table2", "table3");
$sortVal = 1;
foreach ($ids as $id_val) {
$cases[] = sprintf("WHEN '%s' THEN %u ", $id_val, $sortVal++);
}
$order_by = 'ORDER BY CASE `tableName` ' . implode($cases) . ' END ASC';
$result = mysqli_query( $con, "
SELECT DISTINCT tableName
FROM `table`
$order_by");
I have two tables with identical structure except for one column... Table 2 has an additional column in which I would insert the CURRENT_DATE()
I would like to copy all the values from table1 to table2.
If I use
INSERT INTO dues_storage SELECT * FROM dues WHERE id=5;
it throws an error pointing to the difference in the number of columns.
I have two questions:
How do I get around this?
How do I add the value for the additional date column (CURRENT_DATE()) in table2 within this same statement?
To refine the answer from Zed, and to answer your comment:
INSERT INTO dues_storage
SELECT d.*, CURRENT_DATE()
FROM dues d
WHERE id = 5;
See T.J. Crowder's comment
The safest way to do it is to fully specify the columns both for insertion and extraction. There's no guarantee (to the application) that either of these will be the order you think they may be.
insert into dues_storage (f1, f2, f3, cd)
select f1, f2, f3, current_date() from dues where id = 5;
If you're worried about having to change many multiple PHP pages that do this (as you seem to indicate in the comment to another answer), this is ripe for a stored procedure. That way, all your PHP pages simply call the stored procedure with (for example) just the ID to copy and it controls the actual copy process. That way, there's only one place where you need to maintain the code, and, in my opinion, the DBMS is the right place to do it.
INSERT INTO dues_storage
SELECT field1, field2, ..., fieldN, CURRENT_DATE()
FROM dues
WHERE id = 5;
Hope this will help someone... Here's a little PHP script I wrote in case you need to copy some columns but not others, and/or the columns are not in the same order on both tables. As long as the columns are named the same, this will work. So if table A has [userid, handle, something] and tableB has [userID, handle, timestamp], then you'd "SELECT userID, handle, NOW() as timestamp FROM tableA", then get the result of that, and pass the result as the first parameter to this function ($z). $toTable is a string name for the table you're copying to, and $link_identifier is the db you're copying to. This is relatively fast for small sets of data. Not suggested that you try to move more than a few thousand rows at a time this way in a production setting. I use this primarily to back up data collected during a session when a user logs out, and then immediately clear the data from the live db to keep it slim.
function mysql_multirow_copy($z,$toTable,$link_identifier) {
$fields = "";
for ($i=0;$i<mysql_num_fields($z);$i++) {
if ($i>0) {
$fields .= ",";
}
$fields .= mysql_field_name($z,$i);
}
$q = "INSERT INTO $toTable ($fields) VALUES";
$c = 0;
mysql_data_seek($z,0); //critical reset in case $z has been parsed beforehand. !
while ($a = mysql_fetch_assoc($z)) {
foreach ($a as $key=>$as) {
$a[$key] = addslashes($as);
next ($a);
}
if ($c>0) {
$q .= ",";
}
$q .= "('".implode(array_values($a),"','")."')";
$c++;
}
$q .= ";";
$z = mysql_query($q,$link_identifier);
return ($q);
}
Alternatively, you can use Inner Queries to do so.
SQL> INSERT INTO <NEW_TABLE> SELECT * FROM CUSTOMERS WHERE ID IN (SELECT ID FROM <OLD_TABLE>);
Hope this helps!
SET #sql =
CONCAT( 'INSERT INTO <table_name> (',
(
SELECT GROUP_CONCAT( CONCAT('`',COLUMN_NAME,'`') )
FROM information_schema.columns
WHERE table_schema = <database_name>
AND table_name = <table_name>
AND column_name NOT IN ('id')
), ') SELECT ',
(
SELECT GROUP_CONCAT(CONCAT('`',COLUMN_NAME,'`'))
FROM information_schema.columns
WHERE table_schema = <database_name>
AND table_name = <table_source_name>
AND column_name NOT IN ('id')
),' from <table_source_name> WHERE <testcolumn> = <testvalue>' );
PREPARE stmt1 FROM #sql;
execute stmt1;
Of course replace <> values with real values, and watch your quotes.
Just wanted to add this little snippet which works beautifully for me.
INSERT INTO your_target_table
SELECT *
FROM your_rescource_table
WHERE id = 18;
And while I'm at it give a big shout out to Sequel Pro, if you're not using it I highly recommend downloading it...makes life so much easier