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.
Related
need a help with a PHP/MySQL issue. I have a table named bids and two column named buyer and tagged both using int.
buyer
--------------
8
5
2
tagged
--------------
5
4
1
I'm trying to detect multiple same entry number. I want if a same number appears on both of the column it shouldnt display on the menu list anymore, hope yo understand.
Any tip?
code below
$query = "SELECT b.auction, b.buyer, b.bid, b.bidwhen, b.quantity, b.willwin, b.tagged, b.balance, u.nick, u.rate_sum FROM " . $DBPrefix . "bids b
LEFT JOIN " . $DBPrefix . "users u ON (u.id = b.bidder) WHERE b.auction = :auc_id
ORDER BY b.bid asc, b.quantity DESC, b.willwin asc"; $params = array(); $params[] = array(':auc_id', $id, 'int');
I'll explain briefly what I've done so far-
First of all I have multiple of stores and each store has its own table in which it contains id,item,qty and price and there is a main table called all_items that contains the total qty taken from each store table.
Now each store table either have same item number or not. Here you can see what the tables looks like :
Store tables called : S1, S2, S3
S1
id item qty price
1 x1 10 12
2 x2 10 15
3 x3 5 5
S2
id item qty price
1 x1 10 12
2 x4 6 6
S3
id item qty price
1 x3 1 5
2 x6 5 5
3 x7 5 12
all_items - Contains original total qty
id item qty price
1 x1 20 12
2 x2 10 15
3 x3 6 5
4 x4 6 6
5 x6 5 5
6 x7 5 12
Okay now, I've decided to find out the qty available for each item in all stores for comparing purposes- As follows :
item price S1 S2 S3
x1 12 10 10 -
x2 15 10 - -
x3 5 5 - 5
x4 6 - 6 -
x6 5 - - 5
x7 12 - - 5
I hope its clear for you now. I've created a form with checkbox input type ( for each store ) to allow user select which stores he wants to compare, so after submitting the form - a PHP page contains the following code :
$allstore = $_POST['store']; //Collects name from checkbox ticks under form
function createSelect($allstore)
{
if (empty($allstore))
return "";
$querySelect = "";
$queryJoin = "";
$baseTable = "";
foreach ($allstore as $store => $value) {
if (!$querySelect) {
$baseTable = "all_items";
$querySelect = "SELECT " . $store . ".item_no, " . $store . ".actual_price, " . $store . ".selling_price, " . $store . ".qty as " . $store;
} else {
$querySelect .= ", " . $store . ".qty as " . $store;
$queryJoin .= "
INNER JOIN " . $store . " ON " . $baseTable . ".item_no = " . $store . ".item_no";
}
}
$querySelect .= " FROM " . $baseTable;
$query = $querySelect . $queryJoin;
return $query;
}
$allstore = array(); // The below code allows function to know how many stores selected in $allstore
if (!empty($_POST['store'])) {
foreach ($_POST['store'] as $value) {
$allstore["s_".$value] = 0; // or 1, it doesn't matter because your function adds all the keys
}
}
var_dump(createSelect($allstore)); // Output SQL
$query = (createSelect($allstore));
$result = mysql_query($query);
//Rest of the code .....
Now if you notice $baseTable = "all_items"; makes the whole query fail. However if I change it value to $baseTable = $store; it works and shows an output but not as expected because it turns out S1 is the main now and the result will be totally different because it relays on the S1 items only.
If you can provide any helpful solution will be appreciated.
Why not use UNION?
function createSelect($stores)
{
$query = "";
$baseTable = "all_items";
foreach($stores as $i => $store)
{
$query .= "(SELECT {$store}.id AS {$store}_id, {$store}.item AS {$store}_item, {$store}.price AS {$store}_price, {$store}.qty AS {$store}_qty, '{$store}' as Source FROM {$store}) UNION ";
}
$query .= "(SELECT all_items.id AS {$baseTable}_id, {$baseTable}.item AS {$baseTable}_item, {$baseTable}.price AS {$baseTable}_price, {$baseTable}.qty AS {$baseTable}_qty, '{$baseTable}' as Source FROM {$baseTable})";
return $query;
}
$result = mysql_query(createSelect($allStore));
//Rest of code
//if my tables are S1, S1, and my $baseTable is bs
//echo createSelect(array('S1', 'S2'); will output (SELECT S1.id AS S1_id, S1.item AS S1_item, S1.price AS S1_price, S1.qty AS S1_qty, 'S1' as Source FROM S1) UNION (SELECT S2.id AS S2_id, S2.item AS S2_item, S2.price AS S2_price, S2.qty AS S2_qty, 'S2' as Source FROM S2) UNION (SELECT all_items.id AS all_items_id, all_items.item AS all_items_item, all_items.price AS all_items_price, all_items.qty AS all_items_qty, 'all_items' as Source FROM all_items)
I need to display in alphabetical order a list of name and surname (order by surname).
The problem is I can't do a ORDER BY in SQL query because I retrieve my users ID in one table and retrieve the informations in another table.
My PHP code:
$sql = "select id FROM $table_name";
$result = $wpdb->get_results($sql);
foreach ($result as $record) {
$id = $record->id;
$sql2 = "select field_name, field_val FROM $table_name2 where sub_id = $id";
$result2 = $wpdb->get_results($sql2);
foreach ($result2 as $record2) {
if($record2->field_name == "Nom :") {
$surname = ucfirst(stripslashes($record2->field_val));
}
if($record2->field_name == "Prénom :") {
$name = ucfirst(stripslashes($record2->field_val));
}
}
echo $name . " " . $surname . "<br/>";
}
Here the architecture of the second table:
f_id sub_id field_name field_val
127 19 Prénom : Philippe
128 19 Nom : Nailloux
129 20 Prénom : John
130 20 Nom : Drumond
Have you an idea how I can display my list ordered by surname alphabetically?
Thanks.
You can do the trick by using this SQL query :
SELECT t1.id AS user_id,
t2.field_val AS surname,
t3.field_val AS name
FROM $table_name t1
JOIN $table_name2 AS t2
ON ( t2.sub_id = t1.id
AND t2.field_name = 'Nom :' )
JOIN $table_name2 AS t3
ON ( t3.sub_id = t1.id
AND t3.field_name = 'Prénom :' )
ORDER BY t2.field_val
The query will return all the infos needed (user_id, surname and name) ordered by surname.
Use subqueries!
In your example, let's say you have 100 users.
In first query you get your users ids, then for each user you query database for one's data. That's 101 queries for a simple operation! What if you have 10 visits per seconds? That's more than 1000 queries.
There are many strategies (subquery, join, two queries with in () in second one) but in this case consider that:
SELECT
field_name, field_val
FROM
$table_name2
WHERE
sub_id IN(
SELECT
id
FROM
$table_name
) as sq1
ORDER BY field_val ASC;
Also consider using PHP PDO, or at least proper escaping of data you put in queries.
Here is my table structure,
Im try run query
$sql = mysql_query("SELECT content,niche, COUNT(content) TotalCount FROM table_name GROUP by content HAVING COUNT(content)>=2");
I i think is give me corect result, but have problem to list result with php and make delete button to delete one of duplicated rows
Im get result in php
Content ID - Niche ID - TotalCount
208 - 2 - 2
210 - 32 - 3
But result should be
Content ID - Niche ID - TotalCount
208 - 2 - 2
208 - 2 - 2
210 - 32 - 3
210 - 32 - 3
210 - 32 - 3
im try result display with php
while($row = mysql_fetch_assoc($sql)) {
$array[] = $row;
}
foreach($array as $row) {
echo $row['content']." - ".$row['niche']." - ".$row['TotalCount']."<br>";
}
GROUP BY will collapse the results on the field you're grouping, in this case content - hence why you only see two results.
If you want to keep the GROUP BY technique, you can also use GROUP_CONCAT(niche) to pull a comma-separated list of each niche for a given content value:
SELECT
content,
GROUP_CONCAT(niche) AS niche,
COUNT(content) TotalCount
FROM
table_name
GROUP BY
content
HAVING
COUNT(content)>=2;
You can then use PHP's explode(',', $row['niche']) to get each distinct value and then use those to determine which one you want to delete.
foreach($array as $row) {
$niches = explode(',', $row['niche']);
foreach ($niches as $niche) {
echo $row['content'] . " - " . $niche . " - " . $row['TotalCount'] . "<br />";
}
}
I think this is what you're asking for, all duplicate rows (with row_id) and how many times they are duplicated;
SELECT a.row_id, a.content, a.niche, cnt
FROM table_name a
JOIN (
SELECT MIN(row_id) m, COUNT(*) cnt, niche,content
FROM table_name
GROUP BY content,niche
HAVING COUNT(*)>1
) b
ON a.niche=b.niche
AND a.content=b.content
An SQLfiddle to test with.
Make the following change in sql:
$sql = mysql_query("SELECT content,niche, COUNT(content) TotalCount FROM table_name HAVING COUNT(content)>=2");
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";
?>