specific mysql select query - mysql

today i need your help to get an specific sql select query.
i have following table:
and after a specific query regarding a specific id (in this case id 1) i wanna have a result like this:
user_id (an alias for the id_sender/id_recipient), date (maybe a max function, cause i wanna have the latest date to group), messages (a count function to the messages):
10 | 2012-01-14 09:10:05 | 4
11 | 2012-01-13 13:52:49 | 1
13 | 2012-01-13 20:01:17 | 1
14 | 2012-01-14 09:20:17 | 1
i tryed a lot but dont get the exact results - so my approach was something like this:
SELECT `id_recipient`, `id_sender`, MAX(`date`) AS `date`, COUNT(*) AS `messages` FROM `table` WHERE `id_recipient` = 1 OR `id_sender` = 1 GROUP BY `id_recipient`, `id_sender`
but then i get this result:
its not so bad but as u can see the 4th line should be included in the results of the first one.
i hope u got me. feel free to ask if smth is not clear.
thanks in advance,
greetings

Ok, so since we know the value for id_recipient, we can use some math to trick SQL into getting this nasty query done.
Let n be the id value of the person of interest.
We know that the pairing of id_recipient and id_sender will ALWAYS include the user with id value n. Based on the where clause.
Therefore, id_recipient + id_sender == n + id_otherPerson is true.
The resulting query will be very similar to this.
(It's been a while, but I don't think I have any syntax problems)
SELECT (`id_recipient` + `id_sender` - n) AS `id_otherPerson`,
MAX(`date`) AS `date`, COUNT(*) AS `messages`
FROM `table`
WHERE `id_recipient` = n XOR `id_sender` = n
GROUP BY `id_otherPerson`;
Edit: I've changed it to an XOR, so if person n messages person n, it won't cause all values to be incremented by the number of times n has messaged themself.

What about this?
SELECT user_id, MAX(date), COUNT(*)
FROM (
SELECT id_recipient AS 'user_id', date
FROM table
WHERE id_recipient <> 1 AND id_sender = 1
UNION
SELECT id_sender AS 'user_id', date
FROM table
WHERE id_recipient = 1 AND id_sender <> 1
) AS tbl
GROUP BY user_id
It assumes you want to use id_recipient if the id_sender is 1 and id_sender if id_recipient is 1.

I believe the output you want should be as below
10 | 2012-01-13 20:01:17 | 3
11 | 2012-01-13 13:52:49 | 1
13 | 2012-01-13 20:01:17 | 1
I'm saying as you are mixing id_recipient and id_sender

Related

MySQL select - If a column value is redundant, only show the newest by timestamp

I have a table like this:
timesent |nr | value
2018-10-31 05:23:06 | 4 | Value 3
2018-10-31 05:20:19 | 4 | Value 2
2018-10-31 05:19:35 | 4 | Value 1
2018-10-31 04:55:56 | 3 | Value 2
2018-10-31 03:05:15 | 3 | Value 1
2018-10-31 01:31:49 | 2 | Value 1
2018-10-30 04:11:16 | 1 | Value 1
At the moment, my select looks like this:
SELECT * FROM values WHERE ORDER BY timesent DESC
I want to do an sql-select statement which gives me back only the most recent value of each "nr".
My skills are not good enough to translate that into a sql-statement. I donĀ“t even know what I should google for.
Values is a Reserved Keyword in MySQL. Consider changing your table name to something else; otherwise you will have to use backticks around it
There are various ways to achieve the result for your problem. One way is to do a "Self-Left-Join" on nr (field on which you want to get the maximum timesent value row only).
SELECT v1.*
FROM `values` AS v1
LEFT JOIN `values` AS v2
ON v1.nr = v2.nr AND
v1.timesent < v2.timesent
WHERE v2.nr IS NULL
For MySQL version >= 8.0.2, you can use Window Functions. We will determine Row_Number() for each row over a partition of nr, with timesent in Descending order (Highest timesent value will have row number = 1). Then, use this result-set in a Derived Table and consider only those rows, where row number is equal to 1.
SELECT dt.timesent,
dt.nr,
dt.value
FROM
(
SELECT v.timesent, v.nr, v.value,
ROW_NUMBER() OVER (PARTITION BY v.nr
ORDER BY v.timesent DESC) AS row_num
FROM `values` AS v
) AS dt
WHERE dt.row_num = 1
Yet, another approach is to get the maximum value of timesent for a nr group in a Derived Table. Now join this result-set to the main table, so that only the rows corresponding to max value appear:
SELECT v.timesent,
v.nr,
v.value
FROM
`values` AS v
JOIN
(
SELECT nr, MAX(timesent) AS max_timesent
FROM `values`
GROUP BY nr
) AS dt ON dt.nr = v.nr AND
dt.max_timesent = v.timesent

Selecting unique row from MySQL

