i have a table like this
Sender_id | Receiver_id | Topic
456 | 123 | 1
123 | 456 | 3
123 | 456 | 2
456 | 123 | 2
123 | 789 | 1
123 | 456 | 1
123 | 789 | 4
456 | 123 | 1
I want to know for every given Topic who are the speakers (can be both sender or receiver) involved in that conversation
eg. for Topic 2, Mr. 123 and Mr. 456 are the only two speakers
The desired result would be to have just the values: 123, 456
Speakers | Topic
123 | 2
456 | 2
this is my first attempt but i want ot merge the two resulting columns
SELECT *
FROM (
SELECT sender_id
FROM [table]
WHERE topic = '2'
AND sender_id !=0
GROUP BY sender_id) a
INNER JOIN (
SELECT receiver_id
FROM [table]
WHERE topic = '2'
AND receiver_id !=0
GROUP BY receiver_id) b
ON sender_id
You don't need a JOIN, you need a UNION:
SELECT sender_id Speakers
FROM [table]
WHERE topic = '2'
AND sender_id !=0
UNION
SELECT receiver_id
FROM [table]
WHERE topic = '2'
AND receiver_id !=0
You don't need to group to remove duplicate values as the UNION does that for you.
SELECT Sender_id as speakers, Topic from Table1 WHERE Topic ='2'
UNION
SELECT Receiver_id as speakers, Topic FROM Table1 WHERE Topic = '2'
Working fiddle http://sqlfiddle.com/#!9/4cf5e3/2
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,Sender_id INT NOT NULL
,Receiver_id INT NOT NULL
,Topic INT NOT NULL
);
INSERT INTO my_table (sender_id,receiver_id,topic) VALUES
(456,123,1),
(123,456,3),
(123,456,2),
(456,123,2),
(123,789,1),
(123,456,1),
(123,789,4),
(456,123,1);
SELECT speaker FROM
(
SELECT sender_id speaker,topic FROM my_table
UNION
SELECT receiver_id,topic FROM my_table
) x
WHERE topic = 2;
+---------+
| speaker |
+---------+
| 123 |
| 456 |
+---------+
Related
I have 3 mysql tables:
Users:
id | name | interest | user_id
1 | user1 | 1,2 | 1
2 | user2 | 1,2,3 | 2
Interests:
id | name
1 | interest1
2 | interest2
User_posts:
id | user_id | desc
1 | 23 | something..
2 | 31 | something..
What i want to achieve is i want join interest column from users table into user_posts table based on user_id with user_name from interests table which i have already done using this query:
select user_posts.*, users.interest as interest_ids, zaya.interests.name as interest_name
from user_posts
left join users ON user_posts.id = users.interest
left join interests ON user_posts.id = users.interest;
i get the following output with this query:
User_posts:
id | user_id | desc | interest_ids | interest_name
1 | 23 | something.. | 1,2 | interest1
2 | 31 | something.. | 1,2,3 | interest1
Output i want to achieve:
User_posts:
id | user_id | desc | interest_ids | interest_name
1 | 23 | something.. | 1,2 | interest1, interest2
2 | 31 | something.. | 1,2,3 | interest1, interest2, interest3
I believe this can be solved using the temporary table creation method and have tried solving this but i'm newbie in mysql queries and getting errors please help me with the correct query.
Thank you in advance.
I would use a sub query rather than a join if you're looking to just get back one col form the [interests] table.
Here is an example using STRING_SPLIT function to get the names :
DECLARE #users TABLE(
[ID] int IDENTITY(1,1)
,[NAME] varchar(32)
,[INTERESTS] varchar(32)
)
INSERT INTO #users
VALUES ('user1', '1,2'), ('user2', '1,2,3')
DECLARE #interests TABLE(
[ID] int IDENTITY(1,1)
,[NAME] varchar(32)
)
INSERT INTO #interests
VALUES ('interests1'), ('interests2'), ('interests3')
DECLARE #user_posts TABLE(
[ID] int IDENTITY(1,1)
,[USERID] int
,[DESC] varchar(32)
)
INSERT INTO #user_posts
VALUES (1, 'post1'), (2, 'post2')
SELECT
U.[ID]
,UP.[USERID]
,UP.[DESC]
,U.[INTERESTS]
,SUBSTRING((SELECT ',' + I2.[NAME]
FROM #interests I2
WHERE I2.[ID] IN (SELECT [name] FROM STRING_SPLIT(U.[INTERESTS], ','))
FOR XML PATH('')), 2, 1000) AS 'INTEREST_NAME'
FROM #user_posts UP
LEFT JOIN #users U
ON U.[ID] = UP.[USERID]
This should return :
ID
USERID
DESC
INTERESTS
INTEREST_NAME
1
1
post1
1,2
interests1,interests2
2
2
post2
1,2,3
interests1,interests2,interests3
1)The sample data set looks like this:
create table user(
user_id int,
name varchar(10),
surname varchar(10)
);
insert into user(user_id, name, surname) values
(1, 'a', 'aa'),
(2, 'b', 'bb'),
(3, 'c', 'cc');
create table books(
user_id int,
book_name varchar(10)
);
insert into books(user_id, book_name) values
(1, 'book1'),
(1, 'book2'),
(1, 'book3'),
(2, 'book1');
create table expanses(
id int,
user_id int,
amount_spent int,
date timestamp
);
insert into expanses(id, user_id, amount_spent, date)
values
(1,1,10, '2020-02-03'),
(2,1,10, '2020-02-03'),
(3,1,30, '2020-02-02'),
(4,1,12, '2020-02-01'),
(5,1,15, '2020-01-31'),
(6,1,13, '2020-01-15'),
(7,2,15, '2020-02-01'),
(8,3,20, '2020-02-01');
2)The result which I want:
| CountUsers | amount_spent |
|---------|--------------|
| 2 | 77 |
Explanation: I want to count
a) how many users have book1 or book2 and
b) how much total they spend on a date between 2020-02-01 - 2020-02-03.
Now how the query should look like?
I am using MySQL version 8.
I have tried:
SELECT count(*)
, sum(amount_spend) as total_amount_spend
FROM
( select sum(amount_spend) as amount_spend
FROM expanses e
LEFT
JOIN books b
ON b.user_id = e.user_id
WHERE (b.book_name ='book1' or b.book_name ='book2')
and e.date between '2020-02-01' and '2020-02-03'
GROUP
BY e.user_id) src'
And the result is wrong because the select clause from the inside(a little bit modified to show you more clearly):
select amount_spend as amount_spend
FROM expanses
LEFT JOIN books ON books.user_id = expanses.user_id WHERE (books.book_name ='book1' or books.book_name ='book2') and expanses.date between '2020-02-01' and '2020-02-03'
3)Will return something like this:
| user_id | amount_spent | book_name |
|---------|--------------|-----------|
| 1 | 10 | book1 |
| 1 | 30 | book1 |
| 1 | 30 | book1 |
| 1 | 12 | book1 |
| 1 | 10 | book2 |
| 1 | 10 | book2 |
| 1 | 30 | book2 |
| 1 | 12 | book2 |
| 2 | 15 | book1 |
4)So if sum this up, we will get
| CountUsers | amount_spent |
|---------|--------------|
| 2 | 139 |
5)Which is wrong, because there are duplicates.
If we add DISTINCT to sum(DISTINCT amount_spend)
it will be also wrong because it will give the following result
| CountUsers | amount_spent |
|---------|--------------|
| 2 | 67 |
To summarize, you can see in table 3) there are some duplicates of amount_spent cause the book_name.(one to many relationships)
How to avoid duplicating amount_spent but stay with book_name?
Fiddle
select count(distinct user_id)
, sum(amount_spent)
from expanses
where expanses.date between '2020-02-01' and '2020-02-03'
and user_id in (select user_id from books where book_name in('book1','book2'))
https://www.db-fiddle.com/f/26ifPWyRRKGp9YVQXg1qje/0
Here's an idea for a)
SELECT COUNT(DISTINCT user_id) total FROM books WHERE book_name IN ('book1','book2');
Here's an idea for b)
SELECT SUM(amount_spent) total_spent
FROM expanses e
WHERE e.date BETWEEN '2020-02-01' AND '2020-02-03'
AND EXISTS
( SELECT *
FROM books b
WHERE b.user_id = e.user_id
AND b.book_name IN ('book1','book2')
);
Here's and idea for combining a) and b)
SELECT SUM(amount_spent) total_spent
, (SELECT COUNT(DISTINCT user_id) total FROM books WHERE book_name IN ('book1','book2')) total_customers
FROM expanses e
WHERE e.date BETWEEN '2020-02-01' AND '2020-02-03'
AND EXISTS
( SELECT *
FROM books b
WHERE b.user_id = e.user_id
AND b.book_name IN ('book1','book2')
);
Table name is: result
ID Name score position
1 John 40 0
2. Ali 79 0
3 Ben 50 0
4 Joe 79 0
How can I update table result to give me the table below without using rank() as it does not support by server. Pls someone should help me with the MySQL code That breaks ties just as in table below.
ID Name score position
1 John 40 4
2. Ali 79 1
3 Ben 50 3
4 Joe 79 1
In MySQL prior to version 8 try using the multiple table update syntax:
UPDATE scores t
LEFT JOIN (
SELECT t1.id, COUNT(*) + 1 AS new_position
FROM scores t1
JOIN scores t2 ON t1.score < t2.score
GROUP BY t1.id
) agg ON t.id = agg.id
SET t.position = COALESCE(agg.new_position, 1)
fiddle
Lots of ways to skin this particular animal. How about...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(ID SERIAL PRIMARY KEY
,Name VARCHAR(12) NOT NULL
,score INT NOT NULL
);
INSERT INTO my_table VALUES
(1,'John',40),
(2,'Ali',79),
(3,'Ben',50),
(4,'Joe',79);
SELECT id
, name
, score
, FIND_IN_SET(score, scores) rank
FROM my_table
CROSS
JOIN
( SELECT GROUP_CONCAT(score ORDER BY score DESC) scores
FROM my_table
) scores
+----+------+-------+------+
| id | name | score | rank |
+----+------+-------+------+
| 1 | John | 40 | 4 |
| 2 | Ali | 79 | 1 |
| 3 | Ben | 50 | 3 |
| 4 | Joe | 79 | 1 |
+----+------+-------+------+
I've not provided an UPDATE, because you wouldn't normally store derived data.
You can use correlated sub-query as follows:
update your_table t
set t.position = (select count(*) + 1 from your_table tt
where tt.score > t.score)
I want to select a list of non-duplicate records, that invlove a certain user (either in user_to or user_from). I want to retrieve the other user and also the latest content in that record. The list must not have duplications in the other user selected.
For example, I have the following set of records
id user_to user_from content time
1 1 2 ABC 2013-11-05
2 4 2 BBC 2013-11-06
3 3 1 CBC 2013-11-07
4 5 1 ABC 2013-11-08
5 1 2 AAC 2013-11-09
6 5 1 ABB 2013-11-10
7 3 4 CBC 2013-11-11
8 1 2 ACC 2013-11-12
In this case, If the parameter to provide is 1, I want to select record 3,6,8 , the others are not selected because either they are duplicated and older or they do not involve 1.
I have looked into this post and tried something like this:
SELECT u, content, date FROM(
(SELECT
user_from AS u,
MAX(time) AS date,
content
FROM t1
WHERE user_to = :user
)
UNION
(SELECT
user_to AS u,
MAX(time) AS date,
content
FROM t1
WHERE user_from = :user
)
) t2
WHERE date IN (SELECT MAX(date) FROM t2 GROUP BY u)
But no, can't get it done.
Any idea how to write the query? Thanks!
Your query should be this:
select m.* from
message m,
( select user_to,
user_from,
max(dtime) mxdate
from message
where user_from = 1 or user_to = 1
group by user_to, user_from) m2
where m.dtime = m2.mxdate
and (m.user_from = 1 or m.user_to = 1)
See it here at fiddle: http://sqlfiddle.com/#!2/13d4e/4
As you ask in comments: ok. but as I only want the user_id of the other user, is there a way to select only user_to when user_from=1 and user_from when user_to=1 ?
select if(m.user_to=1,m.user_from,m.user_to) as user,
m.content,
m.dtime
from
message m,
( select user_to,
user_from,
max(dtime) mxdate
from message
where user_from = 1 or user_to = 1
group by user_to, user_from) m2
where m.dtime = m2.mxdate
and (m.user_from = 1 or m.user_to = 1)
see it here: http://sqlfiddle.com/#!2/13d4e/5
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,user_to INT NOT NULL
,user_from INT NOT NULL
,content CHAR(3) NOT NULL
,dt DATE NOT NULL
);
INSERT INTO my_table VALUES
(1,1,2,'ABC','2013-11-05'),
(2,4,2,'BBC','2013-11-06'),
(3,3,1,'CBC','2013-11-07'),
(4,5,1,'ABC','2013-11-08'),
(5,1,2,'AAC','2013-11-09'),
(6,5,1,'ABB','2013-11-10'),
(7,3,4,'CBC','2013-11-11'),
(8,1,2,'ACC','2013-11-12');
SELECT x.*
FROM my_table x
JOIN
( SELECT LEAST(user_to,user_from) l
, GREATEST(user_to,user_from) g
, MAX(dt) max_dt FROM my_table
GROUP
BY LEAST(user_to,user_from)
, GREATEST(user_to,user_from)
) y
ON y.l = LEAST(x.user_to,x.user_from)
AND y.g = GREATEST(x.user_to,x.user_from)
AND y.max_dt = x.dt
WHERE 1 IN (x.user_to,x.user_from);
+----+---------+-----------+---------+------------+
| id | user_to | user_from | content | dt |
+----+---------+-----------+---------+------------+
| 3 | 3 | 1 | CBC | 2013-11-07 |
| 6 | 5 | 1 | ABB | 2013-11-10 |
| 8 | 1 | 2 | ACC | 2013-11-12 |
+----+---------+-----------+---------+------------+
if filtering is "1" add this to the query of #Jorge Campos
where user_from = 1 OR user_to=1
I have a sample data with table is test
name | catid | date
------------
abc | 1
def | 2
ghi | 1
jkl | 2
mno | 1
pqr | 3
And my query
SELECT * FROM test WHERE catid = 1 AND catid = 2 AND catid = 3 ORDER BY date DESC
How to get value with result is
name | catid
------------
abc | 1
def | 2
pqr | 3
SELECT a.*
FROM TableName a
INNER JOIN
(
SELECT catid, MAX(DATE) max_date
FROM tableName
GROUP BY catID
) b ON a.catID = b.catID AND
a.date = b.max_date
SELECT name, catid FROM test WHERE catid IN (1, 2, 3) GROUP BY catid
I think you need the IN operator which is simplier than catid = X OR catid... (and you need OR, not AND)
Based on your desired output, this might be the query:
select catid, min(name)
from yourtable
where catid between 1 and 3
group by catid
But it's hard to know what you want based on the info provided in your question.