I have a table something like this:
----------------------------------------
|uID|responseDate|field_01|field_02|etc|
+---+------------+--------+--------+---+
| 1 | 2011-12-02 | yes | no | |
| 2 | 2011-11-25 | no | yes | |
| 1 | 2012-01-02 | no | yes | |
| 2 | 2012-12-01 | no | no | |
| 3 | 2010-01-02 | yes | no | |
+---+------------+--------+--------+---+
I would like to get uIDs and responseDates for whom the latest response to field_01 is 'yes' - so my query should return:
------------------
|uID|responseDate|
+---+------------+
| 3 | 2010-01-02 |
+---+------------+
I'm using an inner join, but incorrectly. Here is my query:
SELECT f.uID, f.responseDate
FROM form_05 as f
INNER JOIN (
SELECT uID, max(responseDate) AS latest_date
FROM form_05
WHERE field_01 = 'yes'
GROUP BY uID ) dmax
ON dmax.uID = f.uID and dmax.latest_date = f.responseDate
ORDER BY f.uID ASC;
What this returns, however, is the latest entries for each uID where field_01 is yes, i.e.:
------------------
|uID|responseDate|
+---+------------+
| 1 | 2011-12-02 |
| 3 | 2010-01-02 |
+---+------------+
But I don't want that. I'd like to make it so that only the latest entry for each uID is eligible for the test. How can I restructure the query? Any pointers are greatly appreciated.
Give this a try and let me know if it doesn't work:
select t2.uid, t2.responseDate from t2
left join (
select t1.uid, max(t1.responseDate) as MaxDate from t1
group by t1.uid
) as SubQuery on t2.uid = SubQuery.uid and t2.responseDate = SubQuery.MaxDate
where MaxDate is not null and field_01 = "yes"
Related
I have some table like this
table request_buys
| id | invoice | user_id |
| -- | ----------------- | ------- |
| 3 | 20220405/01104298 | 1 |
table traces
| id | request_buy_id | status_id | created_at |
| -- | -------------- | --------- | ------------------- |
| 37 | 3 | 1 | 2022-03-27 14:12:25 |
| 38 | 3 | 2 | 2022-03-28 14:12:25 |
| 39 | 3 | 3 | 2022-03-29 14:12:25 |
| 40 | 3 | 4 | 2022-03-30 14:12:25 |
| 41 | 3 | 5 | 2022-03-31 14:12:25 |
| 42 | 3 | 6 | 2022-04-01 14:12:25 |
table statuses
| id | nama |
| -- | ----------------- |
| 1 | Order Placed |
| 2 | Order Paid |
| 3 | Accepted |
| 4 | Picked by Courier |
| 5 | In Transit |
| 6 | Delivered |
| 7 | Rated |
| 8 | Rejected |
| 9 | Canceled |
and then i try to design query like below
select
request_buys.invoice,
MAX(traces.id) as traces_id,
MAX(statuses.nama) as statuses_nama
from
`request_buys`
inner join `traces` on `request_buys`.`id` = `traces`.`request_buy_id`
inner join `statuses` on `traces`.`status_id` = `statuses`.`id`
where
`user_id` = 1
group by
request_buys.id
and produces output like the following
output
| invoice | traces_id | statuses_nama |
| ----------------- | --------- | ----------------- |
| 20220405/01104298 | 42 | Picked by Courier |
and the output i expect should be like in the table below
expect
| invoice | traces_id | statuses_nama |
| ----------------- | --------- | ----------------- |
| 20220405/01104298 | 42 | Delivered |
I understand my error is in MAX(statuses.nama) which I should change like removing MAX() in statuses.nama
But i just get error like this "SELECT list is not in GROUP BY clause and contains nonaggregated ... this is incompatible with sql_mode=only_full_group_by"
then I tried some to clear the value "ONLY_FULL_GROUP_BY" with a query like the following
SET sql_mode=(SELECT REPLACE(##sql_mode,'ONLY_FULL_GROUP_BY',''))
and the result is like this
output
| invoice | traces_id | statuses_nama |
| ----------------- | --------- | ----------------- |
| 20220405/01104298 | 42 | Order Placed |
and I'm really stuck at this
and how to make trace_id.status_id from the "GROUP BY" result based on request_buys.id still have a relationship with statuses.id
Your problem lies with your misuse of the MAX(statuses.nama) expression. Based on your expected output,you intend to get the statuses.nama which matches the MAX(traces.id), NOT the MAX(statuses.nama) value which returns the highest value in terms of alphabetic order. In this case, the initial letter 'P' > 'D' . I have tweaked your code a bit and tried it on workbench,supposing there are more than one invoice for a particular user.(e.g insert into request_buys values (4,'20230405/01104298',1); insert into traces values (43,4,7,'2022-04-01 14:12:25');) It works as intended.
select invoice, t.id as traces_id, s.nama as statuses_name from request_buys r
join traces t on r.id=t.request_buy_id
join statuses s on t.status_id=s.id
join
(select traces.request_buy_id, MAX(traces.id) as traces_id
from `request_buys`
inner join `traces` on `request_buys`.`id` = `traces`.`request_buy_id`
where
`user_id` = 1
group by
traces.request_buy_id ) join_t
on t.request_buy_id=join_t.request_buy_id and t.id=join_t.traces_id
;
If I'm understanding correctly, you're trying to retrieve the most recent status for each invoice. Using MAX(nama) won't return that result, because it just picks the maximum status name alphabetically.
Assuming you're using MySQL 8.x, use ROW_NUMBER() to sort and rank the statuses for each invoice, by the most recent date first. Then grab the latest one using where rowNum = 1
WITH cte AS (
SELECT rb.id AS request_buy_id
, rb.invoice
, t.id AS traces_id
, s.nama AS statuses_nama
, ROW_NUMBER() OVER(PARTITION BY rb.id ORDER BY t.created_at DESC) AS RowNum
FROM request_buys rb
INNER JOIN traces t ON rb.id = t.request_buy_id
INNER JOIN statuses s ON t.status_id = s.id
WHERE user_id = 1
)
SELECT *
FROM cte
WHERE RowNum = 1
;
Result:
request_buy_id
invoice
traces_id
statuses_nama
RowNum
3
20220405/01104298
42
Delivered
1
db<>fiddle here
I need to join tableA and tableB on UniqueID however I only want to join on the latest Date in tableA with certain Status restrictions (Not in S). I know I need to use the Max functions however I can't get it to work. How do I get the result table below?
I was thinking of something like:
Select
tableA.UniqueID,
MAX(tableA.Date),
tableA.Status,
tableB.Col1
From tableA
Inner join tableB on (tableB.UniqueID = tableA.UniqueID and tableA.Status = 'A')`
tableA:
| UniqueID | Date | Status |
| -------- | ------------------- |--------|
| 123 | 2015-07-05 00:00:00 | S |
| 123 | 2015-07-06 00:00:00 | S |
| 123 | 2015-07-07 00:00:00 | A |
and tableB:
| UniqueID | Col1 |
| -------- | - |
| 123 | X |
| 125 | Y |
| 126 | Z |
Result table:
| UniqueID | Date | Status | Col1|
| -------- | ------------------- |--------|---- |
| 123 | 2015-07-07 00:00:00 | A | X |
This is one of the ways -
select
t_a.*, t_b.*
from
table_b t_b
join
(
select
uniqueid, date, status,
rank() over (partition by uniqueid order by date desc ) rank_
from
table_a
) t_a on t_b.uniqueid = t_a.uniqueid
where
t_a.rank_ = 1
;
fiddle url : (https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=06660177b6c116a811218863ce428985)
How to select all addons which a specific user has not buyed or are no longer valid?
Assuming currentdate is 2017-03-02 17:00:00
Table1 (users):
+-----------+----------+
| id | username |
+-----------+----------+
| 1 | Walter |
| 2 | Hank |
| 3 | John |
+-----------+----------+
Table2 (buyLog):
+-----------+----------+------------+---------------------+
| id | idUsers | idItems | validUntil |
+-----------+----------+------------+---------------------+
| 1 | 1 | 1 | 2016-03-02 14:15:47 |
| 2 | 1 | 1 | 2018-03-02 14:15:47 |
| 3 | 1 | 2 | 2016-03-02 14:15:47 |
| 4 | 2 | 1 | 2018-03-02 14:15:47 |
+-----------+----------+------------+---------------------+
Table3 (addons):
+-----------+----------+
| id | name |
+-----------+----------+
| 1 | Foo |
| 2 | Bar |
| 3 | Lorem |
+-----------+----------+
Expected output for user with id 1 should be:
+-----------+----------+
| id | name |
+-----------+----------+
| 2 | Bar |
| 3 | Lorem |
+-----------+----------+
See SQL Fiddle here: http://sqlfiddle.com/#!9/16356
Where I have the most problems is to handle the validUntil in the leftJoin.
I think I have to group by during the left join to tread only the most recent validUntil record. Maybe using max(validUntil)?
This code will work
http://sqlfiddle.com/#!9/16356/1/0
SELECT
C.ID AS 'ID',
C.NAME AS 'NAME'
FROM
(SELECT
A.id AS 'ID',A.name AS 'NAME',
CASE
WHEN B.YY > '2017-03-02 17:00:00' THEN 0
ELSE 1 END AS 'Tag'
FROM
addons AS A
LEFT JOIN
(SELECT idItems AS 'XX', MAX(validUntil) AS 'YY'
FROM
buyLog
WHERE idUsers = 1 GROUP BY 1) AS B
ON
A.id = B.XX) AS C
WHERE
C.Tag = 1
My sense is that neither your explanation nor your data set and desired result are adequate to the task of explaining the problem. The following query produces the desired result, but perhaps that's just coincidence...
SELECT a.*
FROM addons a
LEFT
JOIN buylog b
ON b.iditems = a.id
AND b.validuntil > NOW()
LEFT
JOIN users u
ON u.id = b.idusers
AND u.id = 1
WHERE b.validuntil IS NULL
AND u.id IS NULL;
I have two tables:
Problems
id | name
Responses
id | problem_id | user_id | value
I have the following statement.
SELECT
`problems`.name,
problem_id,
sum(value) as knowledge,
COUNT(*) as attempts FROM `responses`
LEFT JOIN `problems` ON `problems`.id = `responses`.problem_id
WHERE problem_id IS NOT NULL AND user_id = 4
GROUP BY problem_id
It produces a list like so:
| name | problem_id | knowledge | attempts |
| NULL | 1 | 6 | 6 |
| NULL | 2 | 5 | 6 |
| NULL | 3 | 4 | 6 |
| NULL | 4 | 3 | 5 |
I'm missing something and I would be grateful if someone could help format to:
| name | problem_id | knowledge | attempts |
| Problem A | 1 | 6 | 6 |
| Problem B | 2 | 5 | 6 |
| Problem C | 3 | 4 | 6 |
| Problem D | 4 | 3 | 5 |
Try this.
select p.`name`, p.`id`, r.`user_id`, sum(r.`value`) as knowledge
from
`responses` r
join `problems` p on r.`problem_id` = p.`id`
where
r.`user_id` = 4
group by p.`name`, p.`id`
You cannot have in your SELECT something that is neither an aggregate function (like SUM or AVG), nor a variable part of the GROUP BY.
In your case, the name is neither.
Some DBMS might let you do it (MySQL), but the result is unpredictable.
Solution:
SELECT
`problems`.name,
problem_id,
sum(value) as knowledge,
COUNT(*) as attempts FROM `responses`
LEFT JOIN `problems` ON `problems`.id = `responses`.problem_id
WHERE problem_id IS NOT NULL AND user_id = 4
GROUP BY problem_id, problems.name
EDIT: I think I got it. Will do further test tomorrow and I'll get back to this post. Thanks guys!
I'm trying to query for the last transaction made for each item on tbl_invty that doesn't have the transaction type "Idle" from table tbl_trans. The multiplicity of transactions is confusing me on getting my query right and all I was able to do so far was joining the two tables below on tbl_invty.code=tbl_trans.code. How do I go about this so I could output only rows 2 and 3 from tbl_invty joined with rows 5 and 8 from tbl_trans based on the column code?
tbl_invty
+------+-------------+
| CODE | DESCRIPTION |
+------+-------------+
| 1 | abc |
| 2 | bbb |
| 3 | cdf |
+------+-------------+
tbl_trans
+----------+------+--------+------------+
| TRANS_ID | CODE | TYPE | TRANS_DATE |
+----------+------+--------+------------+
| 1 | 1 | NEW | 2012-09-29 |
| 2 | 1 | UPDATE | 2012-09-30 |
| 3 | 1 | IDLE | 2012-09-30 |
| 4 | 2 | NEW | 2012-09-29 |
| 5 | 2 | UPDATE | 2012-09-30 |
| 6 | 3 | NEW | 2012-09-29 |
| 7 | 3 | UPDATE | 2012-09-30 |
| 8 | 3 | UPDATE | 2012-09-30 |
+----------+------+--------+------------+
SELECT tt.*, result.* from tbl_trans tt
INNER JOIN
(SELECT DESCRIPTION, MAX(t.TRANS_ID) as TRANS_ID ,i.`CODE`,
GROUP_CONCAT(t.`TYPE`) TYPES
from tbl_invty i
LEFT JOIN tbl_trans t
ON i.CODE = t.CODE
GROUP BY i.`CODE`
HAVING NOT FIND_IN_SET('IDLE',TYPES)) result
ON tt.TRANS_ID = result.TRANS_ID;
SAMPLE FIDDLE
Try something like this:
SELECT i.des, i.code, max(t.trans_id), max(t.date)
FROM tbl_invty i left join tbl_trans t
ON t.code = i.code
WHERE i.code <> 1 AND t.type <> 'IDLE'
GROUP BY i.code;
SQL Fiddle..
EDIT: I just notice what you're looking for, check this:
SELECT i.des, i.code, max(t.trans_id), max(t.date)
FROM tbl_invty i left join tbl_trans t
ON t.code = i.code
where t.code not in (select code from tbl_trans
where type = 'IDLE')
group by i.code;
SQL Fiddle..