MYSQL Select two tables with multiple which is not there - mysql

I try to use LEFT JOIN but I dont get the result I want.
I have 2 tables
Table 1:
Persons
UID | Names | GID
1 | Mike | 1
2 | Tom | 1
3 | Brenda | 1
4 | Sophie | 2
Table 2:
DailyLog
ID | UID | GID | DATE
1 | 1 | 1 | 2017-10-13
2 | 2 | 1 | 2017-10-13
3 | 3 | 1 | 2017-10-13
4 | 1 | 1 | 2017-10-13
5 | 2 | 1 | 2017-10-14
6 | 1 | 1 | 2017-10-14
7 | 1 | 1 | 2017-10-15
I want search a name who is not have a stamp date of today (2017-10-15) in GID 1,
a result like this:
UID | Name
2 | Tom
3 | Brenda
I use SQL Left Join, but the result not what I expected.
SELECT DISTINCT a.uid
, a.Name
, b.date
FROM Persons AS a
LEFT
JOIN dailylog AS b
ON a.uid = b.uid
AND a.gid = b.gid
WHERE (b.date IS NULL OR b.date !='2017-10-15' )
AND a.gid='1'
Thank you

you could use a not In clause
SELECT a.uid
, a.Name
, b.date
FROM Persons
where uid not in (
select uid from DailyLog
where GID = 1
and DATE = '2017-10-15'
)

Related

Compare two MYSQL tables and return missing dates and group by column

I have two tables. I want to compare table A with B and get the missing date from with name of the user.
TABLE A
|----|----------|------------|
| 1 | king | 2020-08-01 |
| 2 | king | 2020-08-02 |
| 3 | queen | 2020-08-01 |
| 4 | queen | 2020-08-02 |
| 5 | rook | 2020-08-03 |
| 6 | bishop | 2020-08-01 |
| 7 | bishop | 2020-08-01 |
| 8 | queen | 2020-08-03 |
TABLE B
| id | working_date |
|----|--------------|
| 1 | 2020-08-01 |
| 2 | 2020-08-02 |
| 3 | 2020-08-03 |
EXPECTED OUTPUT
| name | missing_date |
|--------|--------------|
| king | 2020-08-03 |
| rook | 2020-08-01 |
| rook | 2020-08-02 |
| bishop | 2020-08-02 |
| bishop | 2020-08-03 |
Also, Along with it can I get the count of the missing dates for each user if possible?
You must cross join Table B to the distinct names of Table A and then left join Table A to filter out the matching rows:
select n.name, b.working_date missing_date
from TableB b
cross join (select distinct name from TableA) n
left join TableA a on a.name = n.name and a.working_date = b.working_date
where a.id is null
If you want to count the missing_dates use the same query and group by name:
select n.name, count(*) missing_dates
from TableB b
cross join (select distinct name from TableA) n
left join TableA a on a.name = n.name and a.working_date = b.working_date
where a.id is null
group by n.name
See the demo.
Results:
> name | missing_date
> :----- | :-----------
> king | 2020-08-03
> rook | 2020-08-01
> rook | 2020-08-02
> bishop | 2020-08-02
> bishop | 2020-08-03
and:
> name | missing_dates
> :----- | ------------:
> bishop | 2
> king | 1
> rook | 2
Getting distinct user names from Table A and joining it with Table B you can create all working date variations of the users. Then with not exists you can list missing dates:
SELECT A1.name, B.working_date
FROM B JOIN
(SELECT DISTINCT name
FROM A) A1
WHERE NOT EXISTS (
SELECT *
FROM A
WHERE A.name = A1.name
and A.working_date = B.working_date
)
For your last question finding missing counts you can use the below query:
SELECT S.name, COUNT(1) AS 'MissingDatesCount'
FROM (
SELECT A1.name, B.working_date
FROM B JOIN
(SELECT DISTINCT name
FROM A) A1
WHERE NOT EXISTS (
SELECT *
FROM A
WHERE A.name = A1.name
and A.working_date = B.working_date
)
) S
GROUP BY S.name
Go to the SqlFiddle

SQL select with complicated conditions

