Mysql reducing number of queries - php

I have 3 columns in table1: book, key and value.
| book | key | value |
------------------------------
| 1 | author | a |
| 1 | editor | b |
| 1 | book | c |
Instead of runnuing three queries
$data = mysql_query("
SELECT * FROM table1 WHERE book = '1' AND key = 'author'
") or die(mysql_error());
while($info = mysql_fetch_array( $data ))
{
$value1 = $info['value'];
}
Then repeat this for editor and book.
$value1 $value2 $value3 are inserted in different places on page
Could I do this with one query?

Yes. If there are no other entries with "book = 1" you just query
SELECT * FROM table1 WHERE book = '1'
If there are more entries you can use this query:
SELECT * FROM table1 WHERE book = '1' AND key IN('author','editor','book')
And then create an assoc array:
while($info = mysqli_fetch_assoc( $data ))
{
$value[$info['key']] = $info['value'];
}
...
echo "the book {$value['book']} was written by {$value['author']}";

for create a $value array you have to use this :
$value[] = $info['value'];
instead of this :
$value1 = $info['value'];
Also you can use this code :
$value[]["key"] = $info['key'];
$value[]["value"] = $info['value'];
And for example you can call first row's value with $value[0]["value"]

If you want the values in a single record try this:
SELECT `t1`.`value` AS `value1`, `t2`.`value` AS `value2`, `t3`.`value` AS `value3`
FROM
`table1` AS `t1` CROSS JOIN
`table1` AS `t2` CROSS JOIN
`table1` AS `t3`
WHERE
(`t1`.`book` = 1) AND (`t1`.`key` = 'author')
AND (`t2`.`book` = 1) AND (`t2`.`key` = 'editor')
AND (`t3`.`book` = 1) AND (`t3`.`key` = 'book');

Related

mysql - multiple select with UNION ALL and count() in the same query

I have a DB-table formed like this:
ID | pairname | timeframe | value1 | value2 | value3
I have about 290 pairnames and 4 timeframes and for each timeframe I will have 250 rows.
Table looks like this:
1 | appusd | 1h | 12319 | 129312 | 11111 | 11111
2 | appusd | 1h | 12444 | 123912 | 11221 | 111231
3 | appusd | 4h | 12312 | 123123 | 11111 | 12321
4 | gttusd | 1h | 12342 | 123123 | 11111 | 12321
5 | gttusd | 4h | 12342 | 123123 | 11111 | 12321
I run a PHP script, that will first fill the DB with values and then check every hour if values are on current.
In PHP I loop first to get all pairnames I need from an other table. Inside of this loop, I loop through the 4 different timeframes to create this SELECT:
(
SELECT value1, timeframe
FROM db1
WHERE pairname = 'blabla'
AND timeframe = '1h'
ORDER BY value1 DESC
LIMIT 2
)
UNION ALL (
SELECT value1, timeframe
FROM db1
WHERE pairname = 'blabla'
AND timeframe = '4h'
ORDER BY value1 DESC
LIMIT 2
)
UNION ALL (
SELECT value1, timeframe
FROM db1
WHERE pairname = 'blabla'
AND timeframe = '8h'
ORDER BY value1 DESC
LIMIT 2
)
UNION ALL (
SELECT value1, timeframe
FROM db1
WHERE pairname = 'blabla'
AND timeframe = '2h'
ORDER BY value1 DESC
LIMIT 2
)
it works nicely. But because I have 290 queries out of the loop, it takes some time. (about 9 secs with all the other script part, that's ok.)
Now I do not only want the last 2 entries of each pairname/timeframe but also to count how many entries I have, I need to count each row of each pairname/timeframe.
(
SELECT COUNT( * ) AS rawnr
FROM db1
WHERE pairname = 'blabla'
AND timeframe = '1h'
)
UNION ALL (
...
)
Now I have another 290 queries. and script-time doubles. It's getting slow. Is it possible to count() and select at the same time, if I have this UNION ALL inside of my SELECT?
I've tried it, and it does not work, maybe because of the "limit 2" inside of the same select? I also tried to UNION ALL the count() into a new select, and this did not work either, because UNION wants the same amount of columns.
My solution works with about 17 seconds script-time. After this, I will have to check each result if it's up to date, pull new data from another server and then also delete/add new entries. This will definitely exceed my script-time, and I will have to find a solution for refreshing the script after certain amount of pairname/timeframe editing. (if you know how to reload a php-script at a certain point, that would be also fine!)
EDIT to see the other tables and the script:
The pairname is combined out of 2 names. Name one could be "app" and second "usd".
1st table with names formed like this:
nameID | name | active | value1 | value2 | value3
2nd table contains which names can be paired.
pairID | nameID1 | nameID2 | active | somevalue
I check first which "names" are active and then which pairs are "active". After this I combine the names to get: "appusd". This pairname I use in the third table, there I save all the data to this pairnames.
The reason I use "pairname" as a own raw is, that the data I fill in comes from an API that wants exactly this "pairname", so I can handle data better later on.
The thing is, that I do not want all names, and not all pairname-combinations.
All this has a script-time of 0,7 sec. So it's fine.
$tradeagainst = array("ABC","USD");
$timeframearr = array("1h","2h","4h","8h");
$tradeagainstsql = "";
$namepairarr = array();
$insert = "";
$ticker = array();
$tabelle = "names";
$tabelle2 = "namepairs";
$sqlsc = "SELECT NameID, shortname, nametyp
FROM ".$tabelle."
ORDER BY shortname ASC";
$resultsc = mysqli_query($conn, $sqlsc);
$nameshortnamearr = array();
$nameIDarr = array();
while($rowc = mysqli_fetch_assoc($resultsc)){
$nameshortnamearr []= $rowc["shortname"];
$nameIDarr []= $rowc["NameID"];
if(in_array($rowc["shortname"],$tradeagainst)){
if($tradeagainstsql == ""){
$tradeagainstsql .= " AND (".$tabelle2.".tradenameID = '".$rowc["NameID"]."'";
}else{
$tradeagainstsql .= " OR ".$tabelle2.".tradenameID = '".$rowc["NameID"]."'";
}
}
}
if($tradeagainstsql != ""){
$tradeagainstsql .= ") ";
}
$sqls = "SELECT ".$tabelle.".*, GROUP_CONCAT(".$tabelle2.".tradenameID) as trID
FROM ".$tabelle."
LEFT JOIN ".$tabelle2." ON ".$tabelle.".NameID = ".$tabelle2.".NameID
WHERE ".$tabelle.".active != '1'
AND ".$tabelle2.".active != '1'
".$tradeagainstsql."
GROUP BY ".$tabelle.".NameID
ORDER BY ".$tabelle.".shortname";
$results = mysqli_query($conn, $sqls);
if (mysqli_num_rows($results) > 0) {
while($row = mysqli_fetch_assoc($results)) {
$nameID = $row["NameID"];
$shortname = $row["shortname"];
$active = $row["active"];
$nametyp = $row["nametyp"];
$namepairsarr = explode(",",$row["trID"]);
foreach($namepairsarr as $trnameID){
$ct++;
$namepair = $shortname.$nameshortnamearr[array_search($trnameID, $nameIDarr)];
$namepairarr []= $namepair;
}
}
}
this first part I do, to get the $namepairarr. It is also dynamically, to be able to set up, the $tradeagainst, $timeframearr;
The second part is this one:
$tabelle3 = "namepairdata";
$updatearray = array();
foreach($namepairarr as $namepair){
$sqlnp = "";
$sqlnpcount = "";
foreach($timeframearr as $timeframe){
if($sqlnp == ""){
$sqlnp .= "(SELECT value1, timeframe
FROM ".$tabelle3."
WHERE pair = '".$namepair."' AND timeframe = '".$timeframe."' ORDER BY value1 DESC LIMIT 2)";
$sqlnpcount .= "(SELECT count(*) AS rawcount
FROM ".$tabelle3."
WHERE pair = '".$namepair."' AND timeframe = '".$timeframe."')";
}else{
$sqlnp .= " UNION ALL (SELECT value1, timeframe
FROM ".$tabelle3."
WHERE pair = '".$namepair."' AND timeframe = '".$timeframe."' ORDER BY value1 DESC LIMIT 2)";
$sqlnpcount .= " UNION ALL (SELECT count(*) AS rawcount
FROM ".$tabelle3."
WHERE pair = '".$namepair."' AND timeframe = '".$timeframe."')";
}
}
$resultnp = mysqli_query($conn, $sqlnp);
$resultnpc = mysqli_query($conn, $sqlnpcount);
$rowsvalue1 = array();
$rowstimeframe = array();
$rowscount = array();
while($rowkl = mysqli_fetch_assoc($resultnp)){
$rowsvalue1 []= $rowkl['value1'];
$rowstimeframe []= $rowkl['timeframe'];
}
while($rowklc = mysqli_fetch_assoc($resultnpc)){
$rowscount []= $rowklc['rawcount'];
}
$rc = 0;
foreach($timeframearr as $timeframe){
$value11 = "";
$value12 = "";
$timeframecount = $rowscount[$rc]; $rc++;
for($ints = 0; $ints < count($rowstimeframe); $ints++){
if($timeframe == $rowstimeframe[$ints]){
if($value11 == ""){
$value11 = $rowsvalue1[$ints];
}else{
$value12 = $rowsvalue1[$ints];
}
}
}
$updatearray []= array($namepair,$timeframe,$value11,$value12,$timeframecount);
}
Finally I get an array $updatearray, which I will have to do something with.

