I have to get unique combinations of two columns.
Eg if the values are :
sender_id recipient_id created_at
1 2 10/11/2014
2 1 10/12/2014
1 2 10/13/2014
1 3 10/14/2014
I want the output to be :
sender_id recipient_id created_at
1 3 10/14/2014
1 2 10/13/2014
I wrote this query :
SELECT DISTINCT ON (sender_id, recipient_id) *
FROM "messages"
WHERE ((recipient_id = 1 and recipient_delete = false)
or (sender_id = 1 and sender_delete = false))
ORDER BY sender_id, recipient_id, created_at DESC
But it outputs this:
sender_id recipient_id created_at
1 3 10/14/2014
2 1 10/12/2014
1 2 10/13/2014
One option to get all pairs, regardless of whether they are forward or backward (for example (1, 2) == (2, 1)) is to select the LEAST() and GREATEST() from each row, and then select distinct values. Using this query:
SELECT DISTINCT LEAST(sender_id, recipient_id), GREATEST(sender_id, recipient_id)
FROM myTable;
You will get the following output:
| 1 | 2 |
| 1 | 3 |
Once you have that, you can GROUP by these to get the maximum date for each pair:
SELECT LEAST(sender_id, recipient_id), GREATEST(sender_id, recipient_id), MAX(created_at)
FROM myTable
GROUP BY LEAST(sender_id, recipient_id), GREATEST(sender_id, recipient_id);
This query will give you the data you need for each pair, but it won't return the actual row from your original table. If there is a row of format | 2 | 1 | 2014-10-15 | this query will return | 1 | 2 | 2014-10-15.
To get the original row from your table, you need to JOIN on the condition that all of the necessary columns match:
SELECT m.*
FROM myTable m
JOIN(
SELECT LEAST(sender_id, recipient_id) AS least,
GREATEST(sender_id, recipient_id) AS greatest,
MAX(created_at) AS maxDate
FROM myTable
GROUP BY LEAST(sender_id, recipient_id), GREATEST(sender_id, recipient_id)) tmp
ON tmp.least = LEAST(m.sender_id, m.recipient_id) AND tmp.greatest = GREATEST(m.sender_id, m.recipient_id) AND tmp.maxDate = m.created_at;
Here is an SQL Fiddle example that matches your expected results.
The initial idea with DISTINCT ON is good, but:
it works with postgres but not with mysql, DISTINCT ON() being a PostgreSQL non-standard extension.
the ON() has to be applied to an expression where (1,2) and (2,1) are equivalent.
So a close query that should work and be efficient for postgres is:
SELECT DISTINCT ON (pair) *,
CASE WHEN sender_id<recipient_id
THEN (sender_id,recipient_id)
ELSE (recipient_id,sender_id)
END AS pair
FROM messages
ORDER BY pair, created_at DESC ;
Related
Hello I had this table:
id | user_id | status
1 | 34 | x
2 | 35 | x
3 | 42 | x
4 | 42 | y
My goal is to count the data with X status except if the user has a another data with Y status, it will exclude in the count. So instead of 3, it will only count 2 since the 3rd row has another data which is the 4th row with y status.
SELECT * FROM logs
AND user_id NOT IN (SELECT user_id FROM logs WHERE status = 'y')
GROUP BY user_id;
We can try the following aggregation approach:
SELECT COUNT(*) AS cnt
FROM
(
SELECT user_id
FROM logs
GROUP BY user_id
HAVING MIN(status) = MAX(status) AND
MIN(status) = 'x'
) t;
The above logic only counts a user having one or more records only having x status.
You can do it this way, I only modify a bit on your sql
SELECT COUNT(*) FROM (
SELECT u_id FROM tbl WHERE u_id NOT IN
(SELECT u_id FROM tbl WHERE status = 'y')
GROUP BY u_id
) as t
You can use inner join:
SELECT
count(t1.id) AS `cnt`
FROM
`test` AS t1,
`test` AS t2
WHERE
t2.`status`='y'
&& t1.`user_id` != t2.`user_id`;
Is it possible to select the next lower number from a table without using limit.
Eg: If my table had 10, 3, 2 , 1 I'm trying to select * from table where col > 10.
The result I'm expecting is 3. I know I can use limit 1, but can it be done without that?
Try
SELECT MAX(no) no
FROM table1
WHERE no < 10
Output:
| NO |
------
| 3 |
SQLFiddle
Try this query
SELECT
*
FROM
(SELECT
#rid:=#rid+1 as rId,
a.*
FROM
tbl a
JOIN
(SELECT #rid:=0) b
ORDER BY
id DESC)tmp
WHERE rId=2;
SQL FIDDLE:
| RID | ID | TYPE | DETAILS |
------------------------------------
| 2 | 28 | Twitter | #sqlfiddle5 |
Another approach
select a.* from supportContacts a inner join
(select max(id) as id
from supportContacts
where
id in (select id from supportContacts where id not in
(select max(id) from supportContacts)))b
on a.id=b.id
SQL FIDDLE:
| ID | TYPE | DETAILS |
------------------------------
| 28 | Twitter | #sqlfiddle5 |
Alternatively, this query will always get the second highest number based on the inner where clause.
SELECT *
FROM
(
SELECT t.col,
(
SELECT COUNT(distinct t2.col)
FROM tableName t2
WHERE t2.col >= t.col
) as rank
FROM tablename t
WHERE col <= 10
) xx
WHERE rank = 2 -- <<== means second highest
SQLFiddle Demo
SQLFiddle Demo (supports duplicate values)
If you want to get next lower number from table
you can get it with this query:
SELECT distinct col FROM table1 a
WHERE 2 = (SELECT count(DISTINCT(b.col)) FROM table1 b WHERE a.col >= b.col);
later again if you want to get third lower number you can just pass 3 in place of 2 in where clause
again if you want to get second higher number, just change the condition of where clause in inner query with
a.col <= b.col
Hi there m trying to calculate the row count for same value,
id,value
1 | a
2 | b
3 | c
4 | d
5 | e
and my query is
select value, count(*) as Count from mytable where id in('4','2','4','1','4') group by value having count(*) > 1
for which my expected output will be,
value,Count
d | 3
b | 1
a | 1
Thanks, any help will be appreciated
Try that:
SELECT value, count(value) AS Count
FROM mytable m
WHERE value = m.value
GROUP BY value
SELECT t.id, t.value, COUNT(t.id)
FROM
test t
JOIN
( SELECT 1 AS id
UNION ALL SELECT 3
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 1
UNION ALL SELECT 1 ) AS tmp
ON t.id = tmp.id
GROUP BY t.id
Sample on sqlfiddle.com
See also: Force MySQL to return duplicates from WHERE IN clause without using JOIN/UNION?
Of course, your IN parameter will be dynamic, and thus you will have to generate the corresponding SQL statement for the tmp table.
That's the SQL-only way to do it. Another possibility is to have the query like you have it in your question and afterwards programmatically associate the rows to the count passed to the IN parameter.
I have 2 tables. One of tables has all mails from users and other table has all calls from users.
Table 1
call_id, | call_date | user_id
1 | 10/01/12| 3
2 | 9/01/12 | 3
Table 2
mail_id, | mail_date | user_id
1 | 8/01/12 | 3
2 7/01/12 | 3
I need to get last last 3 calls and mails :
10/01/12 - call
9/01/12 - call
8/01/12 - mail
Assuming MySQL, and for just one User_ID...
SELECT
*
FROM
(
SELECT 'call' AS type, id, call_date AS event_date, user_id FROM table_1
UNION ALL
SELECT 'mail' AS type, id, mail_date AS event_date, user_id FROM table_2
)
data
WHERE
user_id = 3
ORDER BY
event_date DESC
LIMIT
3
EDIT: Ooops, forgot to specify DESC in the ORDER BY, sorry.
Declare #userID int;
SET #userID=3;
select call_id FROM table_1
where user_id=#userID
order by call_date desc limit 2
UNION ALL
select mail_id FROM table_2
where user_id=#userID
order by mail_date desc limit 1
I have a table that looks something like this:
________________________
|id|value|date|approved|
-----------------------
What I need to be able to do is get each row where approved = 1. That part is obvious. For each occurrence of value, I only want the most recent row (sorted by date).
Meaning that with a table like this:
________________________
|id|value|date|approved|
-----------------------
|1 |Foo | 5 | 1 |
|2 |Bar | 6 | 1 |
|3 |Foo | 8 | 1 |
-----------------------
I only want the rows with id 2 and 3.
I assume I need to use DISTINCT somehow, but I'm not sure how. Could anyone help me out here?
SELECT m.*
FROM (
SELECT DISTINCT value
FROM mytable
) md
JOIN mytable m
ON m.id =
(
SELECT id
FROM mytable mi
WHERE mi.value = md.value
AND mi.approved = 1
ORDER BY
mi.value DESC, mi.date DESC, mi.id DESC
LIMIT 1
)
Create an index on (value, date, id) for this to work fast.
You need:
select id, value, date, approved where (value, date) in (
select value, max(date)
from your_table
group by value
);
Actually using GROUP BY will yeld better results. try something like this:
SELECT id, value, date, approved FROM table WHERE approved = 1 GROUP BY value ORDER BY date;
select id, value, date, approved
from mytable a
where approved = 1
and date =
(select max(b.date)
from mytable b
where b.approved = 1
and b.value = a.value)
select
id,
value,
date
from
( select
value, max( date ) as LastInstance
from
YourTable
where
approved = 1
group by
value ) PreQuery
join YourTable
on PreQuery.value = YourTable.value
and PreQuery.LastInstance = YourTable.LastInstance
and YourTable.approved = 1
order by
date
Try with this:
SELECT * DISTINCT FROM TABLA WHERE APPROVED = 1 ORDER BY DATE DESC
Hope this helps you.