I want to select the last two elements in ascending order followed by the first element. Here is my code
SELECT products.*, locations.logo FROM
(SELECT products.* FROM
(SELECT products.* FROM products AS products ORDER BY products.id DESC )
AS products LEFT JOIN users ON users.id=products.userid WHERE users.hide=0)
AS products LEFT JOIN locations ON products.location=locations.id LIMIT 2
UNION SELECT products.*, locations.logo FROM
(SELECT products.* FROM
(SELECT products.* FROM products AS products ORDER BY products.id ASC )
AS products LEFT JOIN users ON users.id=products.userid WHERE users.hide=0)
AS products LEFT JOIN locations ON products.location=locations.id LIMIT 3
E.g. for 20 products now I'm getting
20, 19, 1 (ordered by id).
I'm trying to get 19, 20, 1.
At this moment the above statement works according to the E.g. I know I have to put an ORDER BYclause but I don't know where cause in my trials I'm getting error
"Incorrect usage of UNION and ORDER BY"
Can anybody help me with that?
You can do something like this
SELECT id
FROM
(
(
SELECT id, 0 sort_order
FROM Table1
ORDER BY id DESC
LIMIT 2
)
UNION ALL
(
SELECT id, 1 sort_order
FROM Table1
ORDER BY id
LIMIT 1
)
) q
ORDER BY sort_order, id
Output:
| ID |
|----|
| 19 |
| 20 |
| 1 |
Here is SQLFiddle demo
Related
I have the following data inside a table:
id person_id item_id price
1 1 1 10
2 1 1 20
3 1 3 50
Now what I want to do is group by the item ID, select the id that has the highest value and take the price.
E.g. the sum would be: (20 + 50) and ignore the 10.
I am using the following:
SELECT SUM(`price`)
FROM
(SELECT id, person_id, item_id, price
FROM `table` tbl
INNER JOIN person p USING (person_id)
WHERE p.person_id = 1
ORDER BY id DESC) x
GROUP BY item_id
However, this query is still adding (10 + 20 + 50), which is obviously not what I need to have.
Any ideas to where I am going wrong?
Here is what you are trying to achieve. First you need grouping in a subquery and not in outer query. In outer query you need only sum:
SELECT SUM(`price`)
FROM
(SELECT MAX(price) as price
FROM `table` tbl
INNER JOIN person p USING (person_id)
WHERE p.person_id = 1
GROUP BY item_id) x
http://sqlfiddle.com/#!9/40803/5
SELECT SUM(t1.price)
FROM tbl t1
LEFT JOIN tbl t2
ON t1.person_id= t2.person_id
AND t1.item_id = t2.item_id
AND t1.id<t2.id
WHERE t1.person_id = 1
AND t2.id IS NULL;
I'm not sure if this is the only requirement you have. If so, try this.
SELECT SUM(price)
FROM
(SELECT MAX(price)
FROM table
WHERE person_id = 1
GROUP BY item_id)
First of all - you don't need the person table, because the other table already contains the person_id. So i removed it from the examples.
Your query returns a sum of prices for each item.
If you replace SELECT SUM(price) with SELECT item_id, SUM(price) you wil get
item_id SUM(`price`)
1 30
3 50
But that is not what you want. Neither is it what you wrote in the question " (10 + 20 + 50)".
Now replacing the first line with SELECT id, item_id, SUM(price) you will get one row for each item with the highest id.
id item_id price
2 1 20
3 3 50
This works because of the "undocumented feature" of MySQL, wich allows you to select columns that are not listed in the GROUP BY clause and get the first row from the subselect each group (each item in this case).
Now you only need to sum the price column in an additional outer select
SELECT SUM(price)
FROM (
SELECT id, item_id ,price
FROM (
SELECT id, person_id, item_id, price
FROM `table` tbl
WHERE tbl.person_id = 1
ORDER BY id DESC ) x
GROUP BY item_id
) y
However i do not recomend to use that "feature". While it still works on MySQL 5.6, you never know if that will work with newer versions. It already doesn't work on MariaDB.
Instead you can determite the MAX(id) for each item in an subselect, select only the rows with the determined ids and get the summed price of them.
SELECT SUM(`price`)
FROM `table` tbl
WHERE tbl.id IN (
SELECT MAX(tbl2.id)
FROM `table` tbl2
WHERE tbl2.person_id = 1
GROUP BY tbl2.item_id
)
Another solution (wich internaly does the same) is
SELECT SUM(`price`)
FROM `table` tbl
JOIN (
SELECT MAX(tbl2.id) as id
FROM `table` tbl2
WHERE tbl2.person_id = 1
GROUP BY tbl2.item_id
) x ON x.id = tbl.id
Alex's solution also works fine, if the groups (number of rows per person and item) are rather small.
You have used group by in main query, but it is on subquery like
SELECT id, person_id, item_id, SUM(`price`) FROM ( SELECT MAX(price) FROM `table` tbl WHERE p.person_id = 1 GROUP BY item_id ) AS x
I need 2 id for each group.
SELECT `id`, `category`.`cat_name`
FROM `info`
LEFT JOIN `category` ON `info`.`cat_id` = `category`.`cat_id`
WHERE `category`.`cat_name` IS NOT NULL
GROUP BY `category`.`cat_name`
ORDER BY `category`.`cat_name` ASC
How to do this?
Sample Data:
id cat_name
1 Cat-1
2 Cat-1
3 Cat-2
4 Cat-1
5 Cat-2
6 Cat-1
7 Cat-2
Output Will be:
id cat_name
6 Cat-1
4 Cat-1
7 Cat-2
5 Cat-2
If you need two arbitrary ids, then use min() and max():
SELECT c.`cat_name` , min(id), max(id)
FROM `info` i INNER JOIN
`category` c
ON i.`cat_id` = c.`cat_id`
WHERE c.`cat_name` IS NOT NULL
GROUP BY c`.`cat_name`
ORDER BY c.`cat_name` ASC ;
Note: You are using a LEFT JOIN and then aggregating by a column in the second table. This is usually not a good idea, because non-matches are all placed in a NULL group. Furthermore, your WHERE clause turns the LEFT JOIN to an INNER JOIN anyway, so I've fixed that. The WHERE clause may or may not be necessary, depending on whether or not cat_name is ever NULL.
If you want the two biggest or smallest -- and can bear to have them in the same column:
SELECT c.`cat_name`,
substring_index(group_concat id order by id), ',', 2) as ids_2
FROM `info` i INNER JOIN
`category` c
ON i.`cat_id` = c.`cat_id`
WHERE c.`cat_name` IS NOT NULL
GROUP BY c`.`cat_name`
ORDER BY c.`cat_name` ASC ;
SELECT id, cat_name
FROM
( SELECT #prev := '', #n := 0 ) init
JOIN
( SELECT #n := if(c.cat_name != #prev, 1, #n + 1) AS n,
#prev := c.cat_name,
c.cat_name,
i.id
FROM `info`
LEFT JOIN `category` ON i.`cat_id` = c.`cat_id`
ORDER BY c.cat_name ASC, i.id DESC
) x
WHERE n <= 2
ORDER BY cat_name ASC, id DESC;
More discussion in Group-wise-max blog.
In a database that supported window functions, you could enumerate the position of each record in each group (ROW_NUMBER() OVER (PARTITION BY cat_name ORDER BY id DESC)) and then select those records in relative position 1 or 2.
In MySQL, you can mimic this by a self-join which counts the number of records whose id is greater-than-or-equal-to a record of the same cat_name (PARTITION ... ORDER BY id DESC). Record #1 in a cat_name group has only one record of >= its id, and record #N has N such records.
This query
SELECT id, cat_name
FROM ( SELECT c.id, c.cat_name, COUNT(1) AS relative_position_in_group
FROM category c
LEFT JOIN category others
ON c.cat_name = others.cat_name
AND
c.id <= others.id
GROUP BY 1, 2) d
WHERE relative_position_in_group <= 2
ORDER BY cat_name, id DESC;
produces:
+----+----------+
| id | cat_name |
+----+----------+
| 6 | Cat-1 |
| 4 | Cat-1 |
| 7 | Cat-2 |
| 5 | Cat-2 |
+----+----------+
Your query is like Select id, cat_name from mytable group by cat_name then update it to Select SELECT SUBSTRING_INDEX(group_concat(id), ',', 2), cat_name from mytable group by cat_name and you will get output like as follows
id cat_name
1,2 Cat-1
3,5 Cat-2
Does it helps?
the only thing you need is adding limit option to the end of your query and ordering in descending order as shown below:
SELECT `id`, `category`.`cat_name`
FROM `info`
LEFT JOIN `category` ON `info`.`cat_id` = `category`.`cat_id`
WHERE `category`.`cat_name` IS NOT NULL
GROUP BY `category`.`cat_name`
ORDER BY `category`.`cat_name` DESC
LIMIT 2
Very simple Group By ID. it is group duplicate data
I have written query for you. I hope it will resolve your problem :
SELECT
id, cat_name
FROM
(SELECT
*,
#prevcat,
CASE
WHEN cat_name != #prevcat THEN #rownum:=0
END,
#rownum:=#rownum + 1 AS cnt,
#prevcat:=cat_name
FROM
category
CROSS JOIN (SELECT #rownum:=0, #prevcat:='') r
ORDER BY cat_name ASC , id DESC) AS t
WHERE
t.cnt <= 2;
Better to use rank function the below sample query for your ouput will be helpful check it
select a.* from
(
select a, b ,rank() over(partition by b order by a desc) as rank
from a
group by b,a) a
where rank<=2
please try this, it worked in the sample data given
SELECT `id`, `category`.`cat_name`
FROM `info`
LEFT JOIN `category` ON `info`.`cat_id` = `category`.`cat_id`
WHERE `category`.`cat_name` IS NOT NULL and (SELECT count(*)
FROM info t
WHERE t.id>=info.id and t.cat_id=category.cat_id )<3
GROUP BY `category`.`cat_name`,id
ORDER BY `category`.`cat_name` ASC
Well, it's pretty ugly, but it looks like it works.
select
cat_name,
max(id) as maxid
from
table1
group by cat_name
union all
select
cat_name,
max(id) as maxid
from
table1
where not exists
(select
cat_name,
maxid
from
(select cat_name,max(id) as maxid from table1 group by cat_name) t
where t.cat_name = table1.cat_name and t.maxid = table1.id)
group by cat_name
order by cat_name
SQLFiddle
Basically, it takes the max for each cat_name, and then unions that to a second query that excludes the actual max id for each cat_name, allowing you to get the second largest id for each. Hopefully all that made sense...
select id, cat_name from
(
select #rank:=if(#prev_cat=cat_name,#rank+1,1) as rank,
id,cat_name,#prev_cat:=cat_name
from Table1,(select #rank:=0, #prev_cat:="")t
order by cat_name, id desc
) temp
where temp.rank<=2
You may verify result at http://sqlfiddle.com/#!9/acd1b/7
Suppose,I have a table named items:
sender_id receiver_id goods_id price
2 1 a1 1000
3 1 b2 2000
2 1 c1 5000
4 1 d1 700
2 1 b1 500
Here I want to select the sender_id,goods_id in descending order of price from the items table such that no row appears more than once which contains the same sender_id value (here sender_id 2). I used the following query,but was in vain:
select distinct sender_id,goods_id from items where receiver_id=1 order by price desc
The result shows all the five tuples(records) with the tuples containing sender_id 2 thrice in descending order of time.But what I want is to display only three records one of them having sender_id of 2 with only the highest price of 5000. What should I do?
My expected output is:
sender_id goods_id
2 c1
3 b2
4 d1
Get the highest price of each group, you could do like below:
SELECT T1.*
FROM (
SELECT
MAX(price) AS max_price,
sender_id
FROM items
GROUP BY sender_id
) AS T2
INNER JOIN items T1 ON T1.sender_id = T2.sender_id AND T1.price = T2.max_price
WHERE T1.receiver_id=1
ORDER BY T1.price
Try this:
SELECT i.sender_id, i.goods_id
FROM items i
INNER JOIN (SELECT i.sender_id, MAX(i.price) AS maxPrice
FROM items i WHERE i.receiver_id=1
GROUP BY i.sender_id
) AS A ON i.sender_id = A.sender_id AND i.price = A.maxPrice
WHERE i.receiver_id=1
OR
SELECT i.sender_id, i.goods_id
FROM (SELECT i.sender_id, i.goods_id
FROM (SELECT i.sender_id, i.goods_id
FROM items i WHERE i.receiver_id=1
ORDER BY i.sender_id, i.price DESC
) AS i
GROUP BY i.sender_id
) AS i
please try this
select sender_id,goods_id from items t1
where not exists (select 1 from items t2
where t2.sender_id = t1.sender_id
and t2.receiver_id = t1.receiver_id
and t2.price > t1.price)
and receiver_id = 1
order by price desc
select distinct (sender_id,goods_id) from items where receiver_id=1 order by price desc;
you can use like this.
Getting the most popular items is relatively easy. But let us say I have a table with two columns: item_id and viewer_id.
Given a viewer_id, I want to fetch the top X item_id rows which have been viewed the MOST times AND have not been viewed by the given viewer_id. So for example:
item_id | viewer_id
A | 1
A | 3
C | 2
C | 3
C | 4
D | 5
Getting most popular items not seen by viewer 2 should give back A, D.
What is a good way to go about this?
As I understand it you don't just want them listed but ordered from most to least popular; this should work.
SELECT item_id
FROM table_name a
WHERE NOT EXISTS
(
SELECT viewer_id FROM table_name t
WHERE a.item_id=t.item_id AND t.viewer_id=2
)
GROUP BY item_id
ORDER BY COUNT(item_id) DESC;
Try this:
select item_id, count(*) as timesViewed from t2
where item_id not in (
select distinct t1.item_id from t1
where viewer_id = 2
)
group by item_id
order by timesViewed desc
Working example
Something like below should work:
SELECT t.item_id, COUNT(t.viewer_id) AS view_count FROM table t
WHERE t.item_id NOT IN (SELECT DISTINCT item_id FROM table t2 WHERE viewer_id = your_viewer_id)
GROUP BY item_id
ORDER BY view_count DESC
I googled a bit and looked on SO but I didn't find anything that helped me.
I have a working MySQL query that selects some columns (accross three tables, with two JOIN statements) and I am looking to do something extra on the result set.
I would like to SELECT all rows from the 3 most recent groups. (I can only assume I have to use a GROUP BY on that column) I'm having a hard time explaining this clearly so I'll use an example:
id | group
--------------
1 | 1
2 | 2
3 | 2
4 | 2
5 | 3
6 | 3
7 | 4
8 | 4
Of course, I dumbed it down a lot for the sake of simplicity (and my current query doesn't include an id column).
Right now my ideal query would return, in order (that's the id field):
8, 7, 6, 5, 4, 3, 2
If I were to add the following 9th element:
id | group
--------------
9 | 5
My ideal query would then return, in order:
9, 8, 7, 6, 5
Because these are all the rows from the most 3 recent groups. Also, when two rows have the same group (and are still in the results set), I would like to ORDER them BY another field (which I have not included in my dumbed down example).
In my search I only found how to do actions on elements of GROUPS (MAX of each, AVG of group elements, etc.) and not GROUPS themselves (first 3 groups ordered by a field).
Thank you in advance for your help!
Edit: Here is what my real query looks like.
SELECT t1.f1, t1.f2, t2.f1, t2.f2, t2.f3, t3.f1, t3.f2, t3.f3, t3.f4
FROM t1
LEFT JOIN t2 ON t2.f1=t1.f3
LEFT JOIN t3 ON t2.f1=t3.f5
WHERE t1.f4='some_constant' AND t2.f4='some_other_constant'
ORDER BY t1.f2 DESC
SELECT `table`.* FROM
(SELECT DISTINCT `group`
FROM `table`
ORDER BY `group` DESC LIMIT 3) t1
INNER JOIN `table` ON `table`.`group` = t1.`group`
the subquery should return the three groups with the largest value, the INNER JOIN will ensure no rows are included which do not have these group values.
assuming t1.f2 is your group column:
SELECT a,b,c,d,e,f,g,h,i
FROM
(
SELECT t1.f1 as a, t1.f2 as b, t2.f1 as c, t2.f2 as d, t2.f3 as e, t3.f1 as f, t3.f2 as g, t3.f3 as h, t3.f4 as i
FROM t1
LEFT JOIN t2 ON t2.f1=t1.f3
LEFT JOIN t3 ON t2.f1=t3.f5
WHERE t1.f4='some_constant' AND t2.f4='some_other_constant'
ORDER BY t1.f2 DESC
) first_table
INNER JOIN
(
SELECT DISTINCT `f2`
FROM `t1`
ORDER BY `f2` DESC LIMIT 3
) second_table
ON first_table.b = second_table.f2
Note that this may be very inefficient depending on your table structure, but is the best I can do without more information.
how about this way... (i use groupId instead of 'group'
[QUERY] => something like (SELECT id, groupId from tables.....) (your query with 2 joins).
-- with this query you have the last thre groups.
[QUERY2] => SELECT distinct(groupId) as groupId FROM ([QUERY]) ORDER BY groupId DESC LIMIT 0,3
and finally you will have:
SELECT id, groupId from tables----...... WHERE groupId in ([QUERY2]) order by groupId DESC, id DESC