select unique data from a table with similar id data field - mysql

I am trying to retrieve unique values from the table above (order_status_data2). I would like to get the most recent order with the following fields: id,order_id and status_id. High id field value signifies the most recent item i.e.
4 - 56 - 4
8 - 52 - 6
7 - 6 - 2
9 - 8 - 2
etc.
I have tried the following query but not getting the desired result, esp the status_id field:
select max(id) as id, order_id, status_id from order_status_data2 group by order_id
This is the result am getting:
How would i formulate the query to get the desired results?

SELECT o.id, o.order_id, o.status_id
FROM order_status_data2 o
JOIN (SELECT order_id, MAX(id) maxid
FROM order_status_data2
GROUP BY order_id) m
ON o.order_id = m.order_id AND o.id = m.maxid
SQL Fiddle
In your query, you didn't put any constraints on status_id, so it picked it from an arbitrary row in the group. Selecting max(id) doesn't make it choose status_id from the row that happens to have that value, you need a join to select a specific row for all the non-aggregated columns.

Like so:
select d.*
from order_status_data2 d
join (select max(id) mxid from order_status_data2 group by order_id) s
on d.id = s.mxid

Try this Query.This will help you
SELECT id ,orderid,statusid
FROM table_name
WHERE id IN
(
SELECT max(id) FROM table_name GROUP BY orderid
)
ORDER BY statusid
You can refer this Sql_Fiddle_link which uses your example.

Related

How to get rows even if count is 0? Only 1 table

I want the count even if the count is 0. My current query is
SELECT `id`,count(0) as `fetchpc` FROM `user` WHERE pid in('4,6,7,8') GROUP BY `id`
But it returns only those id where count is greater than 0
Edit:
the values used for in('4,6,7,8') are first fetched from database in another query. And then using a script rows are converted to 4,6,7,8.
So all the values are present in the database.
Also it is possible that the values returned can go upto 100+ values.
You could left join this query on a "fictive" query that queries these IDs as literals:
SELECT ids.id, COALESCE(cnt, 0)
FROM (SELECT 4 AS id
UNION ALL
SELECT 6 AS id
UNION ALL
SELECT 7 AS id
UNION ALL
SELECT 8 AS id) ids
LEFT JOIN (SELECT id, COUNT(*) AS cnt
FROM fetchpc
GROUP BY id) t ON t.id = ids.id
You can use a derived table. I would recommend:
SELECT i.id, COUNT(u.id) as fetchpc
FROM (SELECT 4 as id UNION ALL
SELECT 6 as id UNION ALL
SELECT 7 as id UNION ALL
SELECT 8 as id
) i LEFT JOIN
`user` u
ON u.id = i.id
GROUP BY i.id;
From a performance perspective, this is much better than aggregating first (in a subquery) and then joining. Basically, the aggregation (in that case) has to aggregate all the data and afterwards filter out the unnecessary rows.
This formulation filters the rows first, which should speed the aggregation.

How to compare an having count with subrequest in MySQl

I'm trying to compare 2 values, the 1st one will be a count() in one request, and the 2nd is a field value from another request/table but they must be related. Here's what I'm trying:
SELECT count(id), lead_id
FROM calls_leads
group by lead_id
having count(id) = (
Select touches_phone_c, id_c
from leads_cstm
where lead_id = id_c)
Where the lead_id and id_c are the same IDs but from 2 different tables.
Thank you!
Try this:
SELECT t.*
FROM (SELECT COUNT(id) AS id_cnt, lead_id
FROM calls_leads
GROUP BY lead_id) t INNER JOIN leads_cstm l
ON l.id_c = t.id_cnt

MySQL - Group and total, but return all rows in each group

