Codeigniter subqueries - mysql

Was looking for some help and found some but nothing for when the FROM also is a subquery.
SELECT COUNT(*)
FROM
( SELECT tc.*,
( SELECT status FROM test_case_executions tce
WHERE tce.test_case_id = tc.id
ORDER BY tce.execution_date DESC, tce.id DESC LIMIT 1
) AS last_status FROM test_cases tc
) a
WHERE a.last_status = '$status'
Is there a way in CI to just use this and execute it or can someone help me write this in the way CI wants it? Thanks

Everything you need can really be found here, as mentioned in above comments. Just to get you started, here's how you could do it:
$this->db->query("
SELECT COUNT(*) AS amount
FROM ( SELECT tc.*,
( SELECT status
FROM test_case_executions AS tce
WHERE tce.test_case_id = tc.id
ORDER BY tce.execution_date DESC, tce.id DESC
LIMIT 1) AS last_status
FROM test_cases AS tc
) AS a
WHERE a.last_status = ?
", array($status));
Basicly this is what the comments are saying. What makes this more "CI convenient" than simple mysql_query etc. is that you're escaping passed values to free yourself from errors and sql injections. Note the last part ? and the second parameter array($status). I also styled this query to be a bit easier on the eye (imo).
You might think "But I wanna use Active Records! D:", however more advanced stuff requires you to leave the comfort zone. Good luck!

Related

SQL query needs optimization

SELECT LM.user_id,LM.users_lineup_id, min( LM.total_score ) AS total_score
FROM vi_lineup_master LM JOIN
vi_contest AS C
ON C.contest_unique_id = LM.contest_unique_id join
(SELECT min( total_score ) as total_score
FROM vi_lineup_master
GROUP BY group_unique_id
) as preq
ON LM.total_score = preq.total_score
WHERE LM.contest_unique_id = 'iledhSBDO' AND
C.league_contest_type = 1
GROUP BY group_unique_id
Above query is to find the loser per group of game, query return accurate result but its not responding with large data. How can I optimize this?
You can try to move your JOINs to subqueries. Also, you should pay attention on your "wrong" GROUP BY usage on the outer query. In Mysql you can group by some columns and select others not specified in the group clause without any aggregation function, but the database can't ensure what data it will return to you. For the sake of consistency of your application, wrap them in an aggregation function.
Check if this one helps:
SELECT
MIN(LM.user_id) AS user_id,
MIN(LM.users_lineup_id) AS users_lineup_id,
MIN(LM.total_score) AS total_score
FROM vi_lineup_master LM
WHERE 1=1
-- check if this "contest_unique_id" is equals
-- to 'iledhSBDO' for a "league_contest_type" valued 1
AND LM.contest_unique_id IN
(
SELECT C.contest_unique_id
FROM vi_contest AS C
WHERE 1=1
AND C.contest_unique_id = 'iledhSBDO'
AND C.league_contest_type = 1
)
-- check if this "total_score" is one of the
-- "min(total_score)" from each "group_unique_id"
AND LM.total_score IN
(
SELECT MIN(total_score)
FROM vi_lineup_master
GROUP BY group_unique_id
)
GROUP BY LM.group_unique_id
;
Also, some pieces of this query may seem redundant, but it's because I did not want to change the filters you wrote, just moved them.
Also, your query logic seems a bit strange to me, based on the tables/columns names and how you wrote it... please, check the comments in my query which reflects what I understood of your implementation.
Hope it helps.

Can I Select Distinct inside a where and get all selects in mysql?

I have this:
SELECT FirstName
FROM MAIN_TABLE_LEVEL100
WHERE FirstName IN
(
SELECT DISTINCT FirstName
FROM MAIN_TABLE_LEVEL100
)
ORDER BY `level` DESC, `time` DESC LIMIT 0,10
Im trying to get top 10 diferents names order by level and time, but it doesn't work, if someone can help me please, thanks.
Your where clause is doing nothing, you just repeated the same select that you had above. As long as level and time are in 'MAIN_TABLE_LEVEL100' you don't even need a where clause. This should work:
SELECT DISTINCT FirstName, level, time
FROM MAIN_TABLE_LEVEL100
ORDER BY level DESC, time DESC LIMIT 10
Why don't use GROUP BY .DISTINCT work only with indexed field in some situation.
You can have multiple lines because of time. Try rolling the data together first.
I'm not familiar with mySql, but using generic SQL syntax it would be something like this:
SELECT b.FirstName
FROM (SELECT a.FirstName, a.Level, MAX(a.Time) AS tm FROM MAIN_TABLE_LEVEL100 as a GROUP BY a.FirstName, a.Level) AS b
ORDER By b.Level, b.tm
Thanks everyone, I finally found the right answer!:
SELECT o.FirstName, o.Level, o.Time, o.City
FROM `MAIN_TABLE_LEVEL100` o # 'o' from 'bigger points'
LEFT JOIN `MAIN_TABLE_LEVEL100` b # 'b' from 'bigger after o'
ON o.FirstName = b.FirstName AND o.Points < b.Points
WHERE b.Points is NULL
ORDER BY `o`.`Points` DESC
LIMIT 0,10
thanks everyone, i hope someone need it ;)

