I got mysql table like this
id | type | number
1 | c | 2
2 | c | 10
3 | c | 20
Also i got PHP array with values:
$array[c] = 5;
$array[d] = 10;
I wanna do something like this
( SELECT * FROM table WHERE number >= $array[ type ] )
so that type could be taken from mysql column somehow and used for finding correct value from array.
Thats kinda tricky, but I'm not sure how better I could ask.
This isn't the most elegant way but something like this?
$where = "WHERE ";
foreach($array as $key => $value)
{
$where .= "(type = $key AND number >= $value) OR";
}
$where = substr($where, 0, strlen($where)-2);
You'd have to attach that to your select statement and then run the query obviously.
Hopefully that allows someone else to catch on and provide a more elegant solution.
Try this:
$type = 'c';
$query = "SELECT * FROM table WHERE number >= " . intval( $array[ $type ] ) . " AND type = '" . $type . "'";
try to do it in two steps:
before use an sql query to put in an array the values of type
then in a while
( SELECT * FROM table WHERE number >= $array[$i] )
where $i is the index of the while loop
Possibly a bit better than using lots of WHERE clauses would be something like this:-
SELECT *
FROM table a
INNER JOIN
(SELECT 'c' AS RowType, 5 AS RowVal
UNION
SELECT 'd', 10) Sub1
ON a.type = Sub1.type AND a.number >= Sub1.RowVal
Set up a subselect which is just getting the constants, and then do a join between that subselect and your existing table.
In php done something like this:-
<?php
$SubQuery = array();
foreach ($array AS $key=>$value)
{
$SubQuery[] = "SELECT '$key' AS RowType, $value AS RowVal";
}
$sql = "SELECT *
FROM table a
INNER JOIN (".implode(" UNION ", $SubQuery).") Sub1
ON a.type = Sub1.type AND a.number >= Sub1.RowVal";
?>
Related
I have a table with a lot of fields, and I need to return the COUNT of NOT NULL for each field.
I make a loop in PHP and I execute 1 request by field...
$result = array();
$champs = array("field1", "field2", "field3", "field4", "field5", "field6", "field7", "field8", "field9", "field10", "field11", "field12", "field13", "field14", "field15", "field16", "field17", "field18", "field19", "field20");
foreach ($champs as $value) {
$and = empty($filtroAdd) ? "$value IS NOT NULL" : "AND $value IS NOT NULL";
$requete = "SELECT COUNT($value)
FROM my_table
WHERE $filtroAdd $and";
$r = $db->query($requete)->fetch(PDO::FETCH_NUM);
$result[$value] = $r[0];
}
print_r( $result );
I think it is not the better way, and we surely can return the same final result with a single postgreSQL request ?!
Thanks for help
You can use a single query:
SELECT COUNT(field1), COUNT(field2), COUNT(field3), . . .
FROM my_table;
There is no need to do a separate query for each field. COUNT(<field>) returns the number of rows with non-NULL values in that column.
If you want the number of different values, then use COUNT(DISTINCT):
SELECT COUNT(DISTINCT field1), COUNT(DISTINCT field2), COUNT(DISTINCT field3), . . .
FROM my_table;
You can also embed CASE logic, if you like. I usually do this using SUM():
SELECT SUM(CASE WHEN field1 > 0 THEN 1 ELSE 0 END),
Is it possible to SELECT with multiple Array tables. I know it sounds confusing but here is what I have done :
First of all, I've created a form, that has two checkboxes option as follows :
<form action="something.php" method="post">
<input type="checkbox" name="store[]" value="M1">
<input type="checkbox" name="store[]" value="M2">
<input type="submit" value="Go">
</form>
Now after submitting the form, I can view which store selected by doing foreach loop:
$allstore = $_POST['store'];
foreach ($allstore as $store=>$value) {
echo $value;
}
Everything till now works as needed !
However those two values in checkboxes are considered to be table names ! Now how can I find a way to let PHP select either one or two tables based on user selection $value ?
$query = "SELECT * from **{$allstore[0]},{$allstore[1]}** WHERE .....";
As you can see {$allstore[0]},{$allstore[1]} should be created based under foreach loop. I can't seem to find a way of doing it! Can I insert a function to do it for me?
Like this : $query = "SELECT * from ((( Function Here ))) WHERE .....";
If you have a different way of doing it, Please share it.
Edit :
M1 Table
id |item_no |qty |price
1 x1 10 20
2 x2 5 22
3 x3 3 5
M2 Table
id |item_no |qty |price
1 x1 11 20
2 x9 5 30
3 x10 6 26
The output table should be
item_no | price | M1 | M2
x1 20 10 11
x2 22 5 N/A
x3 5 3 N/A
x9 30 N/A 5
x10 26 N/A 6
That's what I am aiming for. I hope it can be solved !
here's the structure for 2 tables sqlfiddle
I think you can add more tables from here.
SELECT T1.item_no,
COALESCE(M1.price,M2.price) as price,
M1.qty as M1,
M2.qty as M2
FROM
(SELECT item_no FROM M1
UNION
SELECT item_no FROM M2
)T1
LEFT JOIN M1 ON T1.item_no = M1.item_no
LEFT JOIN M2 ON T1.item_no = M2.item_no
UPDATED: I am not too familiar with PHP but I looked up some syntax and was able to dynamically generate SQL based on array of either ["M1","M2"] or ["M1"] or ["M2"]
DynamicPHPtobuildSQL
<?php
//Enter your code here, enjoy!
$allstore = ["M2"];
$item = 0;
$sqlpart1 = "";
$sqlpart2 = "";
$sqlpart3 = "";
$sqlpart4 = "";
foreach ($allstore as $store=>$value) {
$item += 1;
if ($item > 1){
$sqlpart1 .= ",";
$sqlpart2 .= ",";
$sqlpart3 .= " UNION ";
}
$sqlpart1 .= $value . ".price ";
$sqlpart2 .= $value . ".qty as " . $value . " ";
$sqlpart3 .= "SELECT item_no FROM " . $value . " ";
$sqlpart4 .= "LEFT JOIN " . $value . " ON T1.item_no=" . $value . ".item_no ";
}
$SQL = "SELECT T1.item_no,COALESCE(" . $sqlpart1 . ") as price," . $sqlpart2;
$SQL .= "FROM (" . $sqlpart3 . ")T1 " . $sqlpart4;
echo $SQL;
?>
Be careful to avoid the risk of SQL injection: compare the posted values against a closed list of existing store table names and reject any other value.
Note also that not only the FROM clause is influenced by the user's choices, but also the SELECT clause. So you have two dynamic parts in your SQL statement.
You could use this code which makes use of array_intersect, implode and array_map:
$selected_stores = $_POST['store'];
// Protect against SQL-injection by only accepting known tables:
$all_stores = array("M1", "M2", "M3");
$selected_stores = array_intersect($selected_stores, $all_stores);
// Build dynamic part of the FROM clause
$from = implode("
UNION
", array_map(function ($store) {
return "SELECT '$store' as store, item_no, price, qty FROM $store";
}, $selected_stores));
// Build dynamic part of the SELECT clause
$cols = implode(",
", array_map(function ($store) {
return "CASE store WHEN '$store' THEN qty END AS $store";
}, $selected_stores));
$sql = "
SELECT item_no,
MAX(price) as price,
$cols
FROM ( $from ) data
GROUP BY item_no
";
The SQL generated looks like this:
SELECT item_no,
MAX(price) as price,
CASE store WHEN 'M1' THEN qty END AS M1,
CASE store WHEN 'M2' THEN qty END AS M2
FROM ( SELECT 'M1' as store, item_no, price, qty FROM M1
UNION
SELECT 'M2' as store, item_no, price, qty FROM M2 ) data
GROUP BY item_no
See also this SQL fiddle.
As a side comment: I would advise to combine all store tables into one table, which would have an additional column indicating the store. This is more in line with normalised database design and will give more advantages than disadvantages in terms of searching, sorting, performance, and simplicity.
Ok so my query is this:
select distinct `rate_id`, `p_id`, p_rate from shipping_rates inner join products_to_categories ptc inner join customers_basket cb on ptc.products_id = cb.products_id where cb.customers_id='1' and p_status = '1' and p_free = '0' group by p_id
which returns
rate_id p_id p_rate
1 1 10.00
2 22 11.00
which is what i want however when i add that to an array with
$p_rate[] = $sInfo->p_rate;
$rate = array_sum($p_rate);
this returns 10.00 not 21.00 like it should
by the way here is my code for the objectInfo class
function objectInfo($object_array) {
reset($object_array);
while (list($key, $value) = each($object_array)) {
$this->$key = tep_db_prepare_input($value);
}
}
}
}
and the code right below is
$sRate = tep_db_fetch_array($status_query);
if ($sRate !=''){//error checking for empty query
$sInfo = new objectInfo($sRate);
}
trp_db_fetch_array() is just a function calling up mysql_fetch_array
Are you doing the array_sum() INSIDE the fetch loop? e.g.
while($sInfo = fetch_from_db($result)) {
$p_rate[] = $sInfo->p_rate;
$rate = array_sum($p_rate);
}
? If so, then you'll have to move the summation to OUTSIDE the loop, so it only sums up after you've retrieve all of the data from the DB:
while($sInfo = fetch_from_db($result)) {
$p_rate[] = $sInfo->p_rate;
}
$rate = array_sum($p_rate);
$sInfo only contains one row. You need to fetch the whole result set first.
You seem to use a framework and not the native php functions. For this reason I cannot give the code used to do that.
Once you have the result set, you use :
foreach($sInfoTable as $sInfo){
$p_rate[] = $sInfo->p_rate;
}
$rate = array_sum($p_rate);
Ok so i found out the answer by hunting and pecking here is the query
$status_query = tep_db_query("select `rate_id`, `p_id`, `p_rate`, cb.customers_id from " . TABLE_SHIPPING_RATES ." inner join ". TABLE_PRODUCTS_TO_CATEGORIES . " ptc inner join ". TABLE_CUSTOMERS_BASKET . " cb on cb.products_id = p_id where cb.customers_id='" . $customer_id ."' and p_status = '1' and p_free = '0' group by cb.customers_id,p_id");
and here is where i got all rows:
while($row = mysql_fetch_assoc($status_query)){
$p_rate[] = $row["p_rate"];
}
and here is where i summed up the rows:
$rate = array_sum($p_rate);
so now this doesn't need to count the rows or etc and is a lot cleaner
I want to get Name and corresponding Score at the latest time. So I tried:
$queryObj = mysql_query("SELECT `Name`,`Score` from `Table`.`Score` where `Date` = ( SELECT max(`Date`) from `Table`.`Score`) and `Name`<>'' ");
then get value from it by:
while( $obj = mysql_fetch_object( $queryObj ) ) {
$data = array();
$data['Name'] = $obj->Name;
$data['Score'] = $obj->Score;
$searches[] = $data;
}
But when I print :
print_r(array_values($searches));
the first value is missing in the array, so that won't be the right way.
I also tried:
$row = mysql_fetch_assoc($queryObj);
for ($i = 0; $i <3; $i++)
print( $row['Name'][$i]." Score: ".$row['Score'][$i]."<br />\n");
But it won't give me the right results also. How do I get the value from that query? (the query is correct, I tested it). Any body has suggestion ?
Edit: I add my sample data here:
Name Score Date
abc 3 2013-08-29 10:11:47
abc 2 2013-08-29 09:39:23
abc 1 2013-08-28 10:22:28
jane 2 2013-08-29 09:39:23
2013-08-29 10:08:36
jane 1 2013-08-29 10:11:47
tarzan 1 2013-08-29 10:11:47
Note: Yes, there is some blank values.
My expected result would be:
abc score 3
jane score 1
tarzan score 1
Ok, so after you have updated your question and provided what you expect, your query should look like this:
SELECT t1.Name, t1.Score
FROM Table.Score t1
INNER JOIN
(
SELECT max(Date) MaxDate, Name, Score
FROM Table.Score
WHERE Name <> ''
GROUP BY Name
) t2
ON t1.Name = t2.Name AND t1.Date = t2.MaxDate
This will give you pairs of Name and Score for each Name with Score based on his latest Date (1 row per Name).
So replace your original query with mine in this line:
$queryObj = mysql_query(" ... ");
Then:
$rows = array();
while($row = mysql_fetch_assoc($queryObj)) {
$rows[$row['Name']] = $row['Score'];
}
And you can nicely foreach it in the exact way you wanted in your last comment:
foreach($rows as $name => $score) {
echo $name . ' - ' . $score . "\n";
}
I have a table containing (essentially) three columns - id, name, ref_id.
I would like to create an indented list where the columns with ref_id would be indented below the column with the corresponding id, for example:
Name | ID | Ref ID
about 1 0
story 2 1
history 3 1
contact 4 0
help 5 0
map 6 4
directions 7 4
Would ideally create something like this:
about
- story
- history
contact
- map
- directions
help
What would be ideal is one MySQL query that would return the full list as above, if not something that would create it with the least amount of SQL calls and cpu usage. The only way I can think of doing it is incredibly wasteful and I am sure there is a better way.
Thanks in advance!
--MySQL 5.1 happiness
SELECT
CASE WHEN tp.Level = 1 THEN tp.Parent
ELSE CONCAT( '- ', tp.Name)
END AS result
FROM (
SELECT
t.name,
CASE
WHEN t.ref_id = 0 THEN t.name
ELSE t2.name
END AS Parent,
CASE
WHEN t.ref_id = 0 THEN 1
ELSE 2
END AS Level
FROM question_1900097 t
LEFT JOIN question_1900097 t2 ON t.ref_id = t2.id
) AS tp
ORDER BY tp.Parent, tp.Name;
The PHP version
$in = array(
array('about',1,0),
array('story',2,1),
array('history',3,1),
array('contact',4,0),
array('help',5,0),
array('map',6,4),
array('directions',7,4)
);
foreach ($in as $k => $v) {
if ($v[2] === 0) { $out[$v[1]][0] = $v; };
if ($v[2] > 0) { $out[$v[2]][1][] = $v;};
}
foreach ($out as $k => $v) {
echo $v[0][0] . "\n";
if (isset($v[1])) {
foreach ($v[1] as $sk => $sv) {
echo " - " .$sv[0] . "\n";
}
}
}