I'm trying to write a query that finds each time the same person occurs in my table between a specific date range. It then groups this person and totals their spending for a specific range. If their spending habits are greater than X amount, then return each and every row for this person between date range specified. Not just the grouped total amount. This is what I have so far:
SELECT member_id,
SUM(amount) AS total
FROM `sold_items`
GROUP BY member_id
HAVING total > 50
This is retrieving the correct total and returning members spending over $50, but not each and every row. Just the total for each member and their grand total. I'm currently querying the whole table, I didn't add in the date ranges yet.
JOIN this subquery with the original table:
SELECT si1.*
FROM sold_items AS si1
JOIN (SELECT member_id
FROM sold_items
GROUP BY member_id
HAVING SUM(amount) > 50) AS si2
ON si1.member_id = si2.member_id
The general rule is that the subquery groups by the same column(s) that it's selecting, and then you join that with the original query using the same columns.
SELECT member_id, amount
FROM sold_items si
INNER JOIN (SELECT member_id,
SUM(amount) AS total
FROM `sold_items`
GROUP BY member_id
HAVING total > 50) spenders USING (member_id)
The query you have already built can be used as a temporary table to join with. if member_id is not an index on the table, this will become slow with scale.
The word spenders is a table alias, you can use any valid alias in its stead.
There are a few syntaxes that will get the result you are looking, here is one using an inner join to ensure that all rows returned have a member_id in the list returned by the group by and that the total is repeated for each a certain member has:
SELECT si.*, gb.total from sold_items as si, (SELECT member_id as mid,
SUM(amount) AS total
FROM `sold_items`
GROUP BY member_id
HAVING total > 50) as gb where gb.mid=si.member_id;
I think that this might help:
SELECT
member_id,
SUM(amount) AS amount_value,
'TOTAL' as amount_type
FROM
`sold_items`
GROUP BY
member_id
HAVING
SUM(amount) > 50
UNION ALL
SELECT
member_id,
amount AS amount_value,
'DETAILED' as amount_type
FROM
`sold_items`
INNER JOIN
(
SELECT
A.member_id,
SUM(amount) AS total
FROM
`sold_items` A
GROUP BY
member_id
HAVING
total <= 50
) AS A
ON `sold_items`.member_id = A.member_id
Results of the above query should be like the following:
member_id amount_value amount_type
==========================================
1 55 TOTAL
2 10 DETAILED
2 15 DETAILED
2 10 DETAILED
so the column amount_type would distinguish the two specific member groups
You could do subquery with EXISTS as an alternative:
select *
from sold_items t1
where exists (
select * from sold_items t2
where t1.member_id=t2.member_id
group by member_id
having sum(amount)>50
)
ref: http://dev.mysql.com/doc/refman/5.7/en/exists-and-not-exists-subqueries.html
In case you need to group by multiple columns, you can use a composite identifier with concatenate in combination with a group by subquery
select id, key, language, group
from translation
--query all key-language entries by composite identifier...
where concat(key, '_', language) in (
--by lookup of all key-language combinations...
select concat(key, '_', language)
from translation
group by key, language
--that occur more than once
having count(*) > 1
)

Optimize Group by & Order by query

This is structure of product table.
Currently have more 1 million records.
I have performance issue when I use query group by & order by.
Query:
SELECT product_name FROM vs_product GROUP BY store_id ORDER BY id DESC LIMIT 2
How to improve this query to perform faster? I indexed the store_id, ID is primary key.
SELECT x.*
FROM my_table x
JOIN (SELECT store_id, MAX(id) max_id FROM my_table GROUP BY store_id) y
ON y.store_id = x.store_id
AND y.max_id = x.id
ORDER
BY store_id DESC LIMIT 2;
A hacky (but fast) solution:
SELECT product_name
FROM (
SELECT id
FROM vs_product
GROUP BY store_id DESC
LIMIT 2) as ids
JOIN vs_product USING (id);
How it works:
Your index on store_id stores (store_id, id) pairs in ascending order. GROUP BY DESC will make MySQL read the index in reverse order, that is the subquery will fetch the maximum ids for each store_id. Then you just join them back to the whole table to fetch product names.
Take notice, that the query will fetch two product names for the store ids with the maximum values.
You want a query like this:
select p.*
from product p join
(select store_id, max(id) as maxid
from product p
group by store_id
) psum
on psum.store_id = p.store_id and p.id = maxid
You don't have date in any of the tables, so I'm assuming the largest id is the most recent.

Selecting rows with unique field values in mysql

I have these columns for table comments:
id
content
add_date
uid
school_id
Rows can have the same school_id.
I want to select the latest data according to add_date, but only 1 row per school_id (no duplicate for school_id) with limit of 10.
I've tried many codes already and its not working for me.
Any help would be appreciated.
This is what we call Greatest N per Group. You can achieved this by putting into a subquery so it can be joined against the non-grouped table (comments).
Try this:
SELECT c.*
FROM
(
SELECT school_id, MAX(add_date) maxDate
FROM comments
GROUP BY school_id
) x INNER JOIN comments c
ON x.school_id = c.school_ID AND
x.maxDate = c.add_date
ORDER BY x.maxDate desc
LIMIT 10
select C.ID, C.Content, t1.MaxDate as [add_date], C.uid, t1.school_id
from (selet school_id, max(add_Date) as 'MaxDate'
from comments
group by school_id) T1
inner join comments C on T1.school_id = C.school_id and C.add_Date= T1.MaxDate
LIMIT 10
If you want to choose which 10 rows return, add an order by, or a Where clause
select c1.*
from comments c1
where add_date = (select max(add_date) from comments c2 where c2.school_id =c1.school_id)
order by add_date desc
limit 10
create indexes on comments(add_date) and comments(school_id, add_date)