Alternative to mysql WHERE IN SELECT GROUP BY when wanting max value in group by

I have the following query, which was developed from a hint found online because of a problem with a GROUP BY returning the maximum value; but it's running really slowly.
Having looked online I'm seeing that WHERE IN (SELECT.... GROUP BY) is probably the issue, but, to be honest, I'm struggling to find a way around this:
SELECT *
FROM tbl_berths a
JOIN tbl_active_trains b on a.train_uid=b.train_uid
WHERE (a.train_id, a.TimeStamp) in (
SELECT a.train_id, max(a.TimeStamp)
FROM a
GROUP BY a.train_id
)
I'm thinking I possibly need a derived table, but my experience in this area is zero and it's just not working out!
you can move that to a SUBQUERY and also select only required columns instead of All (*)
SELECT a.train_uid
FROM tbl_berths a
JOIN tbl_active_trains b on a.train_uid=b.train_uid
JOIN (SELECT a.train_id, max(a.TimeStamp) as TimeStamp
FROM a
GROUP BY a.train_id )T
on a.train_id = T.train_id
and a.TimeStamp = T.TimeStamp

MySQL sort grouped data

I have tried to program a inbox that display messages in the order they were received and then by if they have been read or not, it seemed to work for a while, but not it doesn't. It may have only worked under certain circumstances maybe..
Anyway here is my query;
SELECT `id`, `from_userid`, `read`, max(sent) AS sent
FROM (`who_messages`)
WHERE `to_userid` = '41'
GROUP BY `from_userid`
ORDER BY `read` ASC, `sent` DESC
I believe the problem is that the messages are being grouped in the wrong order.. as the inbox is always showing as read, when new messages exist. I get the right time of the new messages, but I am guessing this because I selected max(sent).
Is my logic wrong? or can I sort and then group as all my efforts have resulted in 'Every derived table must have its own alias'
Setup an SQL Fiddle - here's the best I came up with. Basically I do the ordering first in a sub-query then group them afterwards. That seemed to work with the (limited) test data I entered.
SELECT *
FROM (SELECT id, from_userid, is_read, sent
FROM who_messages
WHERE to_userid = 41
ORDER BY from_userid ASC, is_read ASC) m
GROUP BY m.from_userid
ORDER BY m.is_read ASC, m.sent DESC
See the fiddle to play around: http://sqlfiddle.com/#!2/4f63d/8
You are selecting non-grouping fields in a grouped query. It is not guaranteed which record of the group will be returned, and ORDER BY is processed after GROUP BY.
Try this:
SELECT m.*
FROM (
SELECT DISTINCT from_userid
FROM who_messages
WHERE to_userid = 41
) md
JOIN who_messages m
ON m.id =
(
SELECT mi.id
FROM who_message mi
WHERE (mi.to_userid, mi.from_userid) = (41, md.from_userid)
ORDER BY
mi.sent DESC, mi.id DESC
LIMIT 1
)
Create an index on who_message (to_userid, from_userid, sent, id) for this to work fast.
Update
The above query will return the record for the last message from any given user (including its read status). If you want to check that you have any unread messages from the user, use this:
SELECT m.*, md.all_read
FROM (
SELECT from_userid, MIN(read) AS all_read
FROM who_messages
WHERE to_userid = 41
GROUP BY
from_userid
) md
JOIN who_messages m
ON m.id =
(
SELECT mi.id
FROM who_message mi
WHERE (mi.to_userid, mi.from_userid) = (41, md.from_userid)
ORDER BY
mi.sent DESC, mi.id DESC
LIMIT 1
)
For this to work fast, create an index on who_message (to_userid, from_userid, read) (in addition to the previous index).
As Quassnoi said, you are using a GROUP BY query and ordering on 'read' which is not an aggregate function. Therefore you can't be certain of the value used by the MySQL engine (usually the last of the group but...)
I would suggest writing your query this way, as it doesn't involve any subquery and has some many other performance-friendly usage:
SELECT
from_userid,
COUNT(*) AS nb_messages,
SUM(NOT is_read) AS nb_unread_messages,
MAX(sent) AS last_sent
FROM who_messages
WHERE to_userid = 41
GROUP BY from_userid
ORDER BY nb_unread_messages DESC, last_sent DESC;
(I used Andy Jones' fiddle schema: http://sqlfiddle.com/#!2/4f63d/8.
By the way, many thanks Andy, this site is great !)
Hope this help !
"inbox that display messages in the order they were received and then by if they have been read or not ... however it is suppose to be the latest message" - assumes read is a nullable date/time column, and messages are stored in the order they are sent (newer have larger id than older - autoid)
SELECT wm.id, wm.from_userid, (wm.read IS NULL) as unread, wm.sent
FROM (SELECT MAX(id) AS id FROM who_messages WHERE to_userid = '41' GROUP BY from_userid) sub
INNER JOIN who_messages wm ON sub.id = wm.id
ORDER BY wm.sent DESC, wm.read

