multiple subquery need to change as join query - php

Hi all I need a solution for this question here is my query look like it works.But takes too much time because of sub queries.Give an alternate query to this query
SELECT *
FROM `room_types`
WHERE id
IN (SELECT capacity
FROM rooms
WHERE id
IN (
SELECT DISTINCT room_id
FROM `reservations`
WHERE DATE(
START ) >= '2016-01-10'
AND DATE(
END ) <= '2016-01-15'
AND STATUS = 'CheckedOut'
AND id
IN (
SELECT op_no
FROM `bills`
WHERE billed = 'Yes'
)
)
)

As of your provided query, Try this:
SELECT
`room_types`.*
FROM
`room_types`
INNER JOIN `rooms` ON (`room_types`.`id` = `rooms`.`id`)
INNER JOIN `reservations` ON (`rooms`.`id` = `reservations`.`room_id`)
INNER JOIN `bills` ON (`reservations`.`id` = `bills`.`op_no`)
WHERE
DATE(`reservations`.`START`) BETWEEN '2016-01-10' AND '2016-01-15'
AND `reservations`.`STATUS` = 'CheckedOut'
AND `bills`.`billed` = 'Yes'
Also you can index columns which will make it more faster.

So.. First try without Database Schema !
SELECT *
FROM room_types rt
JOIN rooms r ON r.capacity = rt.id
JOIN reservations resa ON r.id = resa.room_id
AND DATE(resa.start ) >= '2016-01-10'
AND DATE(resa.end ) <= '2016-01-15'
AND resa.status LIKE "CheckedOut"
JOIN bills b ON resa.id = b.resa_id AND b.billed LIKE "Yes"
Notice that "rt", "r", "resa" and "b" are aliases for your tables

Related

How get records by last date with specific query