Dynamically selecting tables in mySQL

I have a query in mySQL
SELECT id FROM admin_products;
which return a list of ids, like so
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+------+
And I was using PHP to dynamically generate tables like
vendor_1, vendor_2, vendor_3, vendor_4, vendor_5
Now I want to write a query to retrieve the price and quantity from the table id
For example
"ENTER QUERY HERE"
Should retrieve
+-----------------------------+
| id | price | quantity |
+-----------------------------+
| 1 | 23| 13| // price and quantity retrieved from table vendor_1 since id=1
| 2 | 158| 85| // price and quantity retrieved from table vendor_2 since id=2
| 3 | 15| 7| // price and quantity retrieved from table vendor_3 since id=3
| 4 | 112| 9| // price and quantity retrieved from table vendor_4 since id=4
| 5 | 123| 199| // price and quantity retrieved from table vendor_5 since id=5
+-----------------------------+
What I'm doing now in PHP is:
$conn = mysqli_connect($server,$user,$pwd,$db);
$sql = "SELECT id FROM admin_products";
$res = mysqli_query($conn,$sql);
if(mysqli_num_rows($res)>0){
while($row = mysqli_fetch_assoc($res)){
$product = array();
$innerSQL = "SELECT price,quantity FROM vendor_".$row['id'];
$innerRes = mysqli_query($conn,$innerSQL);
if(mysqli_num_rows($innerRes)>0){
while($innerRow = mysqli_fetch_assoc($innerRes)){
array_push($product,$row['id']);
array_push($product,$innerRow['price']);
array_push($product,$innerRow['quantity']);
}
}
}
}
But it takes two hits to the mySQL database. Can't it be reduced to one?
EDIT
I have later on realized that my database structure was incorrect and dynamically creating tables is a very bad idea and could spell disaster later on
-Solution 1:
Note: This will only work if you have in your vendor_x tables id for the vendor id to match them with. (As Strawberry said, this is a terrible idea to dynamically generate tables).
After selecting the correct id you can do something like this:
connect to the MySql Server
Then you can create the table name and store it in a variable.
$tableName = 'vendor_' . $id;
I would suggest after that to have a check if the table exists with a simple query:
$sql = "SHOW TABLES LIKE '$tableName'";
If this returns empty result you can throw an exception that the table does not exist or handle it whatsoever way you would like.
After checking every table, to be sure it exists, you can create your query.
$joins = "";
$sql = "
SELECT
v.id,
price,
quantity
FROM
vendors AS v
";
foreach ($ids as $id) {
$tableName = "vendor_" . $id;
$tableAlias = "v".$id;
$joins .= " LEFT JOIN " . $tableName . " AS ". $tableAlias ."
ON (v.id = ". $tableAlias .".vendor_id) ";
}
$sql .= $joins;
Then execute the query.
-Solution 2:
Create only one table to manage your vendors. It should have a structure like this :
`id` // AI value
`vendor_id` // The id of the vendor to easily join it afterwards
`price`
`quantity`
You can name it something like vendor_product or whatsoever
And now you have only one simple query:
$sql = "
SELECT
v.id,
vp.quantity,
vp.price
FROM
vendors AS v
LEFT JOIN vendor_product AS vp
ON (vp.vendor_id = v.id)
";
EDIT for the comment about the structure:
You will need one table for the vendors, such so:
`vendor`:
`id`, //AI value
`username`,
`password` // I suggest to you not to keep it in plain text.
`vendor_product` :
`id`, //AI value
`vendor_id`,
`price`,
`quantity`
I don't know here if you are going to store more information about each product, but this should do the trick.
How to show the product with least price ?
You need to match them by somehow and group by that selecting minimum price.
Try this if it suits
$table = "vendor"."_".$id; // this will create table name if $id = 1 then $table = vendor_1;
mysqli_query($connect , "SELECT * FROM $table");
2nd
If you want to fetch data of all table at once then
1) fetch id from admin_products and store in an array like
$ids = array(1,2,3,4,5);
2) Now loop throw array and create sql;
$sql = "SELECT * FROM ";
$ids = array(1,2,3,4,5);
foreach($ids as $id){
$table = "vendor"."_".$id; // this will create table name if $id = 1 then $table = vendor_1;
$sql .=" $table,";
}
$sql = rtrim($sql,",");// this will trim the last comma
echo $sql;
// output SELECT * FROM vendor_1, vendor_2, vendor_3, vendor_4, vendor_5

