Im a little puzzled here, can someone just look over this query and tell me am i doing anything wrong?
SELECT d.* FROM as_downloads d LEFT JOIN as_categories c ON (d.download_category_id = c.category_id) WHERE d.download_category_id != -1 LIMIT 30
Fetching the rows from the as_downloads table but not joining the categories table..
Theres no error what so ever, Ive tested in PHPMyAdmin and same result, Here's the PHP Code used
class Model_Downloads extends ModelType_PDO
{
public function fetchDownloads($limit)
{
$p = Registry::get('Config')->Database->prefix;
$query = "SELECT d.* FROM ".$p."downloads d LEFT JOIN ".$p."categories c ON d.download_category_id = c.category_id WHERE d.download_category_id != -1 LIMIT :limit";
$this->query = $this->prepare($query);
$this->query->bindValue(':limit',$limit,PDO::PARAM_INT);
if($this->query->execute())
{
return $this->query->fetchAll(PDO::FETCH_CLASS);
}
return false;
}
}
Your query is only selecting columns from the downloads table - d.*. You just need to specify the columns that you need from categories.
Related
Really new to working with CI4's Model and struggling to adapt my existing MySQL JOIN queries to work with the examples in its User Guide.
I have adapted part of my code like so:
public function brand_name($brand_name_slug)
{
return $this->asArray()
->where('availability', 'in stock')
->where('sku !=', '')
->where('brand_name_slug', $brand_name_slug)
->groupBy('gtin')
->orderBy('brand_name, subbrand_name, product, size, unit')
->findAll();
}
It works fine. I have looked at examples, and figured out I can add the code ->table('shop a') and it still works, but I also need to to add the following JOIN statement:
JOIN (SELECT gtin, MIN(sale_price) AS sale_price FROM shop GROUP BY gtin) AS b ON a.gtin = b.gtin AND a.sale_price = b.sale_price
As soon as I add ->join('shop b', 'a.gtin = b.gtin and a.sale_price = b.sale_price') I get a '404 - File Not Found' error.
When I look at all examples of CI4 joins and adapt my code to fit, my foreach($shop as $row) loop generates a 'Whoops...' error because they end with a getResult() or getResultArray - instead of findAll().
Which is the way forward, and do I need to change my foreach loop.
Full MySQL statement:
SELECT * FROM shop a JOIN (SELECT gtin, MIN(sale_price) AS sale_price FROM shop GROUP BY gtin) AS b ON a.gtin = b.gtin AND a.sale_price = b.sale_price WHERE availability = 'in stock' AND sku != '' AND brand_name_slug = $brand_name_slug GROUP BY gtin ORDER BY brand_name, subbrand_name, product, size
Query builders have their limits. That's why the query method exists. If you have a complex query I'd advise you to just use $this->query();.
It will make you lose less time and effort converting something you know already works. And in the top of that, while converting complex queries you usually end up using the query builder but with big part of your SQL in it.
In your model extending CodeIgniter\Model :
$query = $this->db->query("SELECT * FROM shop a JOIN (SELECT gtin, MIN(sale_price) AS sale_price FROM shop GROUP BY gtin) AS b ON a.gtin = b.gtin AND a.sale_price = b.sale_price WHERE availability = 'in stock' AND sku != '' AND brand_name_slug = \$brand_name_slug GROUP BY gtin ORDER BY brand_name, subbrand_name, product, size");
// your array result
$result_array = $query->getResultArray();
// your object result
$result_object = $query->getResult();
BaseBuilder Class in Codeigniter expects the first join parameter to be the table name. So try passing the table name and join it on the table name itself. I haven't personally used the table aliases so I might also be wrong.
Following are the parameter that the JOIN query expects :
public function join(string $table, string $cond, string $type = '', bool $escape = null)
Here, it expects the first name be a table, so try out by switching aliases for the table's name directly.
For your second part of query, It would be better if you could show the whole error rather than just posting the first of the error.
Managed to figure it out in the end:
public function brand_name($brand_name_slug)
{
return $this
->db
->table('shop a')
->select()
->join('(SELECT sku, MIN(sale_price) AS sale_price FROM shop GROUP BY sku) AS b', 'a.sku = b.sku AND a.sale_price = b.sale_price')
->where('availability', 'in stock')
->where('a.sku !=', '')
->where('brand_name_slug', $brand_name_slug)
->groupBy('a.sku')
->orderBy('brand_name, subbrand_name, product, size, unit')
->get()
->getResult();
}
Thanks for all your pointers!
I'm trying to filter product collection with multiple OR filter with this code :
$values = ['xxx','xxx'];
$filters = [];
$filters[] = $this->_filterBuilder
->setField('field_a')->setConditionType('in')
->setValue($values)
->create();
$filters[] = $this->_filterBuilder
->setField('field_b')
->setConditionType('in')
->setValue($values)
->create();
// two more filter like that
$filterGroup = $this->_filterGroupBuilder
->setFilters($filters)
->create();
$searchCriteria = $this->_searchCriteriaBuilder
->setFilterGroups([$filterGroup])
->create();
$products = $this->_productRepository->getList($searchCriteria)->getItems();
Problem is collection return 0 result instead of two. After analyze sql query generated by Magento eav table are joined with INNER JOIN like that :
INNER JOIN `catalog_product_entity_text` AS `at_field_b` ON (`at_field_b`.`row_id` = `e`.`row_id`) AND (`at_field_b`.`attribute_id` = '204') AND (`at_field_b`.`store_id` = 0)
If on raw sql query I execute it by replacing INNER JOIN by LEFT JOIN it works, i've got my results.
So my question is how can I "force" magento to left join instead of inner ? Or maybe it's a pure coincidence and real reason isn't the left/inner join
I didn't precise but field_a,field_b,etc... aren't not required so they could be empty for products
Using Microsoft SQL Entity Framework I've got a query where sometimes I have a filter condition and sometimes I don't, so I tried to do what I've shown below. If the condition is not null then instead of doing the query as expected it queries everything from the Org_Hierarchy table, and then queries everything from the Workers table, and then dies as that takes too long:
void SomeMethod(Func<PRT, bool> whereClause) {
IQueryable<PRT> query;
if (whereClause != null) {
query = PRT.Where(whereClause).AsQueryable();
} else {
query = PRT.AsQueryable();
}
var data = from prt in query
// LEFT OUTER JOIN Worker a ON prt.assigned_to = a.WWID
join a_join in Worker on prt.assigned_to equals a_join.WWID into a_grp
from a in a_grp.DefaultIfEmpty()
// LEFT OUTER JOIN Worker c ON prt.closed_by = c.WWID
join c_join in Worker on prt.closed_by equals c_join.WWID into c_grp
from c in c_grp.DefaultIfEmpty()
// LEFT OUTER JOIN Worker r ON prt.requestor = r.WWID
join r_join in Worker on prt.requestor equals r_join.WWID into r_grp
from r in r_grp.DefaultIfEmpty()
// LEFT OUTER JOIN Org_Hierarchy o ON prt.org3 = o.OrganizationHierarchyUnitCd AND o.OrganizationHierarchyUnitTreeLevelNbr = 3 AND o.Active = true
join o in Org_Hierarchy on prt.org3 equals o.OrganizationHierarchyUnitCd
select new PrtInput {
If I change the query and put something direct in there, just for testing, like where prt.id == Guid.NewGuid() right above the last line shown then the query returns in one second. What's the trick to be able to dynamically add a where clause to the query?
The above code is from LinqPAD which is why the normal "context" stuff is all missing.
I'm not sure , but i think you should use something like this :
Expression<Func<PRT ,bool>> whereClause
Insted of:
Func<PRT ,bool> whereClause
When you using Func<> , first fetch data from db to memory then filter data in memory ,but if you use Epression<> filter send to sql and return result.
Also for the better performnce you can use AsNoTracking() like this:
if (whereClause != null) {
query = PRT.Where(whereClause).AsQueryable().AsNoTracking();
} else {
query = PRT.AsQueryable().AsNoTracking();
}
When you only want run query on yout database without any Insert ,update or delete on result , it better use AsNoTracking.
I hope this answers your question.
I am trying to structure a SQL query with complex nested select operation!
My original SQL query successfully JOINS around 30 tables, the data are retrieved as wanted! However every fetched record in the 30 tables
has many records in another table called (Comments)! What I want to do is to atribute every record in the (Comments table) to its record in the other
30 tables by IDs and retrieve them all together in one query. Yet this is not the only challenge, some of the 30 tables have in addition to the records in
(Comments table) more records in another table called (extras), so i am looking for additional subquery within the main subquery within
a LEFT JOIN inside the outter main query.
To make the idea more clear; without subquery the script will be as following:
$query = $mysqli->query("
SELECT
parent1.parent1_id,
parent1.child1_id,
parent1.child2_id,
parent1.child3_id,
parent2.parent2_id,
parent2.child1_id,
parent2.child2_id,
parent2.child3_id,
child1.child1_id,
child1.child1_content,
child2.child2_id,
child2.child2_content,
child3.child3_id,
child3.child3_content
FROM
parent1
LEFT JOIN child1
ON child1.child1_id = parent1.child1_id
LEFT JOIN child2
ON child2.child2_id = parent1.child2_id
LEFT JOIN child3
ON child3.child3_id = parent1.child3_id
LEFT JOIN followers
ON parent1.user_id = followers.followed_id
AND parent1.parent1_timestamp > followers.followed_timestamp
AND parent1.parent1_id NOT IN (SELECT removed.isub_rmv FROM removed)
AND parent1.parent1_hide = false
WHERE
followers.follower_id = {$_SESSION['info']}
{$portname_clause}
ORDER BY
parent1.parent1_timestamp DESC
LIMIT
{$postnumbers}
OFFSET
{$offset}
")
// Now fetching and looping through the retrieved data
while($row = $query->fetch_assoc()){
echo $row['child1_content'];
$subquery1 = $mysqli->query("SELECT extras.child1_id,
extras.extrasContent FROM extras WHERE extras.child1_id =
{$row['child1_id']}");
while($row1 = $subquery1->fetch_assoc()){
echo $row1['extrasContent'];
}
echo $row['child2_content'];
$subquery2 = $mysqli->query("SELECT extras.child2_id,
extras.extrasContent FROM extras WHERE extras.child2_id =
{$row['child2_id']}");
while($row2 = $subquery2->fetch_assoc()){
echo $row2['extrasContent'];
}
echo $row['child3_content'];
$subquery3 = $mysqli->query("SELECT extras.child3_id,
extras.extrasContent FROM extras WHERE extras.child3_id =
{$row['child3_id']}");
while($row3 = $subquery3->fetch_assoc()){
echo $row3['extrasContent'];
// Here i need to run additional query inside the subquery 3 to retrieve the (Comments table) data beside (extras table)
$subquery4 = $mysqli->query("SELECT comments.comment_id, comments.comment FROM comments WHERE comments.child3_id = {$row['child3_id']} OR comments.child3_id = {$row3['child3_id']}");
while($row4 = $subquery4->fetch_assoc()){
echo $row4['comment'];
}
}
} // No sane person would make such code
Because the code above would be totally rediclious i searched for a better way to carry it out, and thats where i came across the subquery
concept, but i do not know anything about subqueries, and shortly after i studied it i came up with this messy code, check it below!
I am not posting the origianl code here because it is too long, i am including a virtual example of the tables i want to apply the
query on in order to demonstrate the process.
SELECT
parent1.parent1_id,
parent1.child1_id,
parent1.child2_id,
parent1.child3_id,
parent2.parent2_id,
parent2.child1_id,
parent2.child2_id,
parent2.child3_id
FROM
parent1
LEFT JOIN
( SELECT
child1.child1_id,
child1.child1_content
FROM
child1
WHERE
child1.child1_id = parent1.child1_id ) child1
( SELECT extras.extrasID, extras.extrasContent
FROM
extras
WHERE
extras.child1_id = child1.child1_id )
ON parent1.child1_id = child1.child1_id
LEFT JOIN child2
( SELECT
child2.child2_id,
child2.child2_content
FROM
child2
WHERE
child2.child2_id = parent1.child2_id )
( SELECT
extras.extrasID,
extras.extrasContent
FROM
extras
WHERE
extras.child2_id = child2.child2_id )
ON parent1.child2_id = child2.child2_id
LEFT JOIN child3
( SELECT
child3.child3_id,
child3.child3_content
FROM
child3
WHERE
child3.child3_id = parent1.child3_id )
( SELECT
extras.extrasID,
extras.extrasContent
FROM
( SELECT
comments.comment_id,
comments.comment
FROM
comments
WHERE
comments.child3_id = extras.child3_id ) extras
JOIN child3
ON extras.child3_id = child3.child3_id )
ON parent1.child3_id = child3.child3_id
LEFT JOIN followers
ON parent1.user_id = followers.followed_id
AND parent1.parent1_timestamp > followers.follower_timestamp
AND parent1.parent1_id NOT IN (SELECT removed.isub_rmv FROM removed)
AND parent1.parent1_hide = false
WHERE
followers.follower_id = {$_SESSION['info']}
{$portname_clause}
ORDER BY
parent1.parent1_timestamp DESC
LIMIT
{$postnumbers}
OFFSET
{$offset} // <-- Sorry for the bad code formatting!
I am using MySql 5.6.37
I did not get the hang of the subquery concept yet, frankly i got lost and confused as i was studying it and for another reason too mentioned in the note below.
Note: I apologize in advance that i might not be on instant reply because where i live there is no electrecity or ADSL or phones and my
USB modem hardly gets signal, i have only two hours of averege three hours a day of electericity generated by a desil generator. i recharge
my laptop and check internet and the remaining one-two hours are for other life stuff.
I know the joke is on me as i am developing a web project without electricity or permanent internet. BUT LIFE DOES NOT GIVE EVERYTHING! lol.
This is how i solved the problem!
SELECT
parent1.parent1_id,
parent1.child1_id,
child1.child1_id,
child1.child1_content,
comments.comment_id,
comments.comment,
comments.child1_id
FROM parent1 LEFT JOIN
(
SELECT comments.comment_id, comments.comment, comments.child1_id
FROM
(
SELECT comments.comment_id,comments. comment, comments.child1_id
FROM comments
) comments JOIN child1
ON comments.child1_id = child1.child1_id
) comments
ON child1.child1_id = comments.
It needs some aliases and then it's good to go.
I'm facing a problem and I'm not finding the answer. I'm querying a MySql table during my java process and I would like to exclude some rows from the return of my query.
Here is the query:
SELECT
o.offer_id,
o.external_cat,
o.cat,
o.shop,
o.item_id,
oa.value
FROM
offer AS o,
offerattributes AS oa
WHERE
o.offer_id = oa.offer_id
AND (cat = 1200000 OR cat = 12050200
OR cat = 13020304
OR cat = 3041400
OR cat = 3041402)
AND (oa.attribute_id = 'status_live_unattached_pregen'
OR oa.attribute_id = 'status_live_attached_pregen'
OR oa.attribute_id = 'status_dead_offer_getter'
OR oa.attribute_id = 'most_recent_status')
AND (oa.value = 'OK'
OR oa.value='status_live_unattached_pregen'
OR oa.value='status_live_attached_pregen'
OR oa.value='status_dead_offer_getter')
The trick here is that I need the value to be 'OK' in order to continue my process but I don't need mysql to return it in its response, I only need the other values to be returned, for the moment its returning two rows by query, one with the 'OK' value and another with one of the other values.
I would like the return value to be like this:
'000005261383370', '10020578', '1200000', '562', '1000000_157795705', 'status_live_attached_pregen'
for my query, but it returns:
'000005261383370', '10020578', '1200000', '562', '1000000_157795705', 'OK'
'000005261383370', '10020578', '1200000', '562', '1000000_157795705', 'status_live_attached_pregen'
Some help would really be appreciated.
Thank you !
You can solve this with an INNER JOIN on the self I think:
SELECT o.offer_id
,o.external_cat
,o.cat
,o.shop
,o.item_id
,oa.value
FROM offer AS o
INNER JOIN offerattributes AS oa
ON o.offer_id = oa.offer_id
INNER JOIN offerattributes AS oaOK
ON oaOK.offer_id = oa.offer_id
AND oaOK.value = 'OK'
WHERE o.cat IN (1200000,12050200,13020304,3041400,3041402)
AND oa.attribute_id IN ('status_live_unattached_pregen','status_live_attached_pregen','status_dead_offer_getter','most_recent_status')
AND oa.value IN ('status_live_unattached_pregen','status_live_attached_pregen','status_dead_offer_getter');
By doing a self-JOIN with the restriction of value OK, it will limit the result set to offer_ids that have an OK response, but the WHERE clause will still retrieve the values you need. Based on your description, I think this is what you were looking for.
I also converted your implicit cross JOIN to an explicit INNER JOIN, as well as changed your ORs to IN, should be more performant this way.