$this->db->query("SELECT *
FROM posts
LEFT JOIN sub_category on
sub_category.sub_id = posts.category_post_id
LEFT JOIN categories ON categories.cat_id = sub_category.parent_id
LEFT JOIN images ON images.img_post_id = post.ID WHERE sub_category.sub_id=". $sub_id. " AND
posts.title LIKE %".$keyword."% concat(price,' ', curency) as price,curency,
case when curency= 'EUR' then concat(price,' ',curency)
when curency= 'USD' then concat(price,' ',curency) * 0.73
end as in_euros
ORDER BY CAST(in_euros as DECIMAL) ".$start_from." LIMIT".$num.",".$start)->result_array();
return $query;
Can anyone explain me how to use concat in a case like this one here.
Thanks.
Related
I have
SELECT p.*, gc.*, g.*, m.*, b.*
FROM (products AS p)
LEFT JOIN merchants AS m
ON m.merchantId = p.merchantId
LEFT JOIN brands AS b
ON b.brand = p.brand
LEFT JOIN groups_content gc
ON p.brand = gc.brandsSelect
LEFT JOIN groups g
ON g.group_id = gc.group_id
WHERE `p`.`percentOff` > gc.percent_off
AND `g`.`group_active` = 1
AND `p`.`price_sale` BETWEEN gc.price_min
AND gc.price_max
AND `gc`.`group_content_id` = '180'
AND `p`.`keyword` LIKE '%women%' AND `p`.`keyword` LIKE '%jacket%'
AND `p`.`status` = 1
ORDER BY p.price_sale ASC
this return me 158 results
Also I have
SELECT p.*, gc.*, g.*, m.*, b.*
FROM (products AS p)
LEFT JOIN merchants AS m
ON m.merchantId = p.merchantId
LEFT JOIN brands AS b
ON b.brand = p.brand
LEFT JOIN groups_content gc
ON p.brand = gc.brandsSelect
LEFT JOIN groups g
ON g.group_id = gc.group_id
WHERE `p`.`percentOff` > gc.percent_off
AND `g`.`group_active` = 1
AND `p`.`price_sale` BETWEEN gc.price_min
AND gc.price_max
AND `gc`.`group_content_id` = '180'
AND `p`.`keyword` REGEXP 'women.+jacket'
AND `p`.`status` = 1
ORDER BY p.price_sale ASC
This should return me same result like previous. But returns me just 17 results. What I am doing wrong?
----------
AFTER MANY SEARCHES here it is the right REGEXP
AND p.`keyword` REGEXP '^(.+jacket.+women.+)|^(.+women.+jacket.+).*$'
Your regex and like are not equivalent statements:
CREATE TABLE tab(keyword VARCHAR(100));
INSERT INTO tab(keyword)
VALUES ('jacket for women');
SELECT *
FROM tab p
WHERE `p`.`keyword` LIKE '%women%' AND `p`.`keyword` LIKE '%jacket%';
-- jacket for women
SELECT *
FROM tab p
WHERE p.`keyword` REGEXP 'women.+jacket';
-- (empty)
SqlFiddleDemo
"woman" anywhere in string and "jacket" anywhere in string
vs.
"woman" at the beginning, then any characters then "jacket" at the end
EDIT:
But How do I get -- "woman" anywhere in string and "jacket" anywhere
in string --- using regular expression?
One way is to use:
SELECT *
FROM tab
WHERE keyword REGEXP '.*women.*'
AND keyword REGEXP '.*jacket.*';
I am sure there exists one regex for this case.
so i wanna try to get a filtering tag method, but in the database part is where i get lost, well kind of, because i wrote a raw query that works, but i need the Eloquent result so i can play with the relationships from the model class.
So here is the raw query:
$peticion = DB::select(DB::Raw("SELECT P.id, P.titulo, P.deadline, P.created_at, P.respuesta_id, U.usuario, C.titulo as categoria, C.clase_css as css, TG.Etiqueta
FROM peticiones P
JOIN usuarios U ON U.id = P.usuario_id
JOIN categorias C ON C.id = P.categoria_id
LEFT JOIN (
SELECT PT.peticion_id, T.nombre as Etiqueta
FROM tags T
JOIN peticion_tag PT ON PT.tag_id = T.id
) AS TG ON TG.peticion_id = P.id
JOIN (
SELECT PP.peticion_id
FROM (
SELECT PT.peticion_id, count(PT.peticion_id) AS conteo
FROM peticion_tag PT
WHERE PT.tag_id IN ( $etiquetas )
GROUP BY PT.peticion_id
) PP
WHERE PP.conteo = $len ) AS PPP
ON P.id = PPP.peticion_id
WHERE P.categoria_id = $id ;"));
what it does is that retrieve all the peticiones who has as many tags in it something like this in SO when filtering by tags.
But as i said i need the eloquent so this is my attempt to recreate the raw query:
$pet = Peticion::whereHas('tags', function($q) use ($tags, $len){
$q->whereIn('tag_id', $tags);
})
->where('categoria_id', '=', $id)
->get();
But it returns me all the peticiones who has this tag OR this tag, OR as many has the $tags array this get achieved with the raw query in the
WHERE PP.conteo = $len
but i dont know how to translate to eloquent.
Hope someone can help me, thanks a lot.
There's a query I need to modify. What the query currently does is return search results (ads) based on Ad Title and Ad Description . If any of the search words are either found in ad title or ad description, it returns those results
I want to modify the query so that each ad appears in search results only once for a given ad title... So if there were 5 ads found with the same ad title for the given words in the search , it should return only 1 ad for that ad title...
$sql = "SELECT a.*, UNIX_TIMESTAMP(a.createdon) AS timestamp, ct.cityname,
COUNT(*) AS piccount, p.picfile,
scat.subcatname, cat.catid, cat.catname $xfieldsql
FROM t_ads a
INNER JOIN t_cities ct ON a.cityid = ct.cityid
INNER JOIN t_subcats scat ON a.subcatid = scat.subcatid
INNER JOIN t_cats cat ON scat.catid = cat.catid
LEFT OUTER JOIN t_adxfields axf ON a.adid = axf.adid
LEFT OUTER JOIN t_adpics p ON a.adid = p.adid AND p.isevent = '0'
LEFT OUTER JOIN t_featured feat ON a.adid = feat.adid AND feat.adtype = 'A'
WHERE $where
AND $visibility_condn
AND (feat.adid IS NULL OR feat.featuredtill < NOW())
$loc_condn
GROUP BY a.adid
ORDER BY a.createdon DESC
LIMIT $offset, $ads_per_page";
Edit: $where contains the search expression... if regular expression search is turned on it uses regex otherwise not... $sqlsearch contains the search words that were input by the user...
if ($regex_search) {
$where = "(a.adtitle RLIKE '[[:<:]]{$searchsql}[[:>:]]' OR a.addesc RLIKE '[[:<:]]{$searchsql}[[:>:]]')";
} else {
$where = "(a.adtitle LIKE '$searchsql' OR a.addesc LIKE '$searchsql')";
The "proper" way to do this would be tackle the route cause by working out why the duplicates are appearing in the first place. It will be something to do with the JOINs but without looking at the data I'm unable to answer that. If, however you'd like a quick(ish) and dirty way to remove duplicates, could try something like below.
Disclaimer: This is completely untested so there's more likely to be a mistake or two in here - but hopefully no dealbreaker.
SELECT a2.*, UNIX_TIMESTAMP(a.createdon) AS timestamp, ct2.cityname,
COUNT(*) AS piccount, p2.picfile,
scat2.subcatname, cat2.catid, cat2.catname $xfieldsql
FROM
(SELECT subq1.title, MIN(subq1.adid) AS adid
FROM
(SELECT a.*, UNIX_TIMESTAMP(a.createdon) AS timestamp, ct.cityname,
COUNT(*) AS piccount, p.picfile,
scat.subcatname, cat.catid, cat.catname
FROM t_ads a
INNER JOIN t_cities ct ON a.cityid = ct.cityid
INNER JOIN t_subcats scat ON a.subcatid = scat.subcatid
INNER JOIN t_cats cat ON scat.catid = cat.catid
LEFT OUTER JOIN t_adxfields axf ON a.adid = axf.adid
LEFT OUTER JOIN t_adpics p ON a.adid = p.adid AND p.isevent = '0'
LEFT OUTER JOIN t_featured feat ON a.adid = feat.adid AND feat.adtype = 'A'
WHERE $where
AND $visibility_condn
AND (feat.adid IS NULL OR feat.featuredtill < NOW())
$loc_condn
GROUP BY a.adid) subq1
GROUP BY subq.title) subq2
INNER JOIN t_ads a2 ON a2.adid = subq2.adid
INNER JOIN t_cities ct2 ON a2.cityid = ct2.cityid
INNER JOIN t_subcats scat2 ON a2.subcatid = scat2.subcatid
INNER JOIN t_cats cat2 ON scat2.catid = cat2.catid
LEFT OUTER JOIN t_adxfields axf2 ON a2.adid = axf2.adid
LEFT OUTER JOIN t_adpics p2 ON a2.adid = p2.adid AND p2.isevent = '0'
LEFT OUTER JOIN t_featured feat2 ON a2.adid = feat2.adid AND feat2.adtype = 'A'
ORDER BY a2.createdon DESC
LIMIT $offset, $ads_per_page
This could be massively simplified and tidied up e.g. by removing some of the stuff from the subquery but am just giving the general idea to (hopefully) get you up and running...
Explanation
subq2 simply groups by title and picks out an adid from each group (chose to use MIN here but could have used MAX instead).
subq1 is the original query but with ordering and limits removed since these are applied by the outer query.
The outer query joins back on the de-duped IDs and joins back to the ads and other tables (giving them different aliases) in order to select the fields from your original query.
I have this query
$query = "SELECT * FROM items WHERE itemStatus = '1' AND itemAdded > '$timestamp'";
Once this query has returned results I loop through the results
the results array is itemID, itemLocationID, categoryParentID, categoryID, itemName, itemDetails
During the loop I then run three other queries by calling functions within the same class
$locationName = $this->getLocationByName($locationID);
$categoryParentName = $this->getCategoryByName($categoryParentID);
$categoryName = $this->getCategoryByName($categoryID);
the function getLocationByName performs this query;
$q = mysql_query("SELECT * FROM locations WHERE locationID = '$locationID'");
this returns an array of locationID, locationName, locationLink
the function getCategoryByName performs this query;
$q = mysql_query("SELECT * FROM categories WHERE categoryID = '$categoryID'");
this returns an array of categoryID, categoryName, categoryLink
Could someone please help me optimize this query and maybe join them to save doing so many queries.
thanks in advance.
Im now using this query
$q = mysql_query("SELECT
i.itemID,
i.locationID,
i.categoryParentID,
i.categoryID,
i.itemName,
i.itemDetails,
l.*,
c.*
FROM
items i
inner join locations l on i.locationID = l.locationID
inner join categories c on i.categoryID = c.categoryID
WHERE
itemStatus = '1'
AND itemAdded > '$timestamp'")or die(mysql_error());
and the result is
Array
(
[itemID] => 81300
[locationID] => 17
[categoryParentID] => 21
[categoryID] => 183
[itemName] => blah
[itemDetails] => blah
[locationName] => brilliant it pulls in the location as expected.
[locationLink] => blah
[categoryName] => brilliant it pulls in the category as expected.
[categoryLink] => blah
)
[categoryName] => //these are missing for categoryParentID
[categoryLink] => //these are missing for categoryParentID
I would not use * in the select statement
The Query with the joins could be
SELECT
i.itemID,
i.itemLocationID,
i.categoryParentID,
i.categoryID,
i.itemName,
i.itemDetails,
l.*,
c.*
FROM
items i
inner join locations l on i.itemLocationID = l.locationID
inner join categories c on i.categoryID = c.categoryID
WHERE
itemStatus = '1'
AND itemAdded > '$timestamp'
I hope it be useful for you.
Cheers!
I think should be something similar to below query. I do not see where are you using $categoryParentName .
Using your queries and data:
SELECT * FROM items WHERE itemStatus = '1' AND itemAdded > '$timestamp'
SELECT * FROM locations WHERE locationID = '$locationID'
SELECT * FROM categories WHERE categoryID = '$categoryID'
$locationName = $this->getLocationByName($locationID);
$categoryParentName = $this->getCategoryByName($categoryParentID);
$categoryName = $this->getCategoryByName($categoryID);
Please let me know if this returns expected result set. Hope this helps
SELECT
it.itemID, it.itemLocationID, it.categoryParentID, it.categoryID, it.itemName, it.itemDetails,
l.locationID, l.locationName, l.locationLink,
c.categoryID, c.categoryName, c.categoryLink
FROM items it
LEFT JOIN locations l ON l.locationID = it.itemLocationID
LEFT JOIN categories c ON c.categoryID = it.categoryID
WHERE
it.itemStatus = '1'
AND it.itemAdded > '$timestamp'
Update query using categoryParentID - i am not saying is efficient but you can test and optimize as needed.
One option is to update above query - not sure that will work - and for large result sets using OR is not efficient:
LEFT JOIN categories c ON (c.categoryID = it.categoryID OR c.categoryID = it.categoryParentID)
The other option that i see is to get 2 result sets (see below) - one for categId = categId and second for categId = categParentId and combine the result set in one big result set.
SELECT
t.itemID, t.itemLocationID, t.categoryParentID, t.categoryID, t.itemName, t.itemDetails,
l.locationID, l.locationName, l.locationLink,
t.categoryID, t.categoryName, t.categoryLink
FROM
(
SELECT
it.itemID, it.itemLocationID, it.categoryParentID, it.categoryID, it.itemName, it.itemDetails,
c.categoryID, c.categoryName, c.categoryLink
FROM items it
INNER JOIN categories c ON c.categoryID = it.categoryID
WHERE
it.itemStatus = '1'
AND it.itemAdded > '$timestamp'
UNION -- [ALL]
SELECT
it.itemID, it.itemLocationID, it.categoryParentID, it.categoryID, it.itemName, it.itemDetails,
c.categoryID, c.categoryName, c.categoryLink
FROM items it
INNER JOIN categories c ON c.categoryID = it.categoryParentID
WHERE
it.itemStatus = '1' AND
it.itemAdded > '$timestamp'
) AS t
LEFT JOIN locations l ON l.locationID = t.itemLocationID
Other idea - not tested and assuming that id are int - will have to cast as string / char. There are a few options how you can write this query - if you post a structure table and some dummy data i am sure that someone will create a demo / sqlfiddle.
SELECT
it.itemID, it.itemLocationID, it.categoryParentID, it.categoryID, it.itemName, it.itemDetails,
l.locationID, l.locationName, l.locationLink,
c.categoryID, c.categoryName, c.categoryLink
FROM items it
LEFT JOIN locations l ON l.locationID = it.itemLocationID
WHERE
it.itemStatus = '1'
AND it.itemAdded > '$timestamp'
AND c.category ID IN ( SELECT GROUP_CONCAT(categs) FROM (SELECT CONCAT(categoryID, ",", categoryParentID) AS categs FROM items ))
Unless I'm missing something obvious, I'd probably suggest something like this as a first start:
select *
from items i
join locations l
on i.location_id=l.location_id
join categories c
on i.category_id=c.category_id
where item_status='1'
and itemAdded > '$timestamp'
I've been playing with LEFT JOINs and I'm wondering if it's possible to get the SUM of all the ratings so far from all users in the below query. The below get's me the information on if the logged in user has rated or not, but i want to show total ratings from other users also.
$query = mysql_query("
SELECT com.comment, com.comment_id, r.rate_up, r.rate_down
FROM comments com
LEFT JOIN ratings r
ON com.comment_id = r.comment_id
AND r.user_id = '" . $user_id_var . "'
WHERE page_id = '" . $category_id_var. "'");
I've tried the following but i only get one comment/row returned for some reason.
$query = mysql_query("
SELECT com.comment, com.comment_id,
r.rate_up, r.rate_down
SUM(r.rate_up) AS total_up_ratings,
SUM(r.rate_down) AS total_down_ratings,
FROM comments com
LEFT JOIN ratings r
ON com.comment_id = r.comment_id
AND r.user_id = '" . $user_id_var . "'
WHERE page_id = '" . $category_id_var. "'");
Any help appreciated. Do i need a different kind of JOIN?
Have you tried using GROUP BY page_id on the end of your SQL?
You could do it something like this:
SELECT
com.comment,
com.comment_id,
Total.total_down_ratings,
Total.total_up_ratings
FROM comments com
LEFT JOIN
(
SELECT
SUM(r.rate_up) AS total_up_ratings,
SUM(r.rate_down) AS total_down_ratings,
r.comment_id
FROM
ratings r
GROUP BY
r.comment_id
) AS Total
ON com.comment_id = Total.comment_id
AND r.user_id = '" . $user_id_var . "'
WHERE page_id = '" . $category_id_var. "'"
If you use an aggregation function in SQL (like SUM()) you will need a corresponding GROUP BY clause.
In your case the most likely one would be com.comment_id; this will give you the sum of all ratings per comment_id:
I don't know if you are duplicating comment rows for purpose but if not you can try write subselect for ratings like this:
select comment_id, user_id, sum(rate_up) as sum_rate_up,
sum(rate_down) as sum_rate_down from ratings
group_by comment_id, user_id;
and then include it in your join query:
select com.comment, com.comment_id, r.user_id, r.sum_rate_up,
r.sum_rate_down from comments com
left join (select comment_id, user_id, sum(rate_up) as sum_rate_up,
sum(rate_down) as sum_rate_down from ratings
group_by comment_id, user_id) as r
on com.comment_id = r.comment_id where page_id = '".$category_id_var."'