I'm banging my head with some SQL query and pretty much the logic behind it.
Let's assume we have these tables:
Table hotels
+----+---------+
| id | name |
+----+---------+
| 1 | Hotel A |
+----+---------+
Table hotel_rooms
+----+----------+-----------+
| id | hotel_id | room_type |
+----+----------+-----------+
| 1 | 1 | dbl | <- can be used as A,B,C,D,E,F
| 2 | 1 | dbl | <- can be used as B,C,D,E,F
| 3 | 1 | sng | <- can be used as A
| 4 | 1 | trp | <- can be used as D,E,F
+----+----------+-----------+
Table hotel_room_usages
+----+---------+-------+
| id | room_id | usage |
+----+---------+-------+
| 1 | 1 | B |
| 2 | 1 | C |
| 3 | 1 | A |
| 4 | 1 | D |
| 5 | 1 | E |
| 6 | 1 | F |
| 7 | 2 | B |
| 8 | 2 | C |
| 9 | 2 | D |
| 10 | 2 | E |
| 11 | 2 | F |
| 12 | 3 | A |
| 13 | 4 | D |
| 14 | 4 | E |
| 15 | 4 | F |
+----+---------+-------+
If I search for 2 rooms with usage A or 3 rooms with usage D as separate queries the result should be Hotel A with the corresponding IDs of the rooms.
The problem is if I search for 2 rooms with usage A and 3 rooms with usage D at the same time it returns also the hotel A because it doesn't count that some rooms can be used as A and D.
The rooms should be unique /total of 5/. The current example should not return a result because there are total of 4 rooms in the hotel.
does this help?
-- two rooms with usage a
select id from hotel_room_usages where usage = 'a'
-- three rooms with usage d
select id from hotel_room_usages where usage = 'd'
-- count of rooms with either
select count(distinct(room_id)) from hotel_room_usages where usage in ('a','d')
SELECT h.name AS hotel_name
, q.*
FROM
(
SELECT r.hotel_id
, COUNT(DISTINCT CASE WHEN ruA.room_id IS NOT NULL AND ruD.room_id IS NULL THEN ruA.room_id END) AS TotalRoomsOnlyA
, COUNT(DISTINCT CASE WHEN ruD.room_id IS NOT NULL AND ruA.room_id IS NULL THEN ruD.room_id END) AS TotalRoomsOnlyD
, COUNT(DISTINCT CASE WHEN ruA.room_id IS NOT NULL AND ruD.room_id IS NOT NULL THEN r.id END) AS TotalRoomsAandD
, COUNT(DISTINCT r.id) AS TotalRoomsAorD
FROM hotel_rooms AS r
LEFT JOIN hotel_room_usages AS ruA ON (ruA.room_id = r.id AND ruA.usage = 'A')
LEFT JOIN hotel_room_usages AS ruD ON (ruD.room_id = r.id AND ruD.usage = 'D')
WHERE (ruA.room_id IS NOT NULL OR ruD.room_id IS NOT NULL)
GROUP BY r.hotel_id
) q
JOIN hotels AS h ON (h.id = q.hotel_id)
CROSS JOIN (SELECT 2 AS a, 3 AS d) AS n
WHERE TotalRoomsAorD >= (a+d)
AND (
((TotalRoomsOnlyA + TotalRoomsAandD) >= a AND TotalRoomsOnlyD >= d) OR
(TotalRoomsOnlyA >= d AND (TotalRoomsOnlyD + TotalRoomsAandD) >= d) OR
((TotalRoomsOnlyA + TotalRoomsAandD/2) >= a AND (TotalRoomsOnlyD + TotalRoomsAandD/2) >= d)
)
ORDER BY h.name;
Test on db<>fiddle here

MySql Left Join records where is null with handling validUntil Row

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;

use standard values if there is no overlap in table columns

