MySQL query from a query result in php - php

How should I go if I wanted to query a query result in php?
Supose I have this..
$result = mysql_query("SELECT * FROM tbl_x WHERE tbl_x.attribute = y");
And now I need to query that $result to filter the results I got from its query. Note that I don't want to do this...
$result2 = mysql_query("SELECT * FROM ( SELECT * FROM tbl_x WHERE tbl_x.attribute = y ) AS tbl_x1 WHERE tbl_x1... etc");
The reason I want to avoid that is I'm getting a "Duplicate column" error when executing a query like that.
I'm looking for something like...
$result = mysql_query("SELECT * FROM tbl_x");
$result2 = mysql_query_result($result);

You can apply more than one term in your search conditions, separated by AND:
$result = mysql_query("SELECT * FROM tbl_x
WHERE tbl_x.attribute = y
AND tbl_x.attribute2 = z");
Re your comments above. It sounds like you are using the Entity-Attribute-Value design.
In order to match multiple attributes, you have to do some tricks. Normally, a WHERE clause can only apply to one row at a time. But since each of your attributes are stored on separate rows, you need to do either one of two solutions:
Join multiple rows into one row, so you can use WHERE on all attributes in one condition.
SELECT config_id
FROM attributes AS s
JOIN attributes AS c USING (config_id)
JOIN attributes AS l USING (config_id)
WHERE (s.attr, s.value) = ('size', 'M')
AND (c.attr, c.value) = ('colour, 'green')
AND (l.attr, l.value) = ('cloth', 'cotton);
Search for any of the several attributes, and then if the number of rows that match is equal to the number of attributes you were searching for, you've found them all.
SELECT config_id
FROM attributes
WHERE (attr, value) = ('size', 'M')
OR (attr, value) = ('colour', 'green')
OR (attr, value) = ('cloth', 'cotton')
GROUP BY config_id
HAVING COUNT(DISTINCT attr) = 3;

You can still have your query of query without getting "duplicate column" error. Just alias and name the columns
$result2 = mysql_query("SELECT tbl_x1.col1, tbl_x1.col2,...etc FROM
(SELECT * FROM tbl_x WHERE tbl_x.attribute = y) AS tbl_x1
WHERE tbl_x1... etc");

Related

Fetch data based on another MySQL query

I have the following two queries. The first query is fetching a key called srNumber from first table called tags and then the second query is using that srNumber to fetch details from a second table called nexttable.
$tagQuery = "SELECT * FROM tags WHERE status = 0 AND currentStage = '1' AND assignedTo = '1' ORDER BY
deliveryDate ASC";
$tagQueryExecute = mysqli_query($conn, $tagQuery);
while($rows = mysqli_fetch_array($tagQueryExecute)){
$srNumber = $rows['srNumber'];
$nextQuery = "SELECT * FROM nexttable WHERE srNumber='$srNumber'";
$nextQueryExecute = mysqli_query($conn, $nextQuery);
$detailsFromNextTable = mysqli_fetch_array($nextQueryExecute);
//Show these details
}
For a small result this is not a big issue. But if the first query got so many results, then second query has to run as many times as number of loop. Is there any other way to do this efficiently?
NB: Please ignore the SQL injection issues with these queries. I just simplified it to show the problem
As you appear to have only 1 row in the second table, you would be better off with a join, MySQL: Quick breakdown of the types of joins gives some more info on the types of joins.
SELECT *
FROM tags t
JOIN nexttable n on t.srNumber = n.srNumber
WHERE t.status = 0 AND t.currentStage = '1' AND t.assignedTo = '1'
ORDER BY t.deliveryDate ASC
This also removes the SQL injection as well.
I would also recommend removing the * and just list the columns you intend to use, this also helps if you have columns with the same names in the different tables as you can add an alias to the specific columns.
FYI - the original problem you have is similar to What is the "N+1 selects problem" in ORM (Object-Relational Mapping)?

Check if specific value exists in mysql column

I have mysql column called categories. It can contain single or multiple values like this: 1 or 2 or 1,2,3 or 2,12...
I try to get all rows containing value 2.
$query = "SELECT * FROM my_table WHERE categories LIKE '2'";
$rows = mysql_query($query);
This returns row if column only has value 2 but not 1,2,3 or 2,12. How I can get all rows including value 2?
You can use either of the following:
% is a wildcard so it will match 2 or 1,2, etc. Anything on either side of a 2. The problem is it could match 21, 22, etc.
$query = "SELECT * FROM my_table WHERE categories LIKE '%2%'";
Instead you should consider the find_in_set mysql function which expects a comma separated list for the value.
$query = "SELECT * FROM my_table WHERE find_in_set('2', `categories`)";
Like #jitendrapurohut said, you can do it using
$query = "SELECT * FROM my_table WHERE categories LIKE '%2%'";
$rows = mysql_query($query);
But is really bad to store collections like this. A better aproach is as follow:
categories(id_c, name) => A table with each category
my_table(id_m [, ...])
categories_my_table(id_c, id_m)
Then use this query:
SELECT *
FROM my_table m
INNER JOIN categories_my_table cm ON m.id_m = cm.id_m
INNER JOIN categories c ON cm.id_c = c.id_c
WHERE
c.id_c = 2;
EDIT:
#e4c5 link explains why it is bad to store collections like this...
SELECT * FROM my_table WHERE categories LIKE '%2%' AND categories!='1,2,3' AND categories!='2,12';

Get two types of number of rows with minimum lines

I have the following query.
$sql = "SELECT customer FROM furniture WHERE id = :id AND category = :cat";
$stmt = $connectdb->prepare($sql);
$stmt->execute(array(':id'=>$id, ':cat'=>"1"));
$resulta = $stmt->fetchAll(PDO::FETCH_ASSOC);
$rowcount = count($result);
This works perfectly. But I have a requirement to get the number of rows from WHERE id = :id AND category = :cat as well as to get the number of rows from WHERE category = :cat. Is it possible to do both of them without having to write all those SELECT query lines twice?
You can use conditional sum to get the 2 different counts something as
select
sum(id = :id AND category = :cat) as count1,
sum(category = :cat) as count2
from furniture;
Later you just fetch the records and get the values of count1 and count2
NOTE : If you just do row count it will always return 1 since its using the aggregate function
I would suggest that you write the query as:
select sum(id = :id) as numCatId, count(*) as numCat
from furniture
where cat = :cat;
Putting the condition in the where clause allows MySQL to use an index on furniture(cat) (or better yet furniture(cat, id). In general, it is a good idea to put common filtering conditions in the where clause. This reduces the number of rows needed for processing the rest of the query.

How to select how many columns have the same value from mysql

I have query that selects goes something like this:
$query = "SELECT members.*
FROM members
JOIN $nombre
ON members.member_ID=$nombre.friends";
$result = mysql_query($query) or die(mysql_error());
$number = mysql_num_rows($result);
$i = 0;
while($msg = mysql_fetch_assoc($result))
{
//store data in arrays
$peer_id[$i] = $msg['member_ID'];
$peer_state[$i] = $msg['home_state'];
$pro_political_views[$i] = $msg['political_views'];
$peer_district[$i] = $msg['district'];
$peer_first[$i] = $msg['first_name'];
$peer_last[$i] = $msg['last_name'];
$peer_issue[$i] = $msg['first_issue'];
$peer_second[$i] = $msg['second_issue'];
$peer_third[$i] = $msg['third_issue'];
$peer_stand[$i] = $msg['iStand'];
$peer_mail[$i] = $msg['email'];
$peer_pic[$i] = $msg['photo'];
++$i;
}
What this essentially does is get all the values from columns in the rows in the members from the members table where the member_ID is present in the $nombre table.
In the members table, there are two columns called "state" and "district". I want to make it so that php could tell me how many different values there are in the state and district columns for this query.
So, how could I go about writing a query or use php to tell how many how many peers are from a given state. I don't want to have to query the db once for each of the fifty states because that would take way too much time for the page to load. So, is there an efficient way to do this?
Thanks
...to tell how many how many peers are
from a given state
For states:
SELECT state, COUNT(m.member_ID) cnt
FROM members m
JOIN $nombre n ON m.member_ID=n.friends
GROUP BY state
and for districts:
SELECT 'district', COUNT(m.member_ID) cnt
FROM members m
JOIN $nombre n ON m.member_ID=n.friends
GROUP BY 'district'
This queries returns distinct values for states and districts and count of peers from them
You could use two queries, like so:
SELECT DISTINCT members.state
FROM members
JOIN $nombre
ON members.member_ID=$nombre.friends
and
SELECT DISTINCT members.district
FROM members
JOIN $nombre
ON members.member_ID=$nombre.friends
This will give you all of the unique states and districts back, which you can use or count or whatever.
Alternatively, add this somewhere in your while loop:
$all_states[$msg['state']] = 1;
$all_districts[$msg['district']] = 1;
Then, after the loop you can:
$state_count = count($all_states);
$district_count = count($all_districts);
The query approach would be faster by itself (assuming an index on the state and district columns), but the latter approach will be faster if you are already executing this loop anyway.
EDIT: To count unique districts in each state, replace
$all_districts[$msg['district']] = 1;
with something like
$all_districts[$msg['state'] . '--' . $msg['district']] = 1;
This will include the state in the array key too, and the count() call later will return all of the unique district-state combinations.
you can save the district in additional array like
$district[] = $msg['district'];
after the loop print_r using a function array_count_values
print_r(array_count_values($district));

A logical problem with two tables

Hey guys, I created a list for fixtures.
$result = mysql_query("SELECT date FROM ".TBL_FIXTURES." WHERE compname = '$comp_name' GROUP BY date");
$i = 1;
$d = "Start";
while ($row = mysql_fetch_assoc($result))
{
$odate = $row['date'];
$date=date("F j Y", $row['date']);
echo "<p>Fixture $i - $d to $date</p>";
}
As you can see from the query, the date is displayed from the fixtures table.
The way my system works is that when a fixture is "played", it is removed from this table. Therefore when the entire round of fixtures are complete, there wont be any dates for that round in this table. They will be in another table.
Is there anyway I can run an other query for dates at the same time, and display only dates from the fixtures table if there isnt a date in the results table?
"SELECT * FROM ".TBL_CONF_RESULTS."
WHERE compid = '$_GET[id]' && type2 = '2' ORDER BY date"
That would be the second query!
EDIT FROM HERE ONWARDS...
Is there anyway I can select the date from two tables and then only use one if there are matches. Then use the rows of dates (GROUPED BY) to populate my query? Is that possible?
It sounds like you want to UNION the two result sets, akin to the following:
SELECT f.date FROM tbl_fixtures f
WHERE f.compname = '$comp_name'
UNION SELECT r.date FROM tbl_conf_results r
WHERE r.compid = '$_GET[id]' AND r.type2 = '2'
GROUP BY date
This should select f.date and add rows from r.date that aren't already in the result set (at least this is the behaviour with T-SQL). Apparently it may not scale well, but there are many blogs on that (search: UNION T-SQL).
From the notes on this page:
//performs the query
$result = mysql_query(...);
$num_rows = mysql_num_rows($result);
//if query result is empty, returns NULL, otherwise,
//returns an array containing the selected fields and their values
if($num_rows == NULL)
{
// Do the other query
}
else
{
// Do your stuff as now
}
WHERE compid = '$_GET[id]' presents an oportunity for SQL Injection.
Are TBL_FIXTURES and TBL_CONF_RESULTS supposed to read $TBL_FIXTURES and $TBL_CONF_RESULTS?
ChrisF has the solution!
One other thing you might think about is whether it is necessary to do a delete and move to another table. A common way to solve this type of challenge is to include a status field for each record, then rather than just querying for "all" you query for all where status = "x". For example, 1 might be "staging", 2 might be "in use", 3 might be "used" or "archived" In your example, rather than deleting the field and "moving" the record to another table (which would also have to happen in the foreach loop, one would assume) you could simply update the status field to the next status.
So, you'd eliminate the need for an additional table, remove one additional database hit per record, and theoretically improve the performance of your application.
Seems like what you want is a UNION query.
$q1 = "SELECT DISTINCT date FROM ".TBL_FIXTURES." WHERE compname = '$comp_name'";
$q2 = "SELECT DISTINCT date FROM ".TBL_CONF_RESULTS.
"WHERE compid = '$_GET[id]' && type2 = '2'";
$q = "($q1) UNION DISTINCT ($q2) ORDER BY date";

Categories