mysql--- select result that some key is null in join table - mysql

I have 2 table in mysql
user_titem
item_id item_name
------------------------
1 a
2 b
3 c
5 d
track
--------------------------------------------------------
track_no member_ID member_track track_type
1 2 1 titem
2 2 2 titem
3 2 3 titem
5 2 13 titem
6 2 5 titem
In track, member_track will refer to item_id, so if i do this select statement:
SELECT track.track_no ,track.track_type, user_titem.item_name ,user_titem.item_id
FROM track
LEFT JOIN user_titem ON track.member_track=user_titem.item_id
WHERE track.track_type = 'titem' and track.member_ID='2'
the result is
result
-----------------------------------
track_no track_type item_name item_id
5 titem NULL NULL
The item_name and item_id is null because in track_no(5), member_track(refer to item_id) is not in user_titem.
Now the problem is, how can i just get the track_no directly in one select statement when the member_track of track_no is null.
The result that i want
result
-----------
track_no
5
How can i solve the problem ?

Just add additional check in WHERE clause:
SELECT track.track_no
FROM track
LEFT JOIN user_titem ON track.member_track=user_titem.item_id
WHERE track.track_type = 'titem' and track.member_ID='2'
AND user_titem.item_id is null

Why dont you try
SELECT track_no FROM track where member_track NOT IN (SELECT item_id FROM user_titem)
I think it will give the same result.

Related

How to select data in mysql that all the joined table is not null on certain column

i have 2 table which is one to many
table order
order_id
order_date
1
2021/01/01
2
2021/01/02
3
2021/01/02
table detail order
detail_order_id
order_id
is_finished
1
1
null
2
1
2021/01/03
3
2
2021/01/04
4
2
2021/01/04
5
3
2021/01/05
6
3
2021/01/06
7
3
null
so i wanna data that have condition if some of the detail order rows is_finished column not null, so the status is gonna be not finish.
and if all the detail order rows is_finished column not contain any null value like id 2, so the status is finished
expected result
order_id
status
1
not finish
2
finished
3
not finish
It seems like you don't really need a join since table_detail_order already have order_id and you only want to check is_finished, you might just need a query on 1 table like:
SELECT order_id,
CASE WHEN SUM(is_finished IS NULL)=0
THEN 'Finished' ELSE 'Not finish' END AS 'Status'
FROM table_detail_order GROUP BY order_id;
Demo fiddle
Btw, is_finished IS NULL will return 1 (true) or 0 (false) so in a table it would look like:
order_id
is_finished
is_finished IS NULL
1
null
1
1
2021/01/03
0
2
2021/01/04
0
2
2021/01/04
0
3
2021/01/05
0
3
2021/01/06
0
3
null
1
Therefore SUM(is_finished IS NULL) with GROUP BY order_id; will do something like this:
order_id
SUM(is_finished IS NULL)
1
1+0=1
2
0+0=0
3
0+0+1=1
And that is why CASE WHEN SUM(is_finished IS NULL)=0 ... is considered as finished while otherwise as not finish.
we can solve the problem like this
left join order and order_detail,but has condition order_details.is_finished is null
so we get a result that the joined order_details's is_finished only null
in that case there is no order_details join with order 2
then we regard the result as a temp table,so when joined order_details has data then it is not finished
here is the example data,you can run query in it
select id,
case when order_id>0 then 'not finish' else 'finished' end as status
from (
select o.id,od.order_id from `order` as o
left join order_detail as od
on (o.id=od.order_id and od.is_finished is null)
group by o.id
) as _t
You can try this. This query uses a LEFT JOIN and COUNT. Where the first count counted the NULL values as ZERO and the second count counts all values, then compare the 2 counts, if the first and second count is equal to each other it means that the order details is finished, if not then not finish.
SELECT a.`order_id`,
IF(COUNT(IF(ISNULL(is_finished),0,1))=COUNT(is_finished), 'finished', 'not finish') AS `status` FROM `order` a
LEFT JOIN `detail_order` b ON a.`order_id`=b.`order_id`
GROUP BY a.`order_id` ;
RESULT*
order_id status
-------- ------------
1 not finish
2 finished
3 not finish

Finding time difference based on distinct ids in mySQL