Query with sub select on join hangs

I have the following query that when executed, it just runs for hours and eventually the server times out.
SELECT l.mloc_id, COUNT( l.tabc_id ) , l.tabc_id, e.establishment_id, e.name, l.LocationName, l.naics, l.cuisine, l.cuisine2, l.service, l.www, l.owner, l.email, l.status
FROM vg_ydrink2.m_loc AS l
JOIN vg_ydk.permit_beverage AS pb ON ( l.tabc_id = pb.permit_code
AND pb.create_date = ( 
SELECT MAX( create_date ) 
FROM vg_ydk.permit_beverage
WHERE permit_code = l.tabc_id ) ) 
JOIN vg_ydk.establishment AS e ON ( pb.establishment_id = e.establishment_id ) 
GROUP BY l.mloc_id
ORDER BY  `l`.`tabc_id` ASC 
LIMIT 1 , 30
No errors are reported. It simply never gets completed.
The problem lies in the sub-select, because when removing it, the query executes without a problem. I also don't think it's the group function causing the issue, because I have tried keeping the subquery but removing the MAX and that did not work either.
Any thoughts?
Thank you in advance.
***EDIT: After having played with the create_date index a bit, I realized that due to the nature of its values, its cardinality is constantly very low. For that reason, it is not treated as an index by the query and as a result, too many rows are constantly loaded.
I have since changed the query altogether, so this is not an issue anymore. If anybody comes across a similar issue, make sure the used field is indexed properly. Analyze/optimize/repair your table if need be.
M.
Try this variation:
select l.mloc_id,
COUNT(l.tabc_id),
l.tabc_id,
e.establishment_id,
e.name,
l.LocationName,
l.naics,
l.cuisine,
l.cuisine2,
l.service,
l.www,
l.owner,
l.email,
l.status
from vg_ydrink2.m_loc as l
inner join (
select permit_code,
max(create_date) as MaxCreateDate
from vg_ydk.permit_beverage
group by permit_code
) pbm on l.tabc_id = pbm.permit_code
inner join vg_ydk.permit_beverage as pb on pbm.permit_code = pb.permit_code
and pbm.MaxCreateDate = pb.create_date
inner join vg_ydk.establishment as e on pb.establishment_id = e.establishment_id
group by l.mloc_id
order by `l`.`tabc_id` asc
LIMIT 1,
30