I have table currencies and table this courses data . How i can get one course data for each currency by last date
This is my code where i get courses for each currency by date:
SELECT
`coll_currency`.`collectionAlias`,
`coll_currency`.`currency_abbr`,
`coll_currency`.`currency_image`,
`coll_currency`.`currency_name`,
`coll_currency`.`currency_amount`,
`coll_currency`.`id`,
`pars_table`.`course` AS `currency_course`,
`pars_table`.`publishdate` AS `currency_publishdate`,
`pars_table`.`currency_id`
FROM
`coll_currency`
INNER JOIN `pars_currency_nbu` AS `pars_table`
ON coll_currency.id = pars_table.currency_id
WHERE
(
(`currency_type` = '3670924')
AND (`currency_state` = '3583429')
AND (
DATE_FORMAT(
`pars_table`.`publishdate`,
'%Y-%m-%d'
) = '2017-08-09'
)
)
ORDER BY
`currency_publishdate` DESC
Try something like this:
SELECT `c`.`collectionAlias`,
`c`.`currency_abbr`,
`c`.`currency_image`,
`c`.`currency_name`,
`c`.`currency_amount`,
`c`.`id`,
`p`.`course` AS `currency_course`,
`p`.`publishdate` AS `currency_publishdate`,
`p`.`currency_id` -- this has the same value as `c`.`id`
FROM `coll_currency` AS `c`
JOIN `pars_currency_nbu` AS `p` ON `c`.`id` = `p`.`currency_id`
JOIN ( SELECT `cc`.`id`, MAX(`pp`.`publishdate`) AS `maxdate`
FROM `coll_currency` AS `cc`
JOIN `pars_currency_nbu` AS `pp` ON `cc`.`id` = `pp`.`currency_id`
GROUP BY `cc`.`id`
) AS `q` ON `q`.id` = `c`.`id` AND `q`.`maxdate` = `p`.`publishdate`

correct query for join two querys

I have this query for select a list
$sql="select * from buy_log where (client_id not in
(select selected_client_id from action_log where media_id=buy_log.media_id and client_id=$client_id )
and totalVisit>0 and coin_id=3 or coin_id=4 or coin_id=5)";
and this is my second select
while($row=mysqli_fetch_assoc($result)){
$media_id = $row['media_id'];
$sql2 = "select * from comment_media,comment_list where comment_list.id=comment_media.id and media_id='$media_id' order by rand() limit 2";
}
i try to use join for one query and this is my try :
SELECT S.*,WW.Comments,WW.Comments_id
FROM buy_log S
INNER JOIN
(
SELECT M.media_id,GROUP_CONCAT(W.Comment SEPARATOR '!###!') as Comments,GROUP_CONCAT(W.id SEPARATOR ',') as Comments_id
FROM comment_list W,comment_media as M
Where W.id=M.id and M.media_id='$media_id' and W.used = 0
) WW
ON S.media_id = WW.media_id
where (client_id not in
(select selected_client_id from action_log where media_id=S.media_id and client_id='1234' )
and totalVisit>0 and coin_id=3 or coin_id=4 or coin_id=5)
but here is my problem
Where W.id=M.id and M.media_id='$media_id' and W.used = 0
I don't know how can i set $media_id
any solution ?
UPDATE
Tables Info :
Tables Info : Pic
This should work:
You're extracting media id from that original query, looping through results and using the media id to assign the value $media_id in the php loop, where you perform another query.
The join seems syntactically right just need to reference the buy_log table inside the subquery.
SELECT S.*,WW.Comments,WW.Comments_id
FROM buy_log S
INNER JOIN
(
SELECT M.media_id,GROUP_CONCAT(W.Comment SEPARATOR '!###!') as Comments,GROUP_CONCAT(W.id SEPARATOR ',') as Comments_id
FROM comment_list W,comment_media as M
Where W.id=M.id and M.media_id= S.media_id and W.used = 0
) WW
ON S.media_id = WW.media_id
where (client_id not in
(select selected_client_id from action_log where media_id=S.media_id and client_id='1234' )
and totalVisit>0 and coin_id=3 or coin_id=4 or coin_id=5)
I guess that first query can be rewritten as follows... does it help?
SELECT b.media_id
FROM buy_log b
LEFT
JOIN action_log a
ON a.selected_client_id = b.client_id
AND a.media_id = b.media_id
AND a.client_id = $client_id
WHERE b.totalVisit > 0
AND b.coin_id IN(3,4,5)
AND a.selected_client_id IS NULL;

Sub query return more than one field

I have a table structure like this
Table Structure
Here I want to select all the data from bus_routines table with bus details and avaliable_seat which is calculated from buses.number_of_seat - reserved_seats.number_of_reserved_seat - booking.number_of_seat even if the data is not present in booking table and reserved_seats table too where the bus_routines.sector_from=Ktm ,bus_routines.sector_to=Pkr and bus_routines.date=2015-12-15
Relation between them are :
buses and bus_routines --> one to many bus_routines and booking -->
one to many bus_routines and reserved_seats --> one to many
I have tried the following query
SELECT r.* , b.* ,
(
SELECT b.number_of_seat - sum(booking.number_of_seat)-sum(reserved_seats.number_of_reserved_seat)
FROM bus_routines AS r
INNER JOIN buses AS b
ON b.id = r.bus_id
INNER JOIN
(SELECT number_of_seat , bus_routine_id FROM booking GROUP BY booking.bus_routine_id) AS booking
ON booking.bus_routine_id = r.id
INNER JOIN (SELECT number_of_reserved_seat , routine_id FROM reserved_seats GROUP BY reserved_seats.routine_id) AS reserved_seats
ON r.id = reserved_seats.routine_id
WHERE
r.sector_from = "KTM" AND
r.sector_to = "PKR" AND
r.departure_date = "2015-12-15"
) AS avaliable_seat
FROM bus_routines AS r
INNER JOIN buses AS b
ON b.id = r.bus_id
WHERE
r.sector_from = "KTM" AND
r.sector_to = "PKR" AND
r.departure_date = "2015-12-15"
HAVING avaliable_seat > 0
I get the result what I want but the avaliable_seat is same for all the row
I have tried another query too but it give me the single result
SELECT r.* , b.* , b.number_of_seat - sum(booking.number_of_seat)-sum(reserved_seats.number_of_reserved_seat) AS available_seat
FROM bus_routines AS r
INNER JOIN buses AS b
ON b.id = r.bus_id
INNER JOIN
(SELECT number_of_seat , bus_routine_id FROM booking GROUP BY booking.bus_routine_id) AS booking
ON booking.bus_routine_id = r.id
INNER JOIN
(SELECT number_of_reserved_seat , routine_id FROM reserved_seats GROUP BY reserved_seats.routine_id) AS reserved_seats
ON r.id = reserved_seats.routine_id
WHERE
r.sector_from = "KTM" AND
r.sector_to = "PKR" AND
r.departure_date = "2015-12-15"
HAVING available_seat > 0
I also tried another query and it give me Subquery returns more than 1 row . The query is
SELECT r.* , b.* ,
b.number_of_seat - (SELECT sum(number_of_seat) FROM booking GROUP BY booking.bus_routine_id)
- (SELECT sum(number_of_reserved_seat) FROM reserved_seats GROUP BY reserved_seats.routine_id) AS available_seat
FROM bus_routines AS r
INNER JOIN buses AS b
ON b.id = r.bus_id
WHERE
r.sector_from = "KTM" AND
r.sector_to = "PKR" AND
r.departure_date = "2015-12-15"
HAVING available_seat > 0
One approach is to use correlated subqueries to get the reserved_seats and booked_seats for each bus_routine.
Let's assume that this query returns the rows you are wanting to return, it's just missing the available_seat column you want calculated:
SELECT r.*
, b.*
FROM bus_routines r
JOIN buses b
ON b.id = r.bus_id
WHERE r.sector_from = 'KTM'
AND r.sector_to = 'PKR'
AND r.departure_date = '2015-12-15'
To number of "reserved seats" for a given bus_routine, you can query the reserved_seats table, like this:
SELECT IFNULL(SUM(s.number_of_reserved_seat),0)
FROM reserved_seats s
WHERE s.routine_id = '649'
And the number of "booked seats" for a given bus_routine can be returned from the booking table, like this:
SELECT IFNULL(SUM(k.number_of_seat),0)
FROM booking k
WHERE k.bus_routine_id = '649'
We can incorporate the queries to get "reserved seats" and "booked seats" into the first query, as correlated subqueries. In place of the literal '649', with a reference the id from the bus_routine table.
SELECT r.*
, b.*
-- number of booked seats
, ( SELECT IFNULL(SUM(k.number_of_seat),0)
FROM booking k
WHERE k.bus_routine_id = r.id
) AS booked_seats
-- number of reserved seats
, ( SELECT IFNULL(SUM(s.number_of_reserved_seat),0)
FROM reserved_seats s
WHERE s.routine_id = r.id
) AS reserved_seats
-- calculate available seats as
-- (bus number_of_seat) - (booked_seats) - (reserved_seats)
, ( b.number_of_seat
- ( SELECT IFNULL(SUM(k.number_of_seat),0)
FROM booking k
WHERE k.bus_routine_id = r.id
)
- ( SELECT IFNULL(SUM(s.number_of_reserved_seat),0)
FROM reserved_seats s
WHERE s.routine_id = r.id
)
) AS avaliable_seat
FROM bus_routines r
JOIN buses b
ON b.id = r.bus_id
WHERE r.sector_from = 'KTM'
AND r.sector_to = 'PKR'
AND r.departure_date = '2015-12-15'
If there's no requirement to return the booked_seats and reserved_seats columns, those can be omitted from the query. The subqueries to get those values can just appear in the calculation of the available_seat column.
SQL Fiddle demonstration here: http://sqlfiddle.com/#!9/64eaa/7
Please try GROUP_CONCAT for return one column from multiple in subquery.
refer the links.
How to use GROUP_CONCAT in a CONCAT in MySQL
http://www.w3resource.com/mysql/aggregate-functions-and-grouping/aggregate-functions-and-grouping-group_concat.php

Speeding up SQL loop

I have a nested loop in my PHP code that is taking a long time and wondered of there was a way to speed this up:
$sql = "SELECT * FROM table_1";
$result = mysqli_query($sql);
while($row = mysqli_fetch_array($result)){
$sql2 = "
SELECT count(*)
FROM user_modules
WHERE
begin_ymdhi >= ".$date_from." AND
begin_ymdhi <= ".$date_to." AND
(
completed_ymdhi IS NULL OR
completed_ymdhi = ''
) AND
user_id = ".$row['user_id']." AND
task_id = ".$row['task_id']." AND
module_discon = 'N'
";
}
The outer query gets 1000 rows, the inner has to count across 10,000 rows - the run-time is around 115 seconds ! Is there any way to improve this method, either using a different technique or combined SQL query?
Don't use nested queries, combine them into a single query with a join:
SELECT t1.*, COUNT(u.user_id) ct
FROM table_1 t1
LEFT JOIN user_modules AS u ON u.user_id = t1.user_id AND u.task_id = t1.task_id
AND u.begin_ymdhi BETWEEN '$date_from' AND '$date_to'
AND u.module_discon = 'N'
GROUP BY t1.user_id, t1.task_id
Are the task_id's unique? if so, the most straight forward would be something like:
$sql2 = "
SELECT count(task_id) AS TaskCount
FROM user_modules
WHERE
begin_ymdhi >= ".$date_from." AND
begin_ymdhi <= ".$date_to." AND
(
completed_ymdhi IS NULL OR
completed_ymdhi = ''
) AND module_discon = 'N'
group by user_id
";
$result = mysqli_query($sql2);
SELECT user_modules.user_id, user_modules.task_id, count(*)
FROM user_modules LEFT JOIN table_1 USING (user_id, task_id)
WHERE
begin_ymdhi >= ".$date_from." AND
begin_ymdhi <= ".$date_to." AND
module_discon = 'N' AND
(
completed_ymdhi IS NULL OR
completed_ymdhi = ''
)
GROUP BY user_modules.user_id, user_modules.task_id
Append EXPLAIN before that entire SELECT statement (i.e EXPLAIN SELECT count(*)...) and MySQL will give you a run-down on what the select is doing.
Make sure the begin_ymdhi field is indexed properly. SHOW INDEX FROM table_2 to see.

How Can i Convert this multiple sub query in zend query?

i have the following query which gives desired output in mysql , now i want to implement it in zend query language,
which has different approach to implement the query..
SELECT A.NAME , B.PAYMENT , C.TOTALPROJ , D.TOTALTASK , T.ACTIVETASK , H.HOUR
FROM USERMASTER AS A
LEFT OUTER JOIN
(
SELECT A.U_ID , SUM(A.TOTALTIME * B.RATE) AS PAYMENT
FROM
(
SELECT U_ID , PROJECT_ID ,
SUM(TIME_TO_SEC(CASE WHEN endtime is null then timediff (starttime,starttime)
ELSE timediff (endtime,starttime) END )) / 3600 AS TOTALTIME
FROM LOGMASTER AS A
WHERE PROJECT_ID IS NOT NULL
GROUP BY U_ID , PROJECT_ID
) AS A
INNER JOIN PROJECTTOUSER AS B ON A.PROJECT_ID = B.PROJECT_ID AND A.U_ID = B.U_ID
GROUP BY B.U_ID
) AS B ON A.ID = B.U_ID
LEFT OUTER JOIN
(
SELECT U_ID , COUNT(*) AS TOTALPROJ FROM PROJECTTOUSER GROUP BY U_ID
) AS C ON A.ID = C.U_ID
LEFT OUTER JOIN
(
SELECT ASSIGNED_TO , COUNT(*) AS TOTALTASK FROM TASKTOTARGET GROUP BY ASSIGNED_TO
) AS D ON A.ID = D.ASSIGNED_TO
LEFT OUTER JOIN
(
SELECT ASSIGNED_TO,COUNT(*) AS ACTIVETASK FROM TASKTOTARGET WHERE
IS_ACTIVE = 0 GROUP BY ASSIGNED_TO
) AS T ON A.ID = T.ASSIGNED_TO
LEFT OUTER JOIN
(
SELECT U_ID, SEC_TO_TIME(SUM(TIME_TO_SEC(CASE WHEN endtime is null then
timediff (starttime,starttime) ELSE timediff (endtime,starttime) END ))) AS HOUR
FROM LOGMASTER WHERE INSERT_DATE >= '2013-08-20' AND INSERT_DATE <='2013-08-31'
GROUP BY U_ID
) AS H ON A.ID = H.U_ID
so if any one can guide me in how to create this query in zend then it will be very helpful, and appreciated
Each of your subqueries becomes an new Zend_Query that you can then use just like a table and pass in to the main query.
For example:
$h = new Zend_Db_Select()
->from('LOGMASTER', array('U_ID', 'HOUR' => new Zend_Db_Expr('SEC_TO_TIME(SUM(TIME_TO_SEC(CASE WHEN endtime is null then
timediff (starttime,starttime) ELSE timediff (endtime,starttime) END ))))')
->where("INSERT_DATE >= '2013-08-20'")
->where("INSERT_DATE <= '2013-08-31'")
->group('U_ID');
$mainQuery = new Zend_Db_Select()
->from('a' => 'USERMASTER', array('NAME'))
->joinLeft($h, 'A.ID = H.U_IS', array('HOUR'));
You would create each of your subqueries as its own object and then you can join them into your main query. The last argument of the join function is which columns from the subquery should be added to the main query.
With ZF's fluid interface you can keep joining tables/queries until you have built your entire query.
http://framework.zend.com/manual/1.12/en/zend.db.select.html

Categories