Hope you guys can help as this has been bugging me a couple of days now. I'm trying to get the total number of unique rows from a table. For instance, the data in the table looks like this;
user_1 | user_2 | date_added | date_removed
--------|--------|---------------------|---------------------
1 | 2 | 2016-09-20 15:51:45 | 2016-09-24 09:15:32
1 | 3 | 2016-09-21 10:16:03 | 2016-09-29 00:46:44
6 | 1 | 2016-09-23 05:48:59 | 0000-00-00 00:00:00
1 | 3 | 2016-09-30 09:57:16 | 0000-00-00 00:00:00
What I want to find is the total number of rows that a user_id appears in (either column user_1 or column user_2), where there is also only a single entry for that pairing of users (user pairings will always be in the same columns), and date_removed = 0000-00-00 00:00:00.
So if I search the table above for user_id '1', the total would be '1'. (Only 3rd line matches search critera);
where a search for user_id '2' would equal '0';
user_id of '3' would equal '0';
user_id of '6' would equal '1';
Hope that makes sense. Any help or pointers will be much appreciated.
---- EDIT ----
This is the query i have so far, i've tried several ways inc joins etc, but this has got me closest so far, and its not the cleanest way im sure!
SELECT COUNT(*) AS `count`
FROM `table`
WHERE (`user_1` = '1' OR `user_2` = '1')
GROUP BY `user_1`, `user_2`
HAVING `count` < '2' AND MAX(`date_removed`) < '0000-00-00 00:00:01'
However, when as more data appears in the table, the result of the query looks like this:
count
-----
1
1
1
Where I want it to show:
count
-----
3
There's more than one way to achieve this.
I'm sending an option, creating a view to make it easier, but if you don't want to create a view, you can use its code in a subquery.
Create a view to union all possible combinations of user1, user2
create view result as
select user1, user2, date_removed from test
union all
select user2, user1, date_removed from test
Create a query
select r.user1, r.user2
from result r
where
r.date_removed = '0000-00-00 00:00:00'
and r.user2 not in (select r2.user2
from result r2
where r2.date_removed <> '0000-00-00 00:00:00')
Hope it helps you to solve it.

mysql select all rows meeting the first and second lowest values?

I wonder how I could select every user who met the first and second lowest values of a result table?
Table Test
NAME VALUE
John 8
Marie 8
Luis 10
Carlos 10
Leo 13
Max 14
So the result in this case would be
NAME VALUE
John 8
Marie 8
Luis 10
Carlos 10
Thanks a lot!
BTW, I did my home work searching on google and everything, didn't come up with anything but querying the table and then using PHP to filter that for me, not good for performance.
#Aziz I get the error : #1235 - This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
Thanks
Thank you all for the load of useful answers!
Just in case falls into funny results like I did, I needed more filters and had to add to the query, here follows:
SELECT * FROM results_temp WHERE
semana='semana6' AND
total_pontos IN (
SELECT * FROM (
SELECT DISTINCT total_pontos
FROM results_temp
WHERE semana='semana6'
ORDER BY `total_pontos`
LIMIT 0,2
) AS t
)
Regards
Try this:
SELECT * FROM Test WHERE `value` IN (
SELECT * FROM (
SELECT DISTINCT `value`
FROM Test
ORDER BY `value`
LIMIT 0,2
) AS t
)
Try this:
SELECT t.*
FROM Test t
INNER JOIN (SELECT DISTINCT t.value FROM Test t ORDER BY t.value LIMIT 2
) A ON t.value = A.value;
Check this SQL FIDDLE DEMO
OUTPUT
| NAME | VALUE |
|--------|-------|
| John | 8 |
| Marie | 8 |
| Luis | 10 |
| Carlos | 10 |
SELECT *
FROM tablename
WHERE
value <= (SELECT MIN(Value)
FROM tablename
WHERE value>(SELECT MIN(VALUE)
FROM tablename))
Please see fiddle here.
The uncorrelated version of a given query is nearly always faster...
SELECT x.*
FROM tablename x
JOIN (SELECT DISTINCT value FROM tablename ORDER BY value LIMIT 2) y
ON y.value = x.value;

how to find duplicate count without counting original