How to select record from two different tables

I have two tables which is
+----------------------------+
| task |
+----------------------------+
| id | t_title | t_assign_to |
+----------------------------+
+-----------------------------+
| task_employee |
+-----------------------------+
| id | emp_name | emp_underon |
+-----------------------------+
My question is that i want to fetch t_assign_to FROM task table which having emp_underon = '2' in task_employee table with foreign key (t_assign_to)
<?php
$sql = mysql_query("SELECT * FROM task");/// i got all value from here
$sql=mysql_query("SELECT * FROM task_employee WHERE emp_underon ='2'");// i got all value from here
//$sql=mysql_query("SELECT * FROM task UNION SELECT * FROM task_employee WHERE emp_underon='2'");
$count = mysql_num_rows($sql);
while($row=mysql_fetch_assoc($sql))
{
echo $row['t_assign_to'];
}
?>
I think the t_assign_to is the foreign key for task_employee
So i JOIN them together
Schema 1
$sql = "SELECT * FROM task t INNER JOIN task_employee te ON t.t_assign_to = te.id";
Schema 2
$sql = "SELECT * FROM task t,task_employee te WHERE t.t_assign_to = te.id";
If the field name in table is same with others field in others table, just alter the field name like:
$sql = "SELECT table.field as new_field_name FROM task t,task_employee te WHERE t.t_assign_to = te.id";
For you convenient,
$sql = "SELECT * FROM task t INNER JOIN task_employee te ON t.t_assign_to = te.id WHERE te.emp_underon = '2' "
$q = mysql_query($sql);
$c = mysql_num_rows($q);
if($c > 0)
{
while($r = mysql_fetch_assoc($q))
{
echo $r['t_assign_to'];
}
}
I hope you can get your answer by this query though I did not test this SQL.
select task.t_title, task.t_assign_to, task_employee.id as emp_id, task_employee.emp_name from task inner join task_employee on task.t_assign_to = task_employee.emp_underon where task_employee.emp_underon = 2