I have a table ce_relations and a table ce_values which i want to combine to a table ce_combined_values. The ce_combined_values table should have the exact same amount of rows as ce_relations. The query stated below does however only return the rows where the user_id and friend_id is existing in the ce_values.user_id column. I tried to solve this problem by using the IFNULL statement, but i guess there is also an extra condition missing in the WHERE clausule... any help is welcome!
INSERT INTO ce_combined_values (user_id, friend_id, relation_degree, user_value, friend_value, relation_value)
SELECT a.user_id, a.friend_id, a.relation_degree, IFNULL(b.1d_value, 0) as user_value, IFNULL(c.1d_value, 0) as friend_value, Least(b.1d_value, c.1d_value) as relation_value
FROM ce_relations a, ce_values b, ce_values c
WHERE a.relation_degree = 1 AND b.user_id = a.user_id AND c.user_id = a.friend_id AND b.user_id <> c.user_id
Union all
//same select query is used for relation_degree 2 with 2d_values and relation_degree 3 with 3d_values.
EDIT:
For example this is what I want to achieve:
table ce_relations:
+---------+-----------+-----------------+
| user_id | friend_id | relation_degree |
+---------+-----------+-----------------+
| 1 | 3 | 1 |
| 2 | 1 | 1 |
| 3 | 4 | 1 |
+---------+-----------+-----------------+
table ce_values:
+---------+----------+----------+----------+
| user_id | 1d_value | 2d_value | 3d_value |
+---------+----------+----------+----------+
| 1 | 5 | 10 | 33 |
| 2 | 10 | 12 | 44 |
| 3 | 20 | 13 | 55 |
+---------+----------+----------+----------+
should become ce_combined values ( deleted relation_degree and relation_value for readability)
+---------+-----------+------------+--------------+
| user_id | friend_id | user_value | friend_value |
+---------+-----------+------------+--------------+
| 1 | 3 | 5 | 20 |
| 2 | 1 | 10 | 5 |
| 3 | 4 | 20 | 0 |
+---------+-----------+------------+--------------+
but currently returns ( the row with friend_id = 4 is missing because it doesn't exist in ce_values)
+---------+-----------+------------+--------------+
| user_id | friend_id | user_value | friend_value |
+---------+-----------+------------+--------------+
| 1 | 3 | 5 | 20 |
| 2 | 1 | 10 | 5 |
+---------+-----------+------------+--------------+
If I understand your problem correctly, you need to LEFT JOIN your tables. And I don't think you need to UNION ALL the same query three times with just a different filter condition.
Maybe that helps you:
SELECT a.user_id, a.friend_id, a.relation_degree,
IFNULL(b.value, 0) as user_value,
IFNULL(c.value, 0) as friend_value,
Least(b.value, c.value) as relation_value
FROM ce_relations a
LEFT
JOIN ce_values b
ON a.user_id = b.user_id
LEFT
JOIN ce_values c
ON a.friend_id = c.user_id
AND b.user_id <> c.user_id
WHERE a.relation_degree IN (1, 2, 3)

Get all actions of the last-three users for each post

In a last Question, i asked about geting all actions of the last three users from a history table that stores all actions done by users on deferments posts, now what i want is to get the same thing but for each post.
all actions of donne by the last-three users for each posts
history table
id | post_id | action | user_id
1 | 5 | 1 | 3
1 | 23 | 2 | 1
2 | 24 | 2 | 6
3 | 34 | 1 | 7
4 | 35 | 1 | 1
5 | 36 | 1 | 1
6 | 23 | 2 | 3
7 | 24 | 2 | 1
8 | 23 | 1 | 4
9 | 24 | 1 | 5
10 | 24 | 1 | 1
11 | 23 | 1 | 2
12 | 23 | 4 | 1
thanks and sorry if it seem to be a duplicate post
I think this will work:
SELECT a.user_ID, a.post_id, a.action
FROM tableName a
INNER JOIN
(
SELECT DISTINCT
#curRow:=IF(#prevRow=post_Id,#curRow+1,1) rn,
user_ID,
Post_Id,
#prevRow:=Post_Id
FROM (
SELECT DISTINCT Post_Id, User_Id
FROM TableName
ORDER BY Post_Id, ID DESC
) t
JOIN (SELECT #curRow:= 0) r
) b ON a.post_id = b.post_id AND a.user_id = b.user_id
WHERE b.rn <= 3
ORDER BY a.post_id, a.User_ID
And the Fiddle.
Coudl this be what you are looking for?
SQLFiddle
Code:
SELECT a.user_ID,
group_concat(a.post_id),
group_concat(a.action)
FROM tableName a
INNER JOIN
(
SELECT DISTINCT user_ID
FROM tableName
ORDER BY ID DESC
LIMIT 3
) b ON a.user_ID = b.user_ID
group by a.user_id
ORDER BY a.User_ID;
| USER_ID | GROUP_CONCAT(A.POST_ID) | GROUP_CONCAT(A.ACTION) |
--------------------------------------------------------------
| 2 | 7 | 3 |
| 3 | 5,5,4 | 1,2,5 |
| 6 | 7 | 2 |