I am hoping for some help making my queries more efficient if possible. I have two tables. One which contains the types of content available and another which contains content linked to the type table by a type id.
I am trying to select from the content table and group the results by type_id. I am currently using a query inside a loop to do this so it is selecting again from the second table for each type_id. Is there a better/more efficient way to do this?
Here are my current tables and queries:
type_id type
1 type 1
2 type 2
id title type_id content
1 test1 1 test content 1
2 test2 2 test content 2
3 test3 1 test content 3
$query="select type_id, type from type_table";
foreach($query as $type){
$query="select title, content from content_table WHERE type_id=$type['type_id']";
}
I hope this makes sense.
Thanks
Your example appears to select all possible values from the content table, albeit in batches of a given type at a time. So select title, content from content_table would surely do this whole thing in one go, without looping.
To put each type_id into a new div, you could do something like this:
SELECT title, content, t.type_id, t.type
FROM content_table c
JOIN type_table t ON t.type_id = c.type_id
ORDER BY t.type_id
// pseudo-code
prev_type_id = -1
print "<div>"
foreach row:
if type_id != prev_type_id:
prev_type_id = type_id
print "</div><div>"
print "</div>"
(edited based on comments)
Use a join and order by. Something like (no guarantee for syntactical correctness):
SELECT
c.title, c.content, t.type_id, t.type
FROM
type_table t, content_table c
WHERE
c.type_id = t.type_id
ORDER BY
t.type_id
Sure, you could join the two tables.
In this example, however, it doesn't appear that you even need to use the type_table. You could just sort your query by type_id:
select title, content from content_table order by type_id;
What is the expected result ?
This is what I think you want.
$sql = 'SELECT t.type, c.title, c.content
FROM `content_table` c
INNER JOIN `type_table` t ON c.type_id = t.type_id
ORDER BY c.type_id ASC'
// Dont use a foreach-loop to loop over the results. While-loop is ideal
while ($row = <query or fetch from resultset here>) {
..
}
Related
$query='SELECT * FROM #__virtuemart_products as a
LEFT JOIN #__virtuemart_products_en_gb as b ON a.virtuemart_product_id = b.virtuemart_product_id
INNER JOIN #__virtuemart_product_categories as c ON a.virtuemart_product_id=c.virtuemart_product_id
INNER JOIN #__virtuemart_categories_en_gb as d ON c.virtuemart_category_id = d.virtuemart_category_id
WHERE b.slug LIKE "'.$current.'%" AND a.product_parent_id = 0
AND d.category_name="'.$query_title.'"' ;
$db->setQuery($query);
$options=$db->loadObjectList();
This is the query i use to parse some products from my db. The problem is:
Table: virtuemart_products_en_gb has a collumn named slug
Table: virtuemart_categories_en_gb has also a collumn named slug
When i used $row->slug it parsed the virtuemart_categories_en_gb slug.
So after i var_dumped the ObjectList i see that there is only 1 collumn named slug. After i used the same query in phpmyadmin, it returns me 2 collumns named slug.
I think i could fix that selecting every single record individual and setting first slug as slug1 and second as slug2.
For example: SELECT id,username,password,b.slug as slug1,c.slug as slug2 etc
Is there any better way ? Cause i need to parse really many fields and that would make the query really huge.And why the php query returns only 1 field named slug while phpmyadmin returns both of em ?
Thanks in advance.
You can specify * after selecting the columns with the same name. For example,
SELECT *, b.slug as slug1,c.slug as slug2
FROM #__virtuemart_products as a
LEFT JOIN #__virtuemart_products_en_gb as b ON a.virtuemart_product_id = b.virtuemart_product_id
INNER JOIN #__virtuemart_product_categories as c ON a.virtuemart_product_id=c.virtuemart_product_id
INNER JOIN #__virtuemart_categories_en_gb as d ON c.virtuemart_category_id = d.virtuemart_category_id
WHERE b.slug LIKE "'.$current.'%" AND a.product_parent_id = 0
AND d.category_name="'.$query_title.'"
I have two tables, Table A and Table B. For each record in table A there are many records in Table B; thus, a one to many relationship exists between tables A and B. I want to perform a query so that for each row returned from table A, all of the corresponding rows will be returned from table B. From what I understand I'll need to use a INNER Join - however, how would I go about accessing all of the returned rows through say, PHP?
$sql = "Select A.ID, B.Name * From A INNER JOIN B ON A.ID = B.ID";
A.ID | B.fName | B.lName
1 nameone lnameone
1 nametwo lnametwo
2 namethree lnamethree
4 namefour lnamefour
Now that I have the above results, I want to use PHP to loop through all of the values of B.Name only for a single A.ID at a time. So, the results I want would look like:
1.
nameOne lNameOne
nameTwo lnametwo
2. namethree lNamethree
4. nameFour lNameFour
Basically, I'm trying to group the query results by the ID in table A.
I appreciate the help very much!
Thank you,
Evan
You could just Google "php get from database," and use some normal array pre-processing, but I worry the advice you find may not be ideal. Here's what I'd do:
$pdo = new PDO('mysql:host=host;dbname=dbname', 'user', 'pass');
$result = $pdo->query(<<<SQL
SELECT
ID,
Name
FROM
A
-- Alternative to `JOIN B USING(ID)` or `JOIN B ON (A.ID = B.ID)
NATURAL JOIN B
SQL
);
$a = array();
while ($row = $result->fetch()) {
if (!isset($a[$row['ID']]) {
$a[$row['ID']] = array();
}
$a[$row['ID']][] = $row['Name'];
}
You could also GROUP BY the ID and GROUP_CONCAT the names to be exploded in PHP later to skip the manual array creation and reduce some iteration (although SQL will do more in that case).
Adding a simple ORDER BY A.ID to the SQL query would probably get you quite far in "grouping" the items together. It's difficult to give a more detailed answer without knowing exactly what you want to do with the "groups".
Sorry, guys.I am quite new in mysql but I do need help from getting and merging data from 2 tables.
table_a
ID | TITLE | CONTENT | DATE
table_b
ID | POST_ID | IMAGE
Here's my code
$query = "SELECT table_a.*, table_b.IMAGE FROM table_a
LEFT JOIN table_b
ON table_a.ID = table_b.POST_ID
ORDER BY table_a.DATE";
$mysql_result = mysql_query($query);
$result = array();
while ($row = mysql_fetch_assoc($mysql_result)) {
$result[] = $row;
}
print json_encode($result);
However, for those record in table_a which got more than 1 IMAGE, my json contain duplicated CONTENT with different IMAGES.
Is there any methods to merge IMAGE with the same ID into a single record?
Thanks for any helps!
You can use the GROUP_CONCAT function to group the images as a comma-delimited list in one column of your posts table.
If I understand correctly, you want to have all fields from table_a, and only one (maybe combined) field from table_b.
First of all, you have to decide what you want to get, if you have more than one image:
Only 1 image? Use MIN(table_b.IMAGE) or MAX(table_b.IMAGE) in the
following SQL
All images separated by e.g. a comma? Use GROUP_CONCAT(table_b.IMAGE SEPARATOR ',') or similar in the following SQL
Next you have to understand, that to get only one row per table_a.ID, you have to group by table_a.ID, so we have
SELECT
table_a.*,
<function from above> AS image
FROM table_a
LEFT JOIN table_b
ON table_a.ID = table_b.POST_ID
GROUP BY table_a.ID
ORDER BY table_a.DATE
I believe what you need is something like this:
SELECT table_a.*, GROUP_CONCAT(table_b.IMAGE) FROM table_a
LEFT JOIN table_b ON table_a.ID = table_b.POST_ID
GROUP BY table_a.*
ORDER BY table_a.DATE
(Not sure if you have to spell out the GROUP BY clause, listing field names individually, or whether .* notation will be accepted here.)
You can perhaps use JOIN instead of LEFT JOIN . In this way it will only load one row
or the other way
put GROUP BY a.ID jsut before ORDER BY...
How do I select a column value as a column name and group the results as a row.
I have a table as such:
id articleId label value
1 1 title Example title
2 1 description This is the description
3 1 author Me
4 2 title Example of another type of article
5 2 description Short description
6 2 author Someone else
Is it possible to select all of the rows and use the label as the column name and the value as the value of that column name and then group them by the article name.
So how I would like to have it returned:
articleId title description author
1 Example title This is the.. Me
2 Example of an.. Short descr.. Someone else
I'm using this for a CMS where the user can define the fields for an article so we don't have to customize the table's. This is why i'm not making the tables as the I would like to have it returned. I am also aware that I can just as easily convert the result to this in php.
-- edit --
Can this be done without knowing what labels are added? In this example im using title, description and author. But it could very well be something totally different like title, shortDescription, availableTo, techInformation, etc.. The idea is that the article's are customizable for the user without needing to change the database and query's
I figured I'd better post as an answer, even if not what OP would like to hear. What you are asking to do is to populate a query with a variable number of columns based on the distinct values within column label, all associated with articleID. Taking your specific example, the following would be the resultant query that I would most likely go to in this instance (though the example from #Devart is equally valid)
SELECT
t.id,
t.articleId,
t1.value AS title,
t2.value AS description,
t3.value AS author
FROM `tableName` t
LEFT JOIN `tablename` t1
ON t1.article_id = t.article_id AND t1.label = 'title'
LEFT JOIN `tablename` t2
ON t2.article_id = t.article_id AND t2.label = 'description'
LEFT JOIN `tablename` t3
ON t3.article_id = t.article_id AND t3.label = 'author'
Now expanding this to account for up to n labels, we get the following query (metacode included, this query will NOT execute verbatim)
SELECT DISTINCT label FROM `tableName`;
SELECT
t.id,
t.articleId
// for (i=1;i<= number of distinct labels) {
,t[i].value AS [value[i]]
// }
FROM `tableName` t
// for (i=1;i<= number of distinct labels) {
LEFT JOIN `tablename` t[i]
ON t[i].article_id = t.article_id AND t[i].label = [value[i]]
// }
;
So what you can do is one of the following.
SELECT t.* FROM tablename t and then have PHP process it as required
SELECT DISTINCT label FROM tablename and have PHP build the second query with the many LEFT JOINs (or MAX / GROUP BY logic if preferred)
Create a Stored Procedure to do the same as #2. This would most likely be more efficient than #2 however may be less efficient overall than #1.
You can use pivote table trick -
SELECT
articleId,
MAX(IF(label = 'title', value, NULL)) AS title,
MAX(IF(label = 'description', value, NULL)) AS description,
MAX(IF(label = 'author', value, NULL)) AS author
FROM
table
GROUP BY
articleId
Try below :
select t1.articleId,t1.title,t1.description,t1.author
from tablename as t1
left join (select max(articleId) as articleId
from tablename
group by articleId ) as t2
on t1.articleId=tsm.articleId where [.....]
I have 4 tables:
categories - id, position
subcategories - id, categories_id, position
sub_subcategories - id, subcategories_id, position
product - id, sub_subcategories_id, prod_pos
Now I'm doing tests to find out what's wrong with my query.
So i want to select sub_subcategories, and to get someting like that:
[[1,2,3,4,5,6], [1,2,3,4,5,6,7]], [[1,2,3,4,5,6], [1,2,3,4]]
Each [] means: big - categories, small - subcategory, and the numbers are position in sub_subcategories. I want the [] to order by their "position" field, so query:
SELECT id FROM sub_subcategories_id
WHERE subcategories_id IN (
SELECT id
FROM subcategories_id
WHERE categories_id IN (
SELECT id FROM categories
WHERE id = 'X' ORDER BY position)
ORDER BY position)
ORDER BY position
is somehow wrong, because I get:
1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,6,6,6,7
Dunno why - does last "ORDER BY position" destroy everything?
You need to apply all of your desired ordering in the outermost query - ORDERing within subqueries doesn't make any sense - the question "is this ID in <this list>?" has the same answer, no matter what order the list is in (indeed, more property, <this list> is a set, which has no order).
So you'll need to get all of the columns you need to order by in your outermost query.
Something like:
SELECT ssi.ID
from
sub_subcategories_id ssi
inner join
subcategories_id si
on
ssi.subcategories_id = si.id
inner join
categories c
on
si.categories_id = c.id
where
c.id = 'X'
order by
c.position,
si.position,
ssi.position
As it stands now, your query would never return a 'set' of numbers as is. If you ignore all the subselects, you're essentially doing:
SELECT id FROM sub_subcategories_id
ORDER BY position
which would only return one column: the sub_sub_categories_id. You'd be better off doing something like:
SELECT cat.id, subcat.id, subsubcat.id
FROM sub_sub_categories AS subsubcat
LEFT JOIN sub_categories AS subcat ON subcat.id = subsubcat.subcategories.id
LEFT JOIN categories AS cat ON cat.id = subcat.category_id
WHERE (cat.id = 'X')
ORDER BY cat.id, subcat.id, subsubcat.id
That'll return 3 columns ordered by the various IDs. If you don't need the individual sub_sub_categories values, and just want them as a single string value, you can mess around with GROUP_CONCAT() and do various bits of grouping:
SELECT cat.id, subcat.id, GROUP_CONCAT(subsubcat.id)
FROM ...
...
WHERE (cat.id = 'X')
GROUP BY cat.id, subcat.id, subsubcat.id
ORDER BY ...