Mysql query array

I have two tables:
1 - hotels[id,name,extras] ( name of hotels with column extras which I've select for each one)
2 - extras[id,name] ( here's the extras of hotel like wifi,tv,swim... )
$name = $_GET['name'];
$hotels_q = mysql_query("SELECT * FROM `hotels` WHERE `name`='$name'") or die (mysql_error());
$hotels_row = mysql_fetch_array($hotels_q);
$id = $hotels_row['id'];
$extras = explode(",", $hotels_row['extras']);
$ekstras_q = mysql_query("SELECT * FROM `extras` order by id") or die(mysql_error());
While($ekstras_row = mysql_fetch_array($ekstri_q)){
$eid = $ekstras_row['id'];
$ename = $ekstri_row ['name'];
echo '<ul><li><input type="checkbox" name="extras['.$eid.'][]" value="'.$ename.'"';
if (in_array($eid, $ekstras)) echo'checked';
echo'/>'.$ename.'</li></ul>';
Problem is here extras_q displays all entries with checked ones from table, but I want only to display only checked items!
Since you're storing your extra IDs in one column as a comma separated string, I think you should be able to do this by not exploding that value, and then using the CSV string as an IN criteria in your second query.
//...
$extras = $hotels_row['extras']; // don't explode
// Use IN with the $extras CSV here
$ekstras_q = mysql_query("SELECT * FROM `extras`
WHERE id IN ($extras) ORDER BY id") or die(mysql_error());
If you are able to modify your database, you can instead create a many-to-many relationship between hotels and extras by adding a table to join those two items together instead of using a CSV column as you currently are. This can make it easier to write queries to select the related records.
If you add a third table hotel_extras with columns hotel_id and extra_id, you can insert one row for each extra that each hotel has. For example, if the hotel with id 1 has several different extras, its entries in that table would look like this:
table: hotel_extras
_______________________
| hotel_id | extra_id |
=======================
| 1 | 1 |
| 1 | 3 |
| 1 | 4 |
-----------------------
Here is an example using PDO of how you could query data from a setup like that:
$sql = "SELECT e.id, e.name
FROM hotels h
INNER JOIN hotel_extras he ON h.id = he.hotel_id
INNER JOIN extras e ON he.extra_id = e.id
WHERE h.`name` = ?";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(1, $_GET['name']);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$eid = $row['id'];
$ename = $row['name'];
'<li><input type="checkbox" name="extras['.$eid.'][]" value="'.$ename.'" checked/>'.$ename.'</li>';
}

php mysql group by

this is my table
row | car_id | car_model | car_features |
1 1 CAR 1 Features 1
2 2 CAR 2 Features 2
3 2 CAR 2 Features 3
and i want to make it like
row | car_id | car_model | car_features |
1 1 CAR 1 Features 1
2 2 CAR 2 Features 2, Features 3
and this is my php mysql script:
<?php
$con = mysql_connect("localhost", "root", "root");
mysql_select_db("car", $con);
$format = mysql_query("SELECT c.* , p.*, d.*,f.* ,e.* FROM bsi_car_master c,bsi_car_type p, bsi_car_vendor d, bsi_selected_features f, bsi_car_features e WHERE c.car_type_id=p.id AND c.car_vendor_id=d.id AND c.car_id = f.car_id AND f.features_id = e.id");
$row = 1;
while($srow = mysql_fetch_array($format))
{
blah blah blah....
}
?>
Use GROUP_CONCAT with GROUP BY. Try this -
SELECT `row`, `car_id`, `car_model`, GROUP_CONCAT(`car_features`, ',')
FROM your_table GROUP BY `car_id`
SELECT car_id,car_model,GROUP_CONCAT(car_features,',')
FROM yourtable
GROUP BY car_id,car_model;
$format = mysql_query("SELECT c.* , p.*, d.*,f.* ,e.*,group_concat(`c.car_features`,',') as `carfeatures` FROM bsi_car_master c,bsi_car_type p, bsi_car_vendor d, bsi_selected_features f, bsi_car_features e WHERE c.car_type_id=p.id AND c.car_vendor_id=d.id AND c.car_id = f.car_id AND f.features_id = e.id group by c.car_id");
Hopefully, it's fairly obvious that I'm no PHP coder, but here's another way to do it, without GROUP_CONCAT()...
<?php
/*
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,car_id INT NOT NULL
,car_model VARCHAR(12) NOT NULL
,car_features VARCHAR(20) NOT NULL
);
INSERT INTO my_table VALUES
(1 ,1 ,'CAR 1','Features 1'),
(2 ,2 ,'CAR 2','Features 2'),
(3 ,2 ,'CAR 2','Features 3');
*/
require('path/to/mysqli/connection/stateme.nts');
$query = "
SELECT id
, car_id
, car_model
, car_features
FROM my_table
ORDER
BY car_model;
";
$result = mysqli_query($db,$query);
$car_id = 0;
while($row = mysqli_fetch_assoc($result)){
if ($car_id== $row['car_id']){
echo " >".$row['car_features']."<br>\n";
} else {
echo $row['car_model']."<br>\n >".$row['car_features']."<br>\n";
$car_id = $row['car_id'];
}
} // end of while loop
/*
Outputs...
CAR 1
>Features 1
CAR 2
>Features 2
>Features 3
*/
?>

Categories