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.
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`;
I've got a query returning the following:
ID | Price
---------------
1 | 20
1 | 30
1 | 15
2 | 10
2 | 12
2 | 20
3 | 1
3 | 0
3 | 0
4 | 0
4 | 0
4 | 7
I'm wondering if there's a way I can get the sum of the lowest value for each ID. So in this case it would return 25.
15+10+0+0
You can use a subquery selecting the min price for each id, then sum those values:
select sum(minprice) as overallprice
from (
select min(price) minprice
from yourtable
group by id) t
You can create a sub-query that finds the lowest price per id and take the results from that and sum them together. In pseudo-code:
select
sum(lowest_price)
from (select id, min(price) as lowest_price from prices group by id) lowest_prices
You can do a query like below
Select sum (a) from
(
Select min (price) as a from yourtable
Group by id
) t
Another approach using partition without using group by statement
select sum(price.min_price) from
(select distinct id,min(price) over(partition by id) as min_price from prices) price
Some other approaches would be to use MySQL user variables or a self left join..
MySQL user variable solution
Query
SELECT
SUM(prices.Price)
FROM (
SELECT
prices.Price
, CASE
WHEN #id != prices.id
THEN 1
ELSE 0
END AS isMinGroupValue
, (#id := prices.id)
FROM
prices
CROSS JOIN (
SELECT
#id := 0
) AS init_user_params
ORDER BY
prices.ID ASC
, prices.price ASC
) AS prices
WHERE
prices.isMinGroupValue = 1
see demo https://www.db-fiddle.com/f/nzWqMQAxd7mvq589R7WuZ8/0
Self left join solution
Query
SELECT
SUM(prices1.Price)
FROM
prices prices1
LEFT JOIN
prices prices2
ON
prices1.ID = prices2.ID
AND
prices1.price > prices2.price
WHERE
prices2.ID IS NULL
see demo https://www.db-fiddle.com/f/nzWqMQAxd7mvq589R7WuZ8/1
I would use correlation subquery :
select sum(t.price) as overallprice
from table t
where price = (select min(price) from table t1 where t1.id = t.id);
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 ;
Imagine the following MySQL table of orders:
id | name
1 | Mike
2 | Steve
3 | Janet
4 | Juliet
5 | Mike
6 | Jane
This is my current query:
SELECT * FROM table ORDER BY id DESC
However, I'd like to "group" those by name, so that I have orders from the same person listed after one another, however, I cannot do ORDER BY name.
This is my desired output:
id | name
6 | Jane
5 | Mike
1 | Mike
4 | Juliet
3 | Janet
2 | Steve
What's the query for this output?
E.g.:
SELECT y.id
, y.name
FROM my_table x
JOIN my_table y
ON y.name = x.name
GROUP
BY name
, id
ORDER
BY MAX(x.id) DESC
, id DESC;
You need to have special calculation to get their row position.
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT Name,
#ord := #ord + 1 ord
FROM
(
SELECT MAX(ID) ID, NAME
FROM TableName
GROUP BY Name
) a, (SELECT #ord := 0) b
ORDER BY ID DESC
) b ON a.Name = b.Name
ORDER BY b.ord, a.ID DESC
SQLFiddle Demo
You can do it via double ORDER BY:
SELECT * FROM t ORDER BY name ASC, id DESC
SELECT * FROM table1
ORDER BY field(NAME,'Mike','Jane') desc,
`ID` desc;
exactly as you asked
You could also try this query if you want to have something which is more generic SQL.
SELECT id, name
FROM ( SELECT id, name, (SELECT MAX(id) from Table1 where name=t.name) AS max_id
FROM Table1 AS t
ORDER BY max_id DESC, id DESC) as x
What about to use group by?
You can group it by name and then order...
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