I want to do something like this:
SELECT a.*, (SELECT COUNT(*) FROM b where b.col1 = a.col2) as count FROM a
is it possible using propel criteria or not?
$c = new Criteria();
$c->addSelectColumn(aPeer::TABLE_NAME.'.*');
$c->addAsColumn('count', '(SELECT COUNT(*) FROM b WHERE b.col1 = a.col2)');
aPeer::doSelect($c);
Related
In my app, I have vehicles which are assigned to a specific class. In the query below I am trying to select all classes which have at least one vehicle in it that is in a certain area.
The code below works fine, however if there are multiple vehicles inside of the class that fit the location parameter, multiple instances of the class are returned in the results.
How can I structure this query so only one instance of every class is returned, regardless of how many vehicles inside of the class fit the paramater?
$get_veh = $pdo->prepare("SELECT * FROM tbl_car_class_category JOIN tbl_vehicles ON tbl_vehicles.veh_class_id = tbl_car_class_category.id_class_cat WHERE tbl_vehicles.veh_advanceLng between (:loc_long-:radius/cos(radians(:loc_lat))*69) and (:loc_long+:radius/cos(radians(:loc_lat))*69) and veh_advanceLat between (:loc_lat-(:radius/69)) and (:loc_lat+(:radius/69)) AND veh_status=:veh_status");
$get_veh->bindparam(":veh_status", $veh_status);
$get_veh->bindparam(":loc_lat", $loc_lat);
$get_veh->bindparam(":loc_long", $loc_long);
$get_veh->bindparam(":radius", $radius);
$get_veh->execute();
If the intent is return just rows from the category table, we could replace the JOIN with an EXISTS (correlated subquery)
For example:
SELECT c.*
FROM tbl_car_class_category c
WHERE EXISTS
( SELECT 1
FROM tbl_vehicles v
WHERE v.veh_class_id = c.id_class_cat
AND v.veh_advanceLng
BETWEEN (:loc_long-:radius/cos(radians(:loc_lat))*69)
AND (:loc_long+:radius/cos(radians(:loc_lat))*69)
AND v.veh_advanceLat
BETWEEN (:loc_lat-(:radius/69))
AND (:loc_lat+(:radius/69))
AND v.veh_status=:veh_status
)
If we also need to return a row from the vehicle table, we can use aggregation in an inline view, and a JOIN .
SELECT c.*
, g.*
FROM tbl_car_class_category c
JOIN ( SELECT v.veh_class_id
, MIN(v.id) AS min_id -- PK or unique identifier
FROM tbl_vehicles v
AND v.veh_advanceLng
BETWEEN (:loc_long-:radius/cos(radians(:loc_lat))*69)
AND (:loc_long+:radius/cos(radians(:loc_lat))*69)
AND v.veh_advanceLat
BETWEEN (:loc_lat-(:radius/69))
AND (:loc_lat+(:radius/69))
AND v.veh_status=:veh_status
GROUP BY v.veh_class_id
) m
ON m.veh_class_id = c.id_class_cat
JOIN tbl_vehicles g
ON g.id = m.min_id
AND g.veh_class_id = m.veh_class_id
ORDER BY ...
(NOTE: this assumes that id_class_cat is UNIQUE in tbl_car_class_category)
Have you tried LIMIT?
$get_veh = $pdo->prepare("SELECT * FROM tbl_car_class_category JOIN tbl_vehicles ON tbl_vehicles.veh_class_id = tbl_car_class_category.id_class_cat WHERE tbl_vehicles.veh_advanceLng between (:loc_long-:radius/cos(radians(:loc_lat))*69) and (:loc_long+:radius/cos(radians(:loc_lat))*69) and veh_advanceLat between (:loc_lat-(:radius/69)) and (:loc_lat+(:radius/69)) AND veh_status=:veh_status LIMIT 1");
http://www.mysqltutorial.org/mysql-limit.aspx
Or DISTINCT: https://dev.mysql.com/doc/refman/5.7/en/distinct-optimization.html
for get a single row for each class you can use a (fake eg: min) aggregation functio and group by
( do the absence of the table schema assuming that you have col1, col2, col3 instead of * )
$get_veh = $pdo->prepare("SELECT
tbl_car_class_category.id_class_cat
, min(col1)
, min(col2)
, min(col3)
FROM tbl_car_class_category
JOIN tbl_vehicles ON tbl_vehicles.veh_class_id = tbl_car_class_category.id_class_cat
WHERE tbl_vehicles.veh_advanceLng between (:loc_long-:radius/cos(radians(:loc_lat))*69)
and (:loc_long+:radius/cos(radians(:loc_lat))*69)
and veh_advanceLat between (:loc_lat-(:radius/69))
and (:loc_lat+(:radius/69)) AND veh_status=:veh_status
GROUP BY tbl_car_class_category.id_class_cat");
I am trying to get all child ids by parent id from a single table.
Below is my table course:
Here is my code:
public function getLeftMenuMainCategoryInfoFromDb()
{
$sqlQuery = "SELECT p.course_id AS parent_id ,p.course_name As parent_coursename ,c.course_id AS child_id ,c.course_name As child_coursename FROM course As p LEFT JOIN course As c ON c.course_parent_id = p.course_id WHERE p.course_parent_id = 0 ORDER BY p.course_id";
$result = $this->selectQuery($sqlQuery);
//print_r($result);
return $result;
}
I think are you looking for Parent ID should be GROUP BY
SELECT p.*,
q.course_name
FROM course p
INNER JOIN
(SELECT course_id,
course_name
FROM course
WHERE course_parent_id = 0
ORDER BY course_id) q ON p.course_parent_id = q.course_id
GROUP BY p.course_parent_id;
Try this Query SELECT GROUP_CONCAT(course_id),course_parent_id FROM courseGROUP BY course_parent_id
SELECT GROUP_CONCAT(course_id),course_parent_id FROM course WHERE course_parent_id =1 GROUP BY course_parent_id
IF this is not you want please elaborate your question.
Is it possible to do something like this:
SELECT *,
COUNT(* WHERE media_id = 1) as count_1,
COUNT(* WHERE media_id = 2) as count_2
WHERE user_id = 1
or do I have to make separate queries?
Thanks.
You can use conditional sum something as
select
sum(media_id = 1) as count_1,
sum(media_id = 2) as count_2
from table_name
where user_id = 1;
Note that using aggregate function does not make sense with select *
Yup, it's possible.
Try this for example:
select
(select count(*) from TableA where 1=1) as totalA,
(select count(*) from TableB where 1=1) as totalB,
(select count(*) from TableC where 1=1) as totalc
I am having trouble with this query and am hoping someone can help.
SELECT
myTable.id,
myTable.subject,
myTable.upvotes,
myTable.downvotes,
(SELECT COUNT(id)
FROM myTable
WHERE myTable.thread = myTable.id) AS comments_count
FROM myTable
Basically I have a table with posts and comments, the comments thread is tied to the id of the original post. In my query I want to show how many relpies (how many threads = id) from all rows for the current id/row.
I hope that makes sense :)
You need to specify the the table with new alias to match in your subquery other wise it will match the thread with id from same table
SELECT
m.id,
m.subject,
m.upvotes,
m.downvotes,
(SELECT COUNT(id)
FROM myTable
WHERE myTable.thread = m.id) AS comments_count
FROM myTable m
Or Better to use LEFT JOIN
SELECT
m.id,
m.subject,
m.upvotes,
m.downvotes,
COUNT(mm.id) AS comments_count
FROM myTable m
LEFT JOIN myTable mm ON(mm.thread = m.id)
GROUP BY m.id
I currently have this left join as part of a query:
LEFT JOIN movies t3 ON t1.movie_id = t3.movie_id AND t3.popularity = 0
The trouble is that if there are several movies with the same name and same popularity (don't ask, it just is that way :-) ) then duplicate results are returned.
All that to say, I would like to limit the result of the left join to one.
I tried this:
LEFT JOIN
(SELECT t3.movie_name FROM movies t3 WHERE t3.popularity = 0 LIMIT 1)
ON t1.movie_id = t3.movie_id AND t3.popularity = 0
The second query dies with the error:
Every derived table must have its own alias
I know what I'm asking is slightly vague since I'm not providing the full query, but is what I'm asking generally possible?
The error is clear -- you just need to create an alias for the subquery following its closing ) and use it in your ON clause since every table, derived or real, must have its own identifier. Then, you'll need to include movie_id in the subquery's select list to be able to join on it. Since the subquery already includes WHERE popularity = 0, you don't need to include it in the join's ON clause.
LEFT JOIN (
SELECT
movie_id,
movie_name
FROM movies
WHERE popularity = 0
ORDER BY movie_name
LIMIT 1
) the_alias ON t1.movie_id = the_alias.movie_id
If you are using one of these columns in the outer SELECT, reference it via the_alias.movie_name for example.
Update after understanding the requirement better:
To get one per group to join against, you can use an aggregate MAX() or MIN() on the movie_id and group it in the subquery. No subquery LIMIT is then necessary -- you'll receive the first movie_id per name withMIN() or the last with MAX().
LEFT JOIN (
SELECT
movie_name,
MIN(movie_id) AS movie_id
FROM movies
WHERE popularity = 0
GROUP BY movie_name
) the_alias ON t1.movie_id = the_alias.movie_id
LEFT JOIN movies as m ON m.id = (
SELECT id FROM movies mm WHERE mm.movie_id = t1.movie_id
ORDER BY mm.id DESC
LIMIT 1
)
you could try to add GROUP BY t3.movie_id to the first query
Try this:
LEFT JOIN
(
SELECT t3.movie_name, t3.popularity
FROM movies t3 WHERE t3.popularity = 0 LIMIT 1
) XX
ON t1.movie_id = XX.movie_id AND XX.popularity = 0
On MySQL 5.7+ use ANY_VALUE & GROUP_BY:
SELECT t1.id,t1.movie_name, ANY_VALUE(t3.popularity) popularity
FROM t1
LEFT JOIN t3 ON (t3.movie_id=t1.movie_id AND t3.popularity=0)
GROUP BY t1.id
more info
LEFT JOIN only first row
https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
Easy solution to left join the 1 most/least recent row is using select over ON phrase
SELECT A.ID, A.Name, B.Content
FROM A
LEFT JOIN B
ON A.id = (SELECT MAX(id) FROM B WHERE id = A.id)
Where A.id is the auto-incremental primary key.
LEFT JOIN (
SELECT id,movie_name FROM movies GROUP BY id
) as m ON (
m.id = x.id
)
// Mysql
SELECT SUM(db.item_sales_nsv) as total FROM app_product_hqsales_otc as db
LEFT JOIN app_item_target_otc as it ON
db.id = (SELECT MAX(id) FROM app_item_target_otc as ot WHERE id = db.id)
and db.head_quarter = it.hqcode
AND db.aaina_item_code = it.aaina_item_code AND db.month = it.month
AND db.year = it.year
WHERE db.head_quarter = 'WIN001' AND db.month = '5' AND db.year = '2022' AND db.status = '1'