I need to count the number of duplicate emails in a mysql database, but without counting the first one (considered the original). In this table, the query result should be the single value "3" (2 duplicate x#q.com plus 1 duplicate f#q.com).
TABLE
ID | Name | Email
1 | Mike | x#q.com
2 | Peter | p#q.com
3 | Mike | x#q.com
4 | Mike | x#q.com
5 | Frank | f#q.com
6 | Jim | f#q.com
My current query produces not one number, but multiple rows, one per email address regardless of how many duplicates of this email are in the table:
SELECT value, count(lds1.leadid) FROM leads_form_element lds1 LEFT JOIN leads lds2 ON lds1.leadID = lds2.leadID
WHERE lds2.typesID = "31" AND lds1.formElementID = '97'
GROUP BY lds1.value HAVING ( COUNT(lds1.value) > 1 )
It's not one query so I'm not sure if it would work in your case, but you could do one query to select the total number of rows, a second query to select distinct email addresses, and subtract the two. This would give you the total number of duplicates...
select count(*) from someTable;
select count(distinct Email) from someTable;
In fact, I don't know if this will work, but you could try doing it all in one query:
select (count(*)-(count(distinct Email))) from someTable
Like I said, untested, but let me know if it works for you.
Try doing a group by in a sub query and then summing up. Something like:
select sum(tot)
from
(
select email, count(1)-1 as tot
from table
group by email
having count(1) > 1
)

Using ORDER BY and GROUP BY together

My table looks like this (and I'm using MySQL):
m_id | v_id | timestamp
------------------------
6 | 1 | 1333635317
34 | 1 | 1333635323
34 | 1 | 1333635336
6 | 1 | 1333635343
6 | 1 | 1333635349
My target is to take each m_id one time, and order by the highest timestamp.
The result should be:
m_id | v_id | timestamp
------------------------
6 | 1 | 1333635349
34 | 1 | 1333635336
And i wrote this query:
SELECT * FROM table GROUP BY m_id ORDER BY timestamp DESC
But, the results are:
m_id | v_id | timestamp
------------------------
34 | 1 | 1333635323
6 | 1 | 1333635317
I think it causes because it first does GROUP_BY and then ORDER the results.
Any ideas? Thank you.
One way to do this that correctly uses group by:
select l.*
from table l
inner join (
select
m_id, max(timestamp) as latest
from table
group by m_id
) r
on l.timestamp = r.latest and l.m_id = r.m_id
order by timestamp desc
How this works:
selects the latest timestamp for each distinct m_id in the subquery
only selects rows from table that match a row from the subquery (this operation -- where a join is performed, but no columns are selected from the second table, it's just used as a filter -- is known as a "semijoin" in case you were curious)
orders the rows
If you really don't care about which timestamp you'll get and your v_id is always the same for a given m_i you can do the following:
select m_id, v_id, max(timestamp) from table
group by m_id, v_id
order by max(timestamp) desc
Now, if the v_id changes for a given m_id then you should do the following
select t1.* from table t1
left join table t2 on t1.m_id = t2.m_id and t1.timestamp < t2.timestamp
where t2.timestamp is null
order by t1.timestamp desc
Here is the simplest solution
select m_id,v_id,max(timestamp) from table group by m_id;
Group by m_id but get max of timestamp for each m_id.
You can try this
SELECT tbl.* FROM (SELECT * FROM table ORDER BY timestamp DESC) as tbl
GROUP BY tbl.m_id
SQL>
SELECT interview.qtrcode QTR, interview.companyname "Company Name", interview.division Division
FROM interview
JOIN jobsdev.employer
ON (interview.companyname = employer.companyname AND employer.zipcode like '100%')
GROUP BY interview.qtrcode, interview.companyname, interview.division
ORDER BY interview.qtrcode;
I felt confused when I tried to understand the question and answers at first. I spent some time reading and I would like to make a summary.
The OP's example is a little bit misleading.
At first I didn't understand why the accepted answer is the accepted answer.. I thought that the OP's request could be simply fulfilled with
select m_id, v_id, max(timestamp) as max_time from table
group by m_id, v_id
order by max_time desc
Then I took a second look at the accepted answer. And I found that actually the OP wants to express that, for a sample table like:
m_id | v_id | timestamp
------------------------
6 | 1 | 11
34 | 2 | 12
34 | 3 | 13
6 | 4 | 14
6 | 5 | 15
he wants to select all columns based only on (group by)m_id and (order by)timestamp.
Then the above sql won't work. If you still don't get it, imagine you have more columns than m_id | v_id | timestamp, e.g m_id | v_id | timestamp| columnA | columnB |column C| .... With group by, you can only select those "group by" columns and aggreate functions in the result.
By far, you should have understood the accepted answer.
What's more, check row_number function introduced in MySQL 8.0:
https://www.mysqltutorial.org/mysql-window-functions/mysql-row_number-function/
Finding top N rows of every group
It does the simlar thing as the accepted answer.
Some answers are wrong. My MySQL gives me error.
select m_id,v_id,max(timestamp) from table group by m_id;
#abinash sahoo
SELECT m_id,v_id,MAX(TIMESTAMP) AS TIME
FROM table_name
GROUP BY m_id
#Vikas Garhwal
Error message:
[42000][1055] Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'testdb.test_table.v_id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
Why make it so complicated? This worked.
SELECT m_id,v_id,MAX(TIMESTAMP) AS TIME
FROM table_name
GROUP BY m_id
Just you need to desc with asc. Write the query like below. It will return the values in ascending order.
SELECT * FROM table GROUP BY m_id ORDER BY m_id asc;