I apologize for the title description as I wasn't sure how to best describe this.
There are multiple computers, multiple users per computer, and multiple data logs per user. I want to get the latest data log per computer.
I realize now that the query below does not provide the correct data because the ORDER BY happens for the results and the GROUP BY does so in no particular order.
I did read up on this before posting this and it appears a sub query is needed and then the result of that joined again on the same table to get the rest of that rows column values (the one found to be the latest). The examples I have found though are pretty basic and do not involve other tables being joined. It also seems I have to do this twice since I want it grouped by computer... (once for data_logs grouped by user_id and get the max then another grouped by computer_id to get the max of the earlier result) or maybe I am wrong there.
Need some help grasping how to tackle this and the approach to do so.
$stmt = $db->prepare("
SELECT
computers.computer_name,
users.username,
data_logs.window_title,
data_logs.filename,
data_logs.capture_timestamp
FROM computers
INNER JOIN users
ON users.computer_id = computers.computer_id
INNER JOIN data_logs
ON data_logs.user_id = users.user_id AND data_logs.marked != 1
WHERE computers.account_id = :cw_account_id AND computers.status = 1
GROUP BY computers.computer_id
ORDER BY data_logs.capture_timestamp desc
");
$binding = array('cw_account_id' => 1721);
$stmt->execute($binding);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo "<pre>";
print_r($results);
echo "</pre>";
One solution is to use a correlated subquery. The principle is that the outer query is not aggregated, but it has a condition in the WHERE clause that selects the latest log entry for the current computer id, using an aggregated subquery.
I guess that you would need this query (without seeing sample data and expected output though, this might not be 100% accurate) :
SELECT
computers.computer_name,
users.username,
data_logs.window_title,
data_logs.filename,
data_logs.capture_timestamp
FROM computers
INNER JOIN users
ON users.computer_id = computers.computer_id
INNER JOIN data_logs
ON data_logs.user_id = users.user_id AND data_logs.marked != 1
WHERE
computers.account_id = :cw_account_id
AND computers.status = 1
AND data_logs.capture_timestamp = (
SELECT MAX(d.capture_timestamp)
FROM computers c
INNER JOIN users u ON u.computer_id = c.computer_id
INNER JOIN data_logs d ON d.user_id = u.user_id AND d.marked != 1
WHERE c.computer_id = computers.computer_id AND c.account_id = computers.account_id
)
ORDER BY data_logs.capture_timestamp desc
Related
I am trying to write a query. I got it work half way, but I am having problems with the LEFT JOIN.
I have three tables:
user
user_preferences
user_subscription_plan
User will always have one user_preference, but it can have many or no entries in the user_subscription_plan
If the user has no entry in the user_subscription_plan, or if he has only one then my sql works. If I have more then one, then I have issue. In the case of two entries, how can I make it to return the last one entered? I tried playing with ORDER statement, but it does not work as expected. Somehow I get empty rows.
Here is my query:
SELECT u.id AS GYM_USER_ID, subscription_plan.id AS subscriptionId, up.onboarding_completed AS CompletedOnboarding,
(CASE
WHEN ((up.onboarding_completed = 1)
AND (ISNULL(subscription_plan.id)))
THEN 'freemiun'
WHEN (ISNULL(up.onboarding_completed)
AND (ISNULL(subscription_plan.id)))
THEN 'not_paying'
END) AS subscription_status
FROM user AS u
INNER JOIN user_preferences up ON up.user_id = u.id
LEFT JOIN (
SELECT * FROM user_subscription_plan AS usp ORDER BY usp.id DESC LIMIT 1
) AS subscription_plan ON subscription_plan.user_id = u.id
GROUP BY u.id;
If I run it as it is, then subscription_plan.id AS subscriptionId is always empty.
If I remove the LIMIT clause, then its not empty, but I am still getting the first entry, which is wrong in my case
I have more CASE's to cover, but I can't process until I solve this problem.
Please try to use "max(usp.id)" that "group by subscription_plan.user_id" instead of limit 1.
If you limit 1 in the subquery, the subquery's result will always return only 1 record (if the table has data).
So the above query can be rewritten like this.
Sorry, I didn't test, because I don't have data, but please try, hope this can help.
SELECT
u.id AS GYM_USER_ID,
subscription_plan.id AS subscriptionId,
up.onboarding_completed AS CompletedOnboarding,
(CASE
WHEN
((up.onboarding_completed = 1)
AND (ISNULL(subscription_plan.id)))
THEN
'freemiun'
WHEN
(ISNULL(up.onboarding_completed)
AND (ISNULL(subscription_plan.id)))
THEN
'not_paying'
END) AS subscription_status
FROM
user AS u
INNER JOIN
user_preferences up ON up.user_id = u.id
LEFT JOIN
(SELECT
usp.user_id, MAX(usp.id)AS id
FROM
user_subscription_plan AS usp
GROUP BY usp.user_id) AS subscription_plan ON subscription_plan.user_id = u.id;
I have a question about a SQL, I have never worked with the select sub and I ended up getting lost with it.
Meu SQL:
SELECT CLI.id, CLI.nome, CLI.senha, CLI.email, CLI.cpf, CLI.celular, CLI.data_nasc, CLI.genero, CLI.data_cadastro, CLI.status, CLI.id_socket, ATEN.mensagem, ARQ.nome AS foto, ATEN.data_mensagem
FROM ut_clientes AS CLI
LEFT JOIN ut_arquivos AS ARQ ON (ARQ.id_tipo = CLI.id AND ARQ.tipo = "ut_clientes")
INNER JOIN ut_atendimentos AS ATEN ON (ATEN.id_usuario_envio = CLI.id)
WHERE ATEN.id_usuario_envio != 59163
GROUP BY CLI.id
ORDER BY ATEN.data_mensagem
DESC
Well, what I would like to do is group the messages according to the customer ID and bring only the last message recorded in the database according to the data_mensagem.
I have tried in many ways but always the last one that is displayed is the first message inserted in DB.
If anyone can help me, I'll be grateful. Thank you guys!
This may help you... I am using a join to a pre-query (PQ alias). This query just goes to your messages and grabs the client ID and the most recent based on the MAX(). By doing the group by here, it will at most return 1 record per client. I also have the WHERE clause to exclude the one ID you listed.
From THAT result, you do a simple join to the rest of your query.
SELECT
CLI.id,
CLI.nome,
CLI.senha,
CLI.email,
CLI.cpf,
CLI.celular,
CLI.data_nasc,
CLI.genero,
CLI.data_cadastro,
CLI.status,
CLI.id_socket,
ATEN.mensagem,
ARQ.nome AS foto,
PQ.data_mensagem
FROM
ut_clientes AS CLI
LEFT JOIN ut_arquivos AS ARQ
ON CLI.id = ARQ.id_tipo
AND ARQ.tipo = "ut_clientes"
INNER JOIN
( select
ATEN.id_usuario_envio,
MAX( ATEN.data_mensagem ) as MostRecentMsg
from
ut_atendimentos AS ATEN
where
ATEN.id_usuario_envio != 59163
group by
ATEN.id_usuario_envio ) PQ
ON CLI.id = PQ.id_usuario_envio
GROUP BY
CLI.id
ORDER BY
PQ.data_mensagem DESC
I have the following which returns all users...from all computers... of a specific user account. Works great, BUT I want to have a ORDER BY computers.computer_id ASC LIMIT 0, ? on the computers table.
I'm fairly new to joins, but have picked it up pretty quickly in the last day or so, but not sure about specific conditions on a table when joins are involved.
The idea is say there are 20 computers in the account... I limit that to only the first 10, for example, in asc order by its computer_id... which in turn would only left join the users for those 10 computers and then left join the account on that.
$stmt = $db->prepare("
SELECT users.*
FROM computers
LEFT JOIN users
on users.computer_id = computers.computer_id
LEFT JOIN accounts
on accounts.account_id = computers.account_id
WHERE accounts.account_id = ?
");
$stmt->execute(array($_SESSION['user']['account_id'], **limit value goes here**));
// return array
$array = $stmt->fetchAll(PDO::FETCH_ASSOC);
EDIT:
In response to Ollie's answer below... I guess I am doing something wrong here because while it does not produce any errors it also produces no result.
$stmt = $db->prepare("
SELECT users.*
FROM (
SELECT * FROM computers ORDER BY computer_id ASC LIMIT 0, ?
) as c
LEFT JOIN users
on users.computer_id = c.computer_id
LEFT JOIN accounts
on accounts.account_id = c.account_id
WHERE accounts.account_id = ?
");
$stmt->execute(array($_SESSION['user']['account_id'], $_SESSION['user']['licenses']));
// return array
$array = $stmt->fetchAll(PDO::FETCH_ASSOC);
Bind values are fine and there is data to be returned as confirmed by my original statement ... so it is something with the statement itself.
The problem :
I've narrowed this down to the LIMIT... if I manually enter LIMIT 0,
whatever in the statement it works. If I enter LIMIT 0, ? where I bind the value it returns null. Any ideas?
The knack you need is this:
Anywhere you can say table in SELECT ... FROM table AS t you can also say
SELECT ...
FROM (
/* some valid query */
) AS t
So you need
SELECT ...
FROM (
SELECT * FROM computers ORDER BY computer_id ASC LIMIT 0,?
) AS t
LEFT JOIN (whatever)
That is, you can either name a physical table, or a virtual table (the result set of a query) anywhere you name a table.
That's why Structured Query Language is called Structured.
when i write a MySQL query, there occur a problem. here is my query
SELECT
SUM(view_product_count_details.view_product_count) AS count_sum,
product_details.product_name,
product_details.product_url,
product_details.product_price,
product_image_details.product_image_name,
main_category_details.main_category_url,
sub_category_details.sub_category_url
FROM
view_product_count_details
JOIN
product_details ON view_product_count_details.product_id_fk = product_details.product_id
JOIN
product_image_details ON product_image_details.product_id_fk = view_product_count_details.product_id_fk
JOIN
main_category_details ON product_details.product_main_cat_id = main_category_details.main_category_id
JOIN
sub_category_details ON product_details.product_sub_cat_id_fk = sub_category_details.sub_category_id
WHERE
view_product_count_details.view_product_status = 'active'
GROUP BY view_product_count_details.product_id_fk
ORDER BY count_sum DESC
LIMIT 4
Here I have multiple images for one product.the images are in table "product_image_details". this query returns count as the number of images, where I need the count of product viewed by people which is stored in table "view_product_count_details". when I just pick the count, i got the count as it is. but when i join the table "product_image details", result become wrong. Is there any way to do it in single query?
Please help me... Thanks in advance.... :)
You can do it by having an inline query. I am not sure how this will perform when you have more data.
SELECT table1.*,product_image_details.product_image_name FROM
(
SELECT
SUM(view_product_count_details.view_product_count) AS count_sum,
product_details.product_id,
product_details.product_name,
product_details.product_url,
product_details.product_price,
main_category_details.main_category_url,
sub_category_details.sub_category_url
FROM
view_product_count_details
JOIN
product_details ON view_product_count_details.product_id_fk = product_details.product_id
JOIN
product_image_details ON product_image_details.product_id_fk = view_product_count_details.product_id_fk
JOIN
main_category_details ON product_details.product_main_cat_id = main_category_details.main_category_id
JOIN
sub_category_details ON product_details.product_sub_cat_id_fk = sub_category_details.sub_category_id
WHERE
view_product_count_details.view_product_status = 'active'
GROUP BY view_product_count_details.product_id_fk
ORDER BY count_sum DESC
LIMIT 4
) table1
JOIN
product_image_details ON product_image_details.product_id_fk = table1.product_id
LIMIT 4
I have taken over a big project, and as the database is becoming large, some of the code stopped working,
Here is the query to find those rendering_requests who's last rending_log is pending, sometimes there are log entries which have no status change and recorded as noaction we dont need to count them. That is what I understood from the query.
SELECT
COUNT(rr.rendering_id) AS recordCount
FROM
rendering_request rr, rendering_log rl
WHERE
rl.rendering_id = rr.rendering_id
AND rl.status = 'pending' AND
rl.log_id = (
SELECT rl1.log_id
FROM rendering_log rl1
WHERE
rl.rendering_id = rl1.rendering_id AND
rl1.status = 'pending'
AND rl1.log_id = (
SELECT rl2.log_id
FROM rendering_log rl2
WHERE rl1.rendering_id = rl2.rendering_id AND rl2.status!='noaction'
ORDER BY rl2.log_id DESC LIMIT 1
)
ORDER BY rl1.log_id DESC
LIMIT 1
)
for example
rendering_id=1 is having multiple logs
status=noaction
status=noaction
status=pending
and
rendering_id=2 is having multiple logs
status=noaction
status=assigned
status=noaction
status=pending
when we run this query it should display count=1 as only the rendering_id=1 is our desired record.
Right now this query has stopped working, and it hangs the mysql server
Not 100% sure I have got this right, but something like this. Think you still need to use a couple of subselects but (depending on the version of MySQL) doing it this way with JOINs should be a lot faster
SELECT COUNT(rr.rendering_id) AS recordCount
FROM rendering_request rr
INNER JOIN rendering_log rl
ON rl.rendering_id = rr.rendering_id
INNER JOIN (SELECT rendering_id, MAX(log_id) FROM rendering_log WHERE status = 'pending' GROUP BY rendering_id) rl1
ON rl1.rendering_id = rl.rendering_id
AND rl1.log_id = rl.log_id
INNER JOIN (SELECT rendering_id, MAX(log_id) FROM rendering_log WHERE status!='noaction' GROUP BY rendering_id) rl2
ON rl2.rendering_id = rl1.rendering_id
AND rl2.log_id = rl1.log_id
WHERE rl.status = 'pending'