I would like to find the day difference between the latest and the 2nd latest distinct order_id for each user.
The intended output would be:
user_id | order_diff
1 | 1
3 | 7
8 | 1
order_diff represents the difference in days between 2 distinct order_id. In the event that there are no two distinct order_id (as in the case for user id 9), the result is not returned.
In this case, the order_diff for user_id 1 is 1 since the day difference between his 2 distinct order_id is 1. However, there is no order_diff for user_id 9 since he has no 2 distinct `order_id'.
This is the dataset:
user_id order_id order_time
1 208965785 2016-12-15 17:14:13
1 201765785 2016-12-14 17:19:05
1 203932785 2016-12-13 20:41:30
1 209612785 2016-12-14 20:14:32
1 208112785 2016-12-14 20:27:08
1 205525785 2016-12-14 17:01:26
1 208812785 2016-12-14 20:18:23
1 206432785 2016-12-11 20:32:20
1 206698785 2016-12-14 10:50:15
2 209524795 2016-11-26 18:06:21
3 206529925 2016-10-01 10:43:57
3 203729925 2016-10-08 10:43:11
4 204876145 2016-09-24 10:23:49
5 203363157 2016-07-13 23:56:43
6 207784875 2017-01-04 12:21:21
7 206437177 2016-06-25 02:40:33
8 202819645 2016-09-09 11:47:27
8 202819645 2016-09-09 11:47:27
8 202819646 2016-09-08 11:47:27
9 205127187 2016-06-05 22:21:18
9 205127187 2016-06-05 22:21:18
11 207874877 2016-06-17 16:49:44
12 204927595 2016-11-28 23:05:40
This is the code that I am currently using:
SELECT e1.user_id,datediff(e1.order_time,e2.time), e1.order_id FROM
sales e1
JOIN
sales e2
ON
e1.user_id=e2.user_id
AND
e1.order_id = (SELECT distinct order_id FROM sales temp1 WHERE temp1.order_id =e1.order_id ORDER BY order_time DESC LIMIT 1)
AND
e2.order_id = (SELECT distinct order_id FROM sales temp2 WHERE temp2.order_id=e2.order_id ORDER BY order_time DESC LIMIT 1 OFFSET 1)
My output does not produce the desired output and it also ignores the cases where order_ids are the same.
Edit: I would also like the query to be extended to larger datasets where the 2nd most recent order_time may not be the min(order_time)
Based on your fiddle:
select user_id,
datediff(max(order_time),
( -- Scalar Subquery to get the 2nd largest order_time
select max(order_time)
from orders as o2
where o2.user_id = o.user_id -- same user
and o2.order_time < max(o.order_time) -- but not the max time
)
) as diff
from orders as o
group by user_id
having diff is not null -- if there's no 2nd largest time diff will be NULL
Following would work:
Schema (MySQL v5.7)
CREATE TABLE orders
(`user_id` int, `order_id` int, `order_time` datetime)
;
INSERT INTO orders
(`user_id`, `order_id`, `order_time`)
VALUES
(1,208965785,'2016-12-15 17:14:13'),
(1,201765785,'2016-12-14 17:19:05'),
(1,203932785,'2016-12-13 20:41:30'),
(1,209612785,'2016-12-14 20:14:32'),
(1,208112785,'2016-12-14 20:27:08'),
(1,205525785,'2016-12-14 17:01:26'),
(1,208812785,'2016-12-14 20:18:23'),
(1,206432785,'2016-12-11 20:32:20'),
(1,206698785,'2016-12-14 10:50:15'),
(2,209524795,'2016-11-26 18:06:21'),
(3,206529925,'2016-10-01 10:43:57'),
(3,203729925,'2016-10-08 10:43:11'),
(4,204876145,'2016-09-24 10:23:49'),
(5,203363157,'2016-07-13 23:56:43'),
(6,207784875,'2017-01-04 12:21:21'),
(7,206437177,'2016-06-25 02:40:33'),
(8,202819645,'2016-09-09 11:47:27'),
(8,202819645,'2016-09-09 11:47:27'),
(8,202819646,'2016-09-08 11:47:27'),
(9,205127187,'2016-06-05 22:21:18'),
(9,205127187,'2016-06-05 22:21:18'),
(11,207874877,'2016-06-17 16:49:44'),
(12,204927595,'2016-11-28 23:05:40');
Query #1
SELECT dt2.user_id,
MIN(datediff(dt2.latest_order_time,
dt2.second_latest_order_time)) AS order_diff
FROM (
SELECT o.user_id,
o.order_time AS latest_order_time,
(SELECT o2.order_time
FROM orders AS o2
WHERE o2.user_id = o.user_id AND
o2.order_id <> o.order_id
ORDER BY o2.order_time DESC LIMIT 1) AS second_latest_order_time
FROM orders AS o
JOIN (SELECT user_id, MAX(order_time) AS latest_order_time
FROM orders
GROUP BY user_id) AS dt
ON dt.user_id = o.user_id AND
dt.latest_order_time = o.order_time
) AS dt2
WHERE dt2.second_latest_order_time IS NOT NULL
GROUP BY dt2.user_id;
| user_id | order_diff |
| ------- | ---------- |
| 1 | 1 |
| 3 | 7 |
| 8 | 1 |
View on DB Fiddle
Details:
We determine maximum order_time for a user_id in a sub-select query (Derived Table). We can alias it as latest_order_time.
We Join this result-set to the orders table. This will help us in considering only the row(s) with maximum value of order_time for a user_id.
Now, we use a Correlated Subquery to determine the maximum order_time value for the same user, out of the rest of order_id value(s). We can alias it as second_latest_order_time.
Finally, use this as a Derived Table again, and remove all the cases where second_latest_order_time is null, and calculate datediff() for the rest.
A final Group By is needed, as your data has multiple entries for a
Here is the solution:
SELECT user_id,
DATEDIFF(MAX(order_time), MIN(order_time)) as order_diff
FROM orders
GROUP BY user_id
HAVING order_diff > 0;
Here is a link to test it.

MySQL Putting in duplicate id's

I'm trying to run an UPDATE query that uses the same table and I'm getting an error saying "1093 - Table 'queues_monitor_times' is specified twice, both as a target for 'UPDATE' and as a separate source for data".
UPDATE queues_monitor_times
SET queue_id = IF((
SELECT id
FROM queues_monitor_times
INNER JOIN(
SELECT pcc_group, pcc, gds, queue, category, `name`
FROM queues_monitor_times
GROUP BY pcc_group, pcc, gds, queue, category, `name`
HAVING COUNT(id) > 1
)temp ON queues_monitor_times.pcc_group = temp.pcc_group AND
queues_monitor_times.pcc = temp.pcc AND
queues_monitor_times.gds = temp.gds AND
queues_monitor_times.queue = temp.queue AND
queues_monitor_times.category = temp.category AND
queues_monitor_times.`name` = temp.`name`), 1, id)
WHERE
id NOT IN (SELECT MIN(id) FROM queues_old GROUP BY pcc_group, pcc, gds, queue, category, `name`);
I ran the select query by itself and it showed all the rows that were duplicates, which is what I wanted. I want queue_id to be set with the lowest duplicate row's id if the row is a duplicate or the row id if it is not.
Example of what the query should do:
id dup_id name value
1 1 John 13
2 2 John 13
3 3 Sally 6
4 4 Frank 4
5 5 Sally 6
And after running the query it will turn into
id dup_id name value
1 1 John 13
2 1 John 13
3 3 Sally 6
4 4 Frank 4
5 3 Sally 6
Please advise and thank you for your help.
I was able to solve my problem. Thanks for all your help!
UPDATE queues_monitor_times
SET queue_id = (
SELECT
id
FROM
queues_old
WHERE
queues_old.pcc_group = queues_monitor_times.pcc_group
AND queues_old.pcc = queues_monitor_times.pcc
AND queues_old.gds = queues_monitor_times.gds
AND queues_old.queue = queues_monitor_times.queue
AND queues_old.category = queues_monitor_times.category
AND queues_old.`name` = queues_monitor_times.`name`
GROUP BY pcc_group, pcc, gds, queue, category, `name`
HAVING COUNT(id) > 1)
WHERE
id NOT IN (SELECT MIN(id) FROM queues_old GROUP BY pcc_group, pcc, gds, queue, category, `name`);
For those that will want to use this in the future, queues_monitor_times table and queues_old table have the exact same data.

Need to display records join results as well as remaing qty without join

i have 3 tables. need to display records join results as well as remaing qty without join
tblBookhead
BookHeadId, bookname, bookauthor,...
tblBookDetail
BookHeaddetailId,BookHeadId,Qty
tblBookorder
orderid,BookHeaddetailId , orderqty
select * from tblBookhead bh inner join tblBookDetail bd on
bh.BookHeadId=bd.BookHeadId inner join tblBookorder br on
br.BookHeaddetailId=db.BookHeaddetailId where BookHeadId=1;
this will retrun good results no problem.
but now if qty is 10 for BookHeadId=1 and orderqty=5 then result need to display remaing 5 qty without join (my expectation is null values for remaining qty in tblBookorder )
my expected result would be:
BookHeadId, bookname, bookauthor,... BookHeaddetailId,BookHeadId,Qty,orderid,BookHeaddetailId , orderqty
1 1 john 1 1 10 1 1 5
1 1 john 1 1 10 null null null

Get either the value or null entry on row in SQL

I have four tables, products, priceplans, and two category tables as follows:
products
---------
product_id
a
b
priceplans
---------
priceplan_id
a
b
product_id (can be null)
price
categoryA
---------
a (id)
category_name
categoryB
---------
b (id)
category_name
In the priceplans a and b are category ids in other tables, the combination (a,b,product_id) is unique but product_id can also be null, and the priceplan should then use the general priceplan for the (a,b,null) combination. That is the theory, but it is not working out as well as I had hoped and I havent managed to construct a query to only filter them out.
Example:
products - 3 products, 2 in the same category, one in another category
product_id a b
1 1 1
2 1 1
3 1 2
priceplans - 3 plans,
1 is for the default (a,b)=(1,1) category combination when there is no product_id,
2 is supposed to override the default as we have declared a product_id, and
3 is the default for (a,b)=(1,2) combination
priceplan_id a b product_id price
1 1 1 null 10
2 1 1 2 15
3 1 2 null 12
What I want the outcome to look like when I join products with the priceplans is:
product_id a b priceplan_id price
1 1 1 1 10
2 1 1 2 15
3 1 2 3 12
If for the product with a category combination (a,b)=(1,1) and id=1 i want the priceplan with combination (a,b,1) if it exists, if not i want the (a,b,null) priceplan. Any suggestions?
I finally managed to create the query I was looking for:
select pro.*, pp.* from products pro
left join price_plans pp
on pro.a=pp.a
and pro.b=pp.b
and (pro.product_id=pp.product_id or pp.product_id is null)
left join price_plans pp2
on pro.a=pp2.a
and pro.b=pp2.b
and pp2.product_id =pro.product_id
where pp.product_id <=